-/* $Id: stencil.c,v 1.12 1999/12/10 16:15:04 brianp Exp $ */
+/* $Id: stencil.c,v 1.21 2000/10/30 13:32:01 keithw Exp $ */
/*
* Mesa 3-D graphics library
- * Version: 3.3
+ * Version: 3.5
*
- * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
#else
#include "glheader.h"
#include "context.h"
+#include "depth.h"
+#include "macros.h"
#include "mem.h"
#include "pb.h"
#include "stencil.h"
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
ctx->Stencil.Clear = (GLstencil) s;
+ ctx->NewState |= _NEW_STENCIL;
if (ctx->Driver.ClearStencil) {
(*ctx->Driver.ClearStencil)( ctx, s );
maxref = (1 << STENCIL_BITS) - 1;
ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref );
ctx->Stencil.ValueMask = (GLstencil) mask;
+ ctx->NewState |= _NEW_STENCIL;
if (ctx->Driver.StencilFunc) {
(*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
ctx->Stencil.WriteMask = (GLstencil) mask;
+ ctx->NewState |= _NEW_STENCIL;
if (ctx->Driver.StencilMask) {
(*ctx->Driver.StencilMask)( ctx, mask );
void
-_mesa_StencilOp( GLenum fail, GLenum zfail, GLenum zpass )
+_mesa_StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
{
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
case GL_INCR:
case GL_DECR:
case GL_INVERT:
- case GL_INCR_WRAP_EXT:
- case GL_DECR_WRAP_EXT:
ctx->Stencil.FailFunc = fail;
break;
+ case GL_INCR_WRAP_EXT:
+ case GL_DECR_WRAP_EXT:
+ if (ctx->Extensions.EXT_stencil_wrap) {
+ ctx->Stencil.FailFunc = fail;
+ break;
+ }
+ /* FALL-THROUGH */
default:
- gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+ gl_error(ctx, GL_INVALID_ENUM, "glStencilOp");
return;
}
switch (zfail) {
case GL_INCR:
case GL_DECR:
case GL_INVERT:
- case GL_INCR_WRAP_EXT:
- case GL_DECR_WRAP_EXT:
ctx->Stencil.ZFailFunc = zfail;
break;
+ case GL_INCR_WRAP_EXT:
+ case GL_DECR_WRAP_EXT:
+ if (ctx->Extensions.EXT_stencil_wrap) {
+ ctx->Stencil.ZFailFunc = zfail;
+ break;
+ }
+ /* FALL-THROUGH */
default:
- gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+ gl_error(ctx, GL_INVALID_ENUM, "glStencilOp");
return;
}
switch (zpass) {
case GL_INCR:
case GL_DECR:
case GL_INVERT:
- case GL_INCR_WRAP_EXT:
- case GL_DECR_WRAP_EXT:
ctx->Stencil.ZPassFunc = zpass;
break;
+ case GL_INCR_WRAP_EXT:
+ case GL_DECR_WRAP_EXT:
+ if (ctx->Extensions.EXT_stencil_wrap) {
+ ctx->Stencil.ZPassFunc = zpass;
+ break;
+ }
+ /* FALL-THROUGH */
default:
- gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
+ gl_error(ctx, GL_INVALID_ENUM, "glStencilOp");
return;
}
+ ctx->NewState |= _NEW_STENCIL;
+
if (ctx->Driver.StencilOp) {
- (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
+ (*ctx->Driver.StencilOp)(ctx, fail, zfail, zpass);
}
}
*
*/
static GLboolean
-stencil_and_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
- const GLdepth z[], GLstencil stencil[],
- GLubyte mask[] )
+stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLstencil stencil[],
+ GLubyte mask[] )
{
ASSERT(ctx->Stencil.Enabled);
ASSERT(n <= PB_SIZE);
MEMCPY(oldmask, mask, n * sizeof(GLubyte));
/* apply the depth test */
- if (ctx->Driver.DepthTestSpan)
- (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask );
+ _mesa_depth_test_span(ctx, n, x, y, z, mask);
/* Set the stencil pass/fail flags according to result of depth testing.
* if oldmask[i] == 0 then
*
*/
GLboolean
-gl_stencil_and_depth_test_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
- const GLdepth z[], GLubyte mask[] )
+_mesa_stencil_and_ztest_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
+ const GLdepth z[], GLubyte mask[] )
{
GLstencil stencilRow[MAX_WIDTH];
GLstencil *stencil;
}
/* do all the stencil/depth testing/updating */
- result = stencil_and_depth_test_span( ctx, n, x, y, z, stencil, mask );
+ result = stencil_and_ztest_span( ctx, n, x, y, z, stencil, mask );
if (ctx->Driver.WriteStencilSpan) {
/* Write updated stencil values into hardware stencil buffer */
* 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_depth_test_span(), which is well
+ * almost identical to stencil_and_ztest_span(), which is well
* commented.
*
* Input: n - number of pixels in the array
* GL_FALSE - one or more fragments passed the testing
*/
GLboolean
-gl_stencil_and_depth_test_pixels( GLcontext *ctx,
- GLuint n, const GLint x[], const GLint y[],
- const GLdepth z[], GLubyte mask[] )
+_mesa_stencil_and_ztest_pixels( GLcontext *ctx,
+ GLuint n, const GLint x[], const GLint y[],
+ const GLdepth z[], GLubyte mask[] )
{
ASSERT(ctx->Stencil.Enabled);
ASSERT(n <= PB_SIZE);
MEMCPY(oldmask, mask, n * sizeof(GLubyte));
- if (ctx->Driver.DepthTestPixels)
- (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
+ _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
for (i=0;i<n;i++) {
ASSERT(mask[i] == 0 || mask[i] == 1);
MEMCPY(oldmask, mask, n * sizeof(GLubyte));
- if (ctx->Driver.DepthTestPixels)
- (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
+ _mesa_depth_test_pixels(ctx, n, x, y, z, mask);
for (i=0;i<n;i++) {
ASSERT(mask[i] == 0 || mask[i] == 1);
* x,y - location of first pixel
* Output: stencil - the array of stencil values
*/
-void gl_read_stencil_span( GLcontext *ctx,
- GLint n, GLint x, GLint y, GLstencil stencil[] )
+void
+_mesa_read_stencil_span( GLcontext *ctx,
+ GLint n, GLint x, GLint y, GLstencil stencil[] )
{
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + n <= 0 || x >= ctx->DrawBuffer->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 > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
+
+
ASSERT(n >= 0);
- if (ctx->DrawBuffer->Stencil) {
- if (ctx->Driver.ReadStencilSpan) {
- (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
- }
- else {
- const GLstencil *s = STENCIL_ADDRESS( x, y );
+ if (ctx->Driver.ReadStencilSpan) {
+ (*ctx->Driver.ReadStencilSpan)( ctx, (GLuint) n, x, y, stencil );
+ }
+ else if (ctx->DrawBuffer->Stencil) {
+ const GLstencil *s = STENCIL_ADDRESS( x, y );
#if STENCIL_BITS == 8
- MEMCPY( stencil, s, n * sizeof(GLstencil) );
+ MEMCPY( stencil, s, n * sizeof(GLstencil) );
#else
- GLuint i;
- for (i=0;i<n;i++)
- stencil[i] = s[i];
+ GLuint i;
+ for (i=0;i<n;i++)
+ stencil[i] = s[i];
#endif
- }
}
}
* x, y - location of first pixel
* stencil - the array of stencil values
*/
-void gl_write_stencil_span( GLcontext *ctx,
- GLint n, GLint x, GLint y,
- const GLstencil stencil[] )
+void
+_mesa_write_stencil_span( GLcontext *ctx, GLint n, GLint x, GLint y,
+ const GLstencil stencil[] )
{
- ASSERT(n >= 0);
- if (ctx->DrawBuffer->Stencil) {
- /* do clipping */
- if (y < ctx->DrawBuffer->Ymin || y > ctx->DrawBuffer->Ymax)
- return;
- if (x < ctx->DrawBuffer->Xmin) {
- GLint diff = ctx->DrawBuffer->Xmin - x;
- n -= diff;
- stencil += diff;
- x = ctx->DrawBuffer->Xmin;
- }
- if (x + n > ctx->DrawBuffer->Xmax) {
- GLint diff = x + n - ctx->DrawBuffer->Xmax;
- n -= diff;
- }
+ if (y < 0 || y >= ctx->DrawBuffer->Height ||
+ x + n <= 0 || x >= ctx->DrawBuffer->Width) {
+ /* span is completely outside framebuffer */
+ return; /* undefined values OK */
+ }
- ASSERT( n >= 0);
+ if (x < 0) {
+ GLint dx = -x;
+ x = 0;
+ n -= dx;
+ stencil += dx;
+ }
+ if (x + n > ctx->DrawBuffer->Width) {
+ GLint dx = x + n - ctx->DrawBuffer->Width;
+ n -= dx;
+ }
+ if (n <= 0) {
+ return;
+ }
- if (ctx->Driver.WriteStencilSpan) {
- (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
- }
- else {
- GLstencil *s = STENCIL_ADDRESS( x, y );
+ if (ctx->Driver.WriteStencilSpan) {
+ (*ctx->Driver.WriteStencilSpan)( ctx, n, x, y, stencil, NULL );
+ }
+ else if (ctx->DrawBuffer->Stencil) {
+ GLstencil *s = STENCIL_ADDRESS( x, y );
#if STENCIL_BITS == 8
- MEMCPY( s, stencil, n * sizeof(GLstencil) );
+ MEMCPY( s, stencil, n * sizeof(GLstencil) );
#else
- GLuint i;
- for (i=0;i<n;i++)
- s[i] = stencil[i];
+ GLuint i;
+ for (i=0;i<n;i++)
+ s[i] = stencil[i];
#endif
- }
}
}
* Allocate a new stencil buffer. If there's an old one it will be
* deallocated first. The new stencil buffer will be uninitialized.
*/
-void gl_alloc_stencil_buffer( GLcontext *ctx )
+void
+_mesa_alloc_stencil_buffer( GLcontext *ctx )
{
GLuint buffersize = ctx->DrawBuffer->Width * ctx->DrawBuffer->Height;
if (!ctx->DrawBuffer->Stencil) {
/* out of memory */
_mesa_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
- gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
+ gl_error( ctx, GL_OUT_OF_MEMORY, "_mesa_alloc_stencil_buffer" );
}
}
static void
clear_software_stencil_buffer( GLcontext *ctx )
{
- if (ctx->Visual->StencilBits==0 || !ctx->DrawBuffer->Stencil) {
+ if (ctx->Visual.StencilBits==0 || !ctx->DrawBuffer->Stencil) {
/* no stencil buffer */
return;
}
if (ctx->Scissor.Enabled) {
/* clear scissor region only */
- const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
if (ctx->Stencil.WriteMask != STENCIL_MAX) {
/* must apply mask to the clear */
GLint y;
- for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
const GLstencil mask = ctx->Stencil.WriteMask;
const GLstencil invMask = ~mask;
const GLstencil clearVal = (ctx->Stencil.Clear & mask);
else {
/* no masking */
GLint y;
- for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
GLstencil *stencil = STENCIL_ADDRESS( ctx->DrawBuffer->Xmin, y );
#if STENCIL_BITS==8
MEMSET( stencil, ctx->Stencil.Clear, width * sizeof(GLstencil) );
if (ctx->Scissor.Enabled) {
/* clear scissor region only */
const GLint x = ctx->DrawBuffer->Xmin;
- const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin + 1;
+ const GLint width = ctx->DrawBuffer->Xmax - ctx->DrawBuffer->Xmin;
if (ctx->Stencil.WriteMask != STENCIL_MAX) {
/* must apply mask to the clear */
GLint y;
- for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
const GLstencil mask = ctx->Stencil.WriteMask;
const GLstencil invMask = ~mask;
const GLstencil clearVal = (ctx->Stencil.Clear & mask);
for (i = 0; i < width; i++) {
stencil[i] = ctx->Stencil.Clear;
}
- for (y = ctx->DrawBuffer->Ymin; y <= ctx->DrawBuffer->Ymax; y++) {
+ for (y = ctx->DrawBuffer->Ymin; y < ctx->DrawBuffer->Ymax; y++) {
(*ctx->Driver.WriteStencilSpan)(ctx, x, y, width, stencil, NULL);
}
}
/*
* Clear the stencil buffer.
*/
-void gl_clear_stencil_buffer( GLcontext *ctx )
+void
+_mesa_clear_stencil_buffer( GLcontext *ctx )
{
if (ctx->Driver.WriteStencilSpan) {
ASSERT(ctx->Driver.ReadStencilSpan);