📄 s_stencil.c
字号:
/* * Mesa 3-D graphics library * Version: 7.1 * * Copyright (C) 1999-2007 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 "imports.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 valueENDIF*//** * 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 voidapply_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); const GLstencil stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1; 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 < stencilMax) { 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 < stencilMax) { 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 GLbooleando_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;}/** * Compute the zpass/zfail masks by comparing the pre- and post-depth test * masks. */static INLINE voidcompute_pass_fail_masks(GLuint n, const GLubyte origMask[], const GLubyte newMask[], GLubyte passMask[], GLubyte failMask[]){ GLuint i; for (i = 0; i < n; i++) { ASSERT(newMask[i] == 0 || newMask[i] == 1); passMask[i] = origMask[i] & newMask[i]; failMask[i] = origMask[i] & (newMask[i] ^ 1); }}/** * 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -