windows-nt/Source/XPSP1/NT/multimedia/opengl/server/soft/so_stenc.c
2020-09-26 16:20:57 +08:00

323 lines
9.1 KiB
C

/*
** Copyright 1991, 1992, 1993, Silicon Graphics, Inc.
** All Rights Reserved.
**
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
** the contents of this file may not be disclosed to third parties, copied or
** duplicated in any form, in whole or in part, without the prior written
** permission of Silicon Graphics, Inc.
**
** RESTRICTED RIGHTS LEGEND:
** Use, duplication or disclosure by the Government is subject to restrictions
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
** rights reserved under the Copyright Laws of the United States.
*/
#include "precomp.h"
#pragma hdrstop
GLint FASTCALL Fetch(__GLstencilBuffer *sfb, GLint x, GLint y)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
return fb[0];
}
static void Store(__GLstencilBuffer *sfb, GLint x, GLint y,GLint v)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
fb[0] = (__GLstencilCell) ((v & sfb->buf.gc->state.stencil.writeMask)
| (fb[0] & ~sfb->buf.gc->state.stencil.writeMask));
}
static GLboolean FASTCALL TestFunc(__GLstencilBuffer *sfb, GLint x, GLint y)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
return sfb->testFuncTable[fb[0] & sfb->buf.gc->state.stencil.mask];
}
static void FASTCALL FailOp(__GLstencilBuffer *sfb, GLint x, GLint y)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
fb[0] = sfb->failOpTable[fb[0]];
}
static void FASTCALL PassDepthFailOp(__GLstencilBuffer *sfb, GLint x, GLint y)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
fb[0] = sfb->depthFailOpTable[fb[0]];
}
static void FASTCALL DepthPassOp(__GLstencilBuffer *sfb, GLint x, GLint y)
{
__GLstencilCell *fb;
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
fb[0] = sfb->depthPassOpTable[fb[0]];
}
static GLboolean FASTCALL NoOp(__GLstencilBuffer *sfb, GLint x, GLint y)
{
return GL_FALSE;
}
/************************************************************************/
static void FASTCALL Clear(__GLstencilBuffer *sfb)
{
__GLcontext *gc = sfb->buf.gc;
__GLstencilCell *fb;
GLint x, y, x1, y1, skip, w, w8, w1;
__GLstencilCell sten = (__GLstencilCell)gc->state.stencil.clear;
x = gc->transform.clipX0;
y = gc->transform.clipY0;
x1 = gc->transform.clipX1;
y1 = gc->transform.clipY1;
if (((w = x1 - x) == 0) || (y1 - y == 0)) {
return;
}
fb = __GL_STENCIL_ADDR(sfb, (__GLstencilCell*), x, y);
skip = sfb->buf.outerWidth - w;
w8 = w >> 3;
w1 = w & 7;
if (gc->state.stencil.writeMask == __GL_MAX_STENCIL_VALUE) {
for (; y < y1; y++) {
w = w8;
while (--w >= 0) {
fb[0] = sten; fb[1] = sten; fb[2] = sten; fb[3] = sten;
fb[4] = sten; fb[5] = sten; fb[6] = sten; fb[7] = sten;
fb += 8;
}
w = w1;
while (--w >= 0) {
*fb++ = sten;
}
fb += skip;
}
} else {
GLint mask;
mask = gc->state.stencil.writeMask;
sten = sten & mask;
mask = ~mask;
for (; y < y1; y++) {
w = w8;
while (--w >= 0) {
fb[0] = (fb[0] & mask) | (sten);
fb[1] = (fb[1] & mask) | (sten);
fb[2] = (fb[2] & mask) | (sten);
fb[3] = (fb[3] & mask) | (sten);
fb[4] = (fb[4] & mask) | (sten);
fb[5] = (fb[5] & mask) | (sten);
fb[6] = (fb[6] & mask) | (sten);
fb[7] = (fb[7] & mask) | (sten);
fb += 8;
}
w = w1;
while (--w >= 0) {
fb[0] = (fb[0] & mask) | (sten);
fb++;
}
fb += skip;
}
}
}
/************************************************************************/
static void buildOpTable(__GLstencilCell *tp, GLenum op,
__GLstencilCell reference, __GLstencilCell writeMask)
{
GLuint i;
__GLstencilCell newValue;
__GLstencilCell notWriteMask = ~writeMask;
for (i = 0; i < __GL_STENCIL_RANGE; i++) {
switch (op) {
case GL_KEEP: newValue = (__GLstencilCell)i; break;
case GL_ZERO: newValue = 0; break;
case GL_REPLACE: newValue = reference; break;
case GL_INVERT: newValue = ~i; break;
case GL_INCR:
/* Clamp so no overflow occurs */
if (i == __GL_MAX_STENCIL_VALUE) {
newValue = (__GLstencilCell)i;
} else {
newValue = i + 1;
}
break;
case GL_DECR:
/* Clamp so no underflow occurs */
if (i == 0) {
newValue = 0;
} else {
newValue = i - 1;
}
break;
}
*tp++ = (i & notWriteMask) | (newValue & writeMask);
}
}
#ifdef NT
void FASTCALL __glValidateStencil(__GLcontext *gc, __GLstencilBuffer *sfb)
#else
void FASTCALL __glValidateStencil(__GLcontext *gc)
#endif // NT
{
GLint i;
__GLstencilCell reference, mask, writeMask;
__GLstencilCell refVal; //actual reference value, part of GL state
GLenum testFunc;
GLboolean *tp;
/*
** Validate the stencil tables even if stenciling is disabled. This
** function is only called if the stencil func or op changes, and it
** won't get called later if stenciling is turned on, so we need to get
** it right now.
*/
mask = (__GLstencilCell) gc->state.stencil.mask;
refVal = ((__GLstencilCell) gc->state.stencil.reference);
reference = (__GLstencilCell) (refVal & mask);
testFunc = gc->state.stencil.testFunc;
/*
** Build up test function table. The current stencil buffer value
** will be the index to this table.
*/
tp = &gc->stencilBuffer.testFuncTable[0];
// If we don't have a stencil buffer then set everything to
// do nothing
if (!gc->modes.haveStencilBuffer)
{
sfb->testFunc = NoOp;
sfb->failOp = NoOp;
sfb->passDepthFailOp = NoOp;
sfb->depthPassOp = NoOp;
return;
}
else if (tp != NULL && sfb->testFunc == NoOp)
{
// If we've recovered from not having a stencil buffer then
// turn the functions back on
sfb->testFunc = TestFunc;
sfb->failOp = FailOp;
sfb->passDepthFailOp = PassDepthFailOp;
sfb->depthPassOp = DepthPassOp;
}
if (!tp)
{
gc->stencilBuffer.testFuncTable = tp = (GLboolean *)
GCALLOC(gc, (sizeof(GLboolean)+3*sizeof(__GLstencilCell))*
__GL_STENCIL_RANGE);
if (!tp)
{
sfb->testFunc = NoOp;
sfb->failOp = NoOp;
sfb->passDepthFailOp = NoOp;
sfb->depthPassOp = NoOp;
gc->stencilBuffer.failOpTable =
gc->stencilBuffer.depthFailOpTable =
gc->stencilBuffer.depthPassOpTable = (__GLstencilCell*) NULL;
return;
}
else
{
sfb->testFunc = TestFunc;
sfb->failOp = FailOp;
sfb->passDepthFailOp = PassDepthFailOp;
sfb->depthPassOp = DepthPassOp;
}
gc->stencilBuffer.failOpTable = (__GLstencilCell*)
(gc->stencilBuffer.testFuncTable + __GL_STENCIL_RANGE);
gc->stencilBuffer.depthFailOpTable = (__GLstencilCell*)
(gc->stencilBuffer.failOpTable + __GL_STENCIL_RANGE);
gc->stencilBuffer.depthPassOpTable = (__GLstencilCell*)
(gc->stencilBuffer.depthFailOpTable + __GL_STENCIL_RANGE);
}
for (i = 0; i < __GL_STENCIL_RANGE; i++) {
switch (testFunc) {
case GL_NEVER: *tp++ = GL_FALSE; break;
case GL_LESS: *tp++ = reference < (i & mask); break;
case GL_EQUAL: *tp++ = reference == (i & mask); break;
case GL_LEQUAL: *tp++ = reference <= (i & mask); break;
case GL_GREATER: *tp++ = reference > (i & mask); break;
case GL_NOTEQUAL: *tp++ = reference != (i & mask); break;
case GL_GEQUAL: *tp++ = reference >= (i & mask); break;
case GL_ALWAYS: *tp++ = GL_TRUE; break;
}
}
/*
** Build up fail op table.
*/
writeMask = (__GLstencilCell) gc->state.stencil.writeMask;
buildOpTable(&gc->stencilBuffer.failOpTable[0],
gc->state.stencil.fail, refVal, writeMask);
buildOpTable(&gc->stencilBuffer.depthFailOpTable[0],
gc->state.stencil.depthFail, refVal, writeMask);
buildOpTable(&gc->stencilBuffer.depthPassOpTable[0],
gc->state.stencil.depthPass, refVal, writeMask);
}
/************************************************************************/
static void FASTCALL Pick(__GLcontext *gc, __GLstencilBuffer *sfb)
{
#ifdef __GL_LINT
sfb = sfb;
#endif
if (gc->validateMask & (__GL_VALIDATE_STENCIL_FUNC |
__GL_VALIDATE_STENCIL_OP)) {
#ifdef NT
__glValidateStencil(gc, sfb);
#else
__glValidateStencil(gc);
#endif // NT
}
}
void FASTCALL __glInitStencil8(__GLcontext *gc, __GLstencilBuffer *sfb)
{
sfb->buf.elementSize = sizeof(__GLstencilCell);
sfb->buf.gc = gc;
sfb->pick = Pick;
sfb->store = Store;
sfb->fetch = Fetch;
#ifndef NT
// Initialized in __glValidateStencil.
sfb->testFunc = TestFunc;
sfb->failOp = FailOp;
sfb->passDepthFailOp = PassDepthFailOp;
sfb->depthPassOp = DepthPassOp;
#endif // !NT
sfb->clear = Clear;
}
void FASTCALL __glFreeStencil8(__GLcontext *gc, __GLstencilBuffer *fb)
{
#ifdef __GL_LINT
gc = gc;
fb = fb;
#endif
}