📄 s_stencil.c
字号:
/*
* Mesa 3-D graphics library
* Version: 6.4
*
* Copyright (C) 1999-2005 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"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "glheader.h"
#include "context.h"
#include "macros.h"
#include "imports.h"
#include "fbobject.h"
#include "s_context.h"
#include "s_depth.h"
#include "s_stencil.h"
#include "s_span.h"
/* Stencil Logic:
IF stencil test fails THEN
Apply fail-op to stencil value
Don't write the pixel (RGBA,Z)
ELSE
IF doing depth test && depth test fails THEN
Apply zfail-op to stencil value
Write RGBA and Z to appropriate buffers
ELSE
Apply zpass-op to stencil value
ENDIF
*/
/**
* Apply the given stencil operator to the array of stencil values.
* Don't touch stencil[i] if mask[i] is zero.
* Input: n - size of stencil array
* oper - the stencil buffer operator
* face - 0 or 1 for front or back face operation
* stencil - array of stencil values
* mask - array [n] of flag: 1=apply operator, 0=don't apply operator
* Output: stencil - modified values
*/
static void
apply_stencil_op( const GLcontext *ctx, GLenum oper, GLuint face,
GLuint n, GLstencil stencil[], const GLubyte mask[] )
{
const GLstencil ref = ctx->Stencil.Ref[face];
const GLstencil wrtmask = ctx->Stencil.WriteMask[face];
const GLstencil invmask = (GLstencil) (~wrtmask);
GLuint i;
switch (oper) {
case GL_KEEP:
/* do nothing */
break;
case GL_ZERO:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
stencil[i] = 0;
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
stencil[i] = (GLstencil) (stencil[i] & invmask);
}
}
}
break;
case GL_REPLACE:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
stencil[i] = ref;
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
}
}
}
break;
case GL_INCR:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
if (s < STENCIL_MAX) {
stencil[i] = (GLstencil) (s+1);
}
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
/* VERIFY logic of adding 1 to a write-masked value */
GLstencil s = stencil[i];
if (s < STENCIL_MAX) {
stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
}
}
}
}
break;
case GL_DECR:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
if (s>0) {
stencil[i] = (GLstencil) (s-1);
}
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
/* VERIFY logic of subtracting 1 to a write-masked value */
GLstencil s = stencil[i];
if (s>0) {
stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
}
}
}
}
break;
case GL_INCR_WRAP_EXT:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
stencil[i]++;
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
}
}
}
break;
case GL_DECR_WRAP_EXT:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
stencil[i]--;
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
}
}
}
break;
case GL_INVERT:
if (invmask==0) {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
stencil[i] = (GLstencil) ~s;
}
}
}
else {
for (i=0;i<n;i++) {
if (mask[i]) {
GLstencil s = stencil[i];
stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
}
}
}
break;
default:
_mesa_problem(ctx, "Bad stencil op in apply_stencil_op");
}
}
/**
* Apply stencil test to an array of stencil values (before depth buffering).
* Input: face - 0 or 1 for front or back-face polygons
* n - number of pixels in the array
* stencil - array of [n] stencil values
* 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.
* stencil - updated stencil values (where the test passed)
* Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
*/
static GLboolean
do_stencil_test( GLcontext *ctx, GLuint face, GLuint n, GLstencil stencil[],
GLubyte mask[] )
{
GLubyte fail[MAX_WIDTH];
GLboolean allfail = GL_FALSE;
GLuint i;
GLstencil r, s;
const GLuint valueMask = ctx->Stencil.ValueMask[face];
ASSERT(n <= MAX_WIDTH);
/*
* 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:
/* never pass; 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]) {
s = (GLstencil) (stencil[i] & 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]) {
s = (GLstencil) (stencil[i] & 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]) {
s = (GLstencil) (stencil[i] & 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]) {
s = (GLstencil) (stencil[i] & 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]) {
s = (GLstencil) (stencil[i] & 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]) {
s = (GLstencil) (stencil[i] & 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_span");
return 0;
}
if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
apply_stencil_op( ctx, ctx->Stencil.FailFunc[face], face, n, stencil, fail );
}
return !allfail;
}
/**
* Apply stencil and depth testing to the span of pixels.
* Both software and hardware stencil buffers are acceptable.
* Input: n - number of pixels in the span
* x, y - location of leftmost pixel in span
* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -