source: trunk/src/opengl/mesa/stencil.c@ 2938

Last change on this file since 2938 was 2938, checked in by sandervl, 25 years ago

created

File size: 27.7 KB
Line 
1/* $Id: stencil.c,v 1.1 2000-02-29 00:50:10 sandervl Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/* $XFree86: xc/lib/GL/mesa/src/stencil.c,v 1.3 1999/04/04 00:20:32 dawes Exp $ */
29
30#ifdef PC_HEADER
31#include "all.h"
32#else
33#ifndef XFree86Server
34#include <stdlib.h>
35#include <string.h>
36#else
37#include "GL/xf86glx.h"
38#endif
39#include "context.h"
40#include "macros.h"
41#include "pb.h"
42#include "stencil.h"
43#include "types.h"
44#include "enable.h"
45#endif
46
47
48
49/*
50 * Return the address of a stencil buffer value given the window coords:
51 */
52#define STENCIL_ADDRESS(X,Y) (ctx->Buffer->Stencil + ctx->Buffer->Width * (Y) + (X))
53
54
55void gl_ClearStencil( GLcontext *ctx, GLint s )
56{
57 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearStencil");
58 ctx->Stencil.Clear = (GLstencil) s;
59
60 if (ctx->Driver.ClearStencil) {
61 (*ctx->Driver.ClearStencil)( ctx, s );
62 }
63}
64
65
66
67void gl_StencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask )
68{
69 GLint maxref;
70
71 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilFunc");
72
73 switch (func) {
74 case GL_NEVER:
75 case GL_LESS:
76 case GL_LEQUAL:
77 case GL_GREATER:
78 case GL_GEQUAL:
79 case GL_EQUAL:
80 case GL_NOTEQUAL:
81 case GL_ALWAYS:
82 ctx->Stencil.Function = func;
83 break;
84 default:
85 gl_error( ctx, GL_INVALID_ENUM, "glStencilFunc" );
86 return;
87 }
88
89 maxref = (1 << STENCIL_BITS) - 1;
90 ctx->Stencil.Ref = (GLstencil) CLAMP( ref, 0, maxref );
91 ctx->Stencil.ValueMask = (GLstencil) mask;
92
93 if (ctx->Driver.StencilFunc) {
94 (*ctx->Driver.StencilFunc)( ctx, func, ctx->Stencil.Ref, mask );
95 }
96}
97
98
99
100void gl_StencilMask( GLcontext *ctx, GLuint mask )
101{
102 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilMask");
103 ctx->Stencil.WriteMask = (GLstencil) mask;
104
105 if (ctx->Driver.StencilMask) {
106 (*ctx->Driver.StencilMask)( ctx, mask );
107 }
108}
109
110
111
112void gl_StencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass )
113{
114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glStencilOp");
115 switch (fail) {
116 case GL_KEEP:
117 case GL_ZERO:
118 case GL_REPLACE:
119 case GL_INCR:
120 case GL_DECR:
121 case GL_INVERT:
122 case GL_INCR_WRAP_EXT:
123 case GL_DECR_WRAP_EXT:
124 ctx->Stencil.FailFunc = fail;
125 break;
126 default:
127 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
128 return;
129 }
130 switch (zfail) {
131 case GL_KEEP:
132 case GL_ZERO:
133 case GL_REPLACE:
134 case GL_INCR:
135 case GL_DECR:
136 case GL_INVERT:
137 case GL_INCR_WRAP_EXT:
138 case GL_DECR_WRAP_EXT:
139 ctx->Stencil.ZFailFunc = zfail;
140 break;
141 default:
142 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
143 return;
144 }
145 switch (zpass) {
146 case GL_KEEP:
147 case GL_ZERO:
148 case GL_REPLACE:
149 case GL_INCR:
150 case GL_DECR:
151 case GL_INVERT:
152 case GL_INCR_WRAP_EXT:
153 case GL_DECR_WRAP_EXT:
154 ctx->Stencil.ZPassFunc = zpass;
155 break;
156 default:
157 gl_error( ctx, GL_INVALID_ENUM, "glStencilOp" );
158 return;
159 }
160
161 if (ctx->Driver.StencilOp) {
162 (*ctx->Driver.StencilOp)( ctx, fail, zfail, zpass );
163 }
164}
165
166
167
168/* Stencil Logic:
169
170IF stencil test fails THEN
171 Apply fail-op to stencil value
172 Don't write the pixel (RGBA,Z)
173ELSE
174 IF doing depth test && depth test fails THEN
175 Apply zfail-op to stencil value
176 Write RGBA and Z to appropriate buffers
177 ELSE
178 Apply zpass-op to stencil value
179ENDIF
180
181*/
182
183
184
185
186/*
187 * Apply the given stencil operator to the array of stencil values.
188 * Don't touch stencil[i] if mask[i] is zero.
189 * Input: n - number of pixels in the span
190 * oper - the stencil buffer operator
191 * stencil - array of stencil values
192 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
193 */
194static void apply_stencil_op( GLcontext *ctx, GLenum oper,
195 GLuint n, GLstencil stencil[], GLubyte mask[] )
196{
197 const GLstencil ref = ctx->Stencil.Ref;
198 const GLstencil wrtmask = ctx->Stencil.WriteMask;
199 const GLstencil invmask = (GLstencil) (~ctx->Stencil.WriteMask);
200 GLuint i;
201
202 switch (oper) {
203 case GL_KEEP:
204 /* do nothing */
205 break;
206 case GL_ZERO:
207 if (invmask==0) {
208 for (i=0;i<n;i++) {
209 if (mask[i]) {
210 stencil[i] = 0;
211 }
212 }
213 }
214 else {
215 for (i=0;i<n;i++) {
216 if (mask[i]) {
217 stencil[i] = (GLstencil) (stencil[i] & invmask);
218 }
219 }
220 }
221 break;
222 case GL_REPLACE:
223 if (invmask==0) {
224 for (i=0;i<n;i++) {
225 if (mask[i]) {
226 stencil[i] = ref;
227 }
228 }
229 }
230 else {
231 for (i=0;i<n;i++) {
232 if (mask[i]) {
233 GLstencil s = stencil[i];
234 stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref));
235 }
236 }
237 }
238 break;
239 case GL_INCR:
240 if (invmask==0) {
241 for (i=0;i<n;i++) {
242 if (mask[i]) {
243 GLstencil s = stencil[i];
244 if (s < STENCIL_MAX) {
245 stencil[i] = (GLstencil) (s+1);
246 }
247 }
248 }
249 }
250 else {
251 for (i=0;i<n;i++) {
252 if (mask[i]) {
253 /* VERIFY logic of adding 1 to a write-masked value */
254 GLstencil s = stencil[i];
255 if (s < STENCIL_MAX) {
256 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1)));
257 }
258 }
259 }
260 }
261 break;
262 case GL_DECR:
263 if (invmask==0) {
264 for (i=0;i<n;i++) {
265 if (mask[i]) {
266 GLstencil s = stencil[i];
267 if (s>0) {
268 stencil[i] = (GLstencil) (s-1);
269 }
270 }
271 }
272 }
273 else {
274 for (i=0;i<n;i++) {
275 if (mask[i]) {
276 /* VERIFY logic of subtracting 1 to a write-masked value */
277 GLstencil s = stencil[i];
278 if (s>0) {
279 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1)));
280 }
281 }
282 }
283 }
284 break;
285 case GL_INCR_WRAP_EXT:
286 if (invmask==0) {
287 for (i=0;i<n;i++) {
288 if (mask[i]) {
289 stencil[i]++;
290 }
291 }
292 }
293 else {
294 for (i=0;i<n;i++) {
295 if (mask[i]) {
296 GLstencil s = stencil[i];
297 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (stencil[i]+1)));
298 }
299 }
300 }
301 break;
302 case GL_DECR_WRAP_EXT:
303 if (invmask==0) {
304 for (i=0;i<n;i++) {
305 if (mask[i]) {
306 stencil[i]--;
307 }
308 }
309 }
310 else {
311 for (i=0;i<n;i++) {
312 if (mask[i]) {
313 GLstencil s = stencil[i];
314 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (stencil[i]-1)));
315 }
316 }
317 }
318 break;
319 case GL_INVERT:
320 if (invmask==0) {
321 for (i=0;i<n;i++) {
322 if (mask[i]) {
323 GLstencil s = stencil[i];
324 stencil[i] = (GLstencil) ~s;
325 }
326 }
327 }
328 else {
329 for (i=0;i<n;i++) {
330 if (mask[i]) {
331 GLstencil s = stencil[i];
332 stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s));
333 }
334 }
335 }
336 break;
337 default:
338 gl_problem(ctx, "Bad stencil op in apply_stencil_op");
339 }
340}
341
342
343
344
345/*
346 * Apply stencil test to a span of pixels before depth buffering.
347 * Input: n - number of pixels in the span
348 * x, y - coordinate of left-most pixel in the span
349 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
350 * Output: mask - pixels which fail the stencil test will have their
351 * mask flag set to 0.
352 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
353 */
354GLint gl_stencil_span( GLcontext *ctx,
355 GLuint n, GLint x, GLint y, GLubyte mask[] )
356{
357 GLubyte fail[MAX_WIDTH];
358 GLint allfail = 0;
359 GLuint i;
360 GLstencil r, s;
361 GLstencil *stencil;
362
363 stencil = STENCIL_ADDRESS( x, y );
364
365 /*
366 * Perform stencil test. The results of this operation are stored
367 * in the fail[] array:
368 * IF fail[i] is non-zero THEN
369 * the stencil fail operator is to be applied
370 * ELSE
371 * the stencil fail operator is not to be applied
372 * ENDIF
373 */
374 switch (ctx->Stencil.Function) {
375 case GL_NEVER:
376 /* always fail */
377 for (i=0;i<n;i++) {
378 if (mask[i]) {
379 mask[i] = 0;
380 fail[i] = 1;
381 }
382 else {
383 fail[i] = 0;
384 }
385 }
386 allfail = 1;
387 break;
388 case GL_LESS:
389 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
390 for (i=0;i<n;i++) {
391 if (mask[i]) {
392 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
393 if (r < s) {
394 /* passed */
395 fail[i] = 0;
396 }
397 else {
398 fail[i] = 1;
399 mask[i] = 0;
400 }
401 }
402 else {
403 fail[i] = 0;
404 }
405 }
406 break;
407 case GL_LEQUAL:
408 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
409 for (i=0;i<n;i++) {
410 if (mask[i]) {
411 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
412 if (r <= s) {
413 /* pass */
414 fail[i] = 0;
415 }
416 else {
417 fail[i] = 1;
418 mask[i] = 0;
419 }
420 }
421 else {
422 fail[i] = 0;
423 }
424 }
425 break;
426 case GL_GREATER:
427 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
428 for (i=0;i<n;i++) {
429 if (mask[i]) {
430 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
431 if (r > s) {
432 /* passed */
433 fail[i] = 0;
434 }
435 else {
436 fail[i] = 1;
437 mask[i] = 0;
438 }
439 }
440 else {
441 fail[i] = 0;
442 }
443 }
444 break;
445 case GL_GEQUAL:
446 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
447 for (i=0;i<n;i++) {
448 if (mask[i]) {
449 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
450 if (r >= s) {
451 /* passed */
452 fail[i] = 0;
453 }
454 else {
455 fail[i] = 1;
456 mask[i] = 0;
457 }
458 }
459 else {
460 fail[i] = 0;
461 }
462 }
463 break;
464 case GL_EQUAL:
465 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
466 for (i=0;i<n;i++) {
467 if (mask[i]) {
468 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
469 if (r == s) {
470 /* passed */
471 fail[i] = 0;
472 }
473 else {
474 fail[i] = 1;
475 mask[i] = 0;
476 }
477 }
478 else {
479 fail[i] = 0;
480 }
481 }
482 break;
483 case GL_NOTEQUAL:
484 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
485 for (i=0;i<n;i++) {
486 if (mask[i]) {
487 s = (GLstencil) (stencil[i] & ctx->Stencil.ValueMask);
488 if (r != s) {
489 /* passed */
490 fail[i] = 0;
491 }
492 else {
493 fail[i] = 1;
494 mask[i] = 0;
495 }
496 }
497 else {
498 fail[i] = 0;
499 }
500 }
501 break;
502 case GL_ALWAYS:
503 /* always pass */
504 for (i=0;i<n;i++) {
505 fail[i] = 0;
506 }
507 break;
508 default:
509 gl_problem(ctx, "Bad stencil func in gl_stencil_span");
510 return 0;
511 }
512
513 if (ctx->Stencil.FailFunc != GL_KEEP) {
514 apply_stencil_op( ctx, ctx->Stencil.FailFunc, n, stencil, fail );
515 }
516
517 return (allfail) ? 0 : 1;
518}
519
520
521
522
523/*
524 * Apply the combination depth-buffer/stencil operator to a span of pixels.
525 * Input: n - number of pixels in the span
526 * x, y - location of leftmost pixel in span
527 * z - array [n] of z values
528 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
529 * Output: mask - array [n] of flags (1=depth test passed, 0=failed)
530 */
531void gl_depth_stencil_span( GLcontext *ctx,
532 GLuint n, GLint x, GLint y, const GLdepth z[],
533 GLubyte mask[] )
534{
535 GLstencil *stencil = STENCIL_ADDRESS(x, y);
536
537 if (ctx->Depth.Test==GL_FALSE) {
538 /*
539 * No depth buffer, just apply zpass stencil function to active pixels.
540 */
541 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, mask );
542 }
543 else {
544 /*
545 * Perform depth buffering, then apply zpass or zfail stencil function.
546 */
547 GLubyte passmask[MAX_WIDTH], failmask[MAX_WIDTH], oldmask[MAX_WIDTH];
548 GLuint i;
549
550 /* save the current mask bits */
551 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
552
553 /* apply the depth test */
554 if (ctx->Driver.DepthTestSpan)
555 (*ctx->Driver.DepthTestSpan)( ctx, n, x, y, z, mask );
556
557 /* Set the stencil pass/fail flags according to result of depth testing.
558 * if oldmask[i] == 0 then
559 * Don't touch the stencil value
560 * else if oldmask[i] and newmask[i] then
561 * Depth test passed
562 * else
563 * assert(oldmask[i] && !newmask[i])
564 * Depth test failed
565 * endif
566 */
567 for (i=0;i<n;i++) {
568 ASSERT(mask[i] == 0 || mask[i] == 1);
569 passmask[i] = oldmask[i] & mask[i];
570 failmask[i] = oldmask[i] & (mask[i] ^ 1);
571 }
572
573 /* apply the pass and fail operations */
574 if (ctx->Stencil.ZFailFunc != GL_KEEP) {
575 apply_stencil_op( ctx, ctx->Stencil.ZFailFunc, n, stencil, failmask );
576 }
577 if (ctx->Stencil.ZPassFunc != GL_KEEP) {
578 apply_stencil_op( ctx, ctx->Stencil.ZPassFunc, n, stencil, passmask );
579 }
580 }
581}
582
583
584
585
586/*
587 * Apply the given stencil operator for each pixel in the array whose
588 * mask flag is set.
589 * Input: n - number of pixels in the span
590 * x, y - array of [n] pixels
591 * operator - the stencil buffer operator
592 * mask - array [n] of flag: 1=apply operator, 0=don't apply operator
593 */
594static void apply_stencil_op_to_pixels( GLcontext *ctx,
595 GLuint n, const GLint x[],
596 const GLint y[],
597 GLenum oper, GLubyte mask[] )
598{
599 GLuint i;
600 GLstencil ref;
601 GLstencil wrtmask, invmask;
602
603 wrtmask = ctx->Stencil.WriteMask;
604 invmask = (GLstencil) (~ctx->Stencil.WriteMask);
605
606 ref = ctx->Stencil.Ref;
607
608 switch (oper) {
609 case GL_KEEP:
610 /* do nothing */
611 break;
612 case GL_ZERO:
613 if (invmask==0) {
614 for (i=0;i<n;i++) {
615 if (mask[i]) {
616 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
617 *sptr = 0;
618 }
619 }
620 }
621 else {
622 for (i=0;i<n;i++) {
623 if (mask[i]) {
624 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
625 *sptr = (GLstencil) (invmask & *sptr);
626 }
627 }
628 }
629 break;
630 case GL_REPLACE:
631 if (invmask==0) {
632 for (i=0;i<n;i++) {
633 if (mask[i]) {
634 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
635 *sptr = ref;
636 }
637 }
638 }
639 else {
640 for (i=0;i<n;i++) {
641 if (mask[i]) {
642 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
643 *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref));
644 }
645 }
646 }
647 break;
648 case GL_INCR:
649 if (invmask==0) {
650 for (i=0;i<n;i++) {
651 if (mask[i]) {
652 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
653 if (*sptr < STENCIL_MAX) {
654 *sptr = (GLstencil) (*sptr + 1);
655 }
656 }
657 }
658 }
659 else {
660 for (i=0;i<n;i++) {
661 if (mask[i]) {
662 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
663 if (*sptr < STENCIL_MAX) {
664 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
665 }
666 }
667 }
668 }
669 break;
670 case GL_DECR:
671 if (invmask==0) {
672 for (i=0;i<n;i++) {
673 if (mask[i]) {
674 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
675 if (*sptr>0) {
676 *sptr = (GLstencil) (*sptr - 1);
677 }
678 }
679 }
680 }
681 else {
682 for (i=0;i<n;i++) {
683 if (mask[i]) {
684 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
685 if (*sptr>0) {
686 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
687 }
688 }
689 }
690 }
691 break;
692 case GL_INCR_WRAP_EXT:
693 if (invmask==0) {
694 for (i=0;i<n;i++) {
695 if (mask[i]) {
696 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
697 *sptr = (GLstencil) (*sptr + 1);
698 }
699 }
700 }
701 else {
702 for (i=0;i<n;i++) {
703 if (mask[i]) {
704 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
705 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1)));
706 }
707 }
708 }
709 break;
710 case GL_DECR_WRAP_EXT:
711 if (invmask==0) {
712 for (i=0;i<n;i++) {
713 if (mask[i]) {
714 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
715 *sptr = (GLstencil) (*sptr - 1);
716 }
717 }
718 }
719 else {
720 for (i=0;i<n;i++) {
721 if (mask[i]) {
722 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
723 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1)));
724 }
725 }
726 }
727 break;
728 case GL_INVERT:
729 if (invmask==0) {
730 for (i=0;i<n;i++) {
731 if (mask[i]) {
732 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
733 *sptr = (GLstencil) (~*sptr);
734 }
735 }
736 }
737 else {
738 for (i=0;i<n;i++) {
739 if (mask[i]) {
740 GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] );
741 *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr));
742 }
743 }
744 }
745 break;
746 default:
747 gl_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels");
748 }
749}
750
751
752
753/*
754 * Apply stencil test to an array of pixels before depth buffering.
755 * Input: n - number of pixels in the span
756 * x, y - array of [n] pixels to stencil
757 * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel
758 * Output: mask - pixels which fail the stencil test will have their
759 * mask flag set to 0.
760 * Return: 0 = all pixels failed, 1 = zero or more pixels passed.
761 */
762GLint gl_stencil_pixels( GLcontext *ctx,
763 GLuint n, const GLint x[], const GLint y[],
764 GLubyte mask[] )
765{
766 GLubyte fail[PB_SIZE];
767 GLstencil r, s;
768 GLuint i;
769 GLint allfail = 0;
770
771 /*
772 * Perform stencil test. The results of this operation are stored
773 * in the fail[] array:
774 * IF fail[i] is non-zero THEN
775 * the stencil fail operator is to be applied
776 * ELSE
777 * the stencil fail operator is not to be applied
778 * ENDIF
779 */
780
781 switch (ctx->Stencil.Function) {
782 case GL_NEVER:
783 /* always fail */
784 for (i=0;i<n;i++) {
785 if (mask[i]) {
786 mask[i] = 0;
787 fail[i] = 1;
788 }
789 else {
790 fail[i] = 0;
791 }
792 }
793 allfail = 1;
794 break;
795 case GL_LESS:
796 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
797 for (i=0;i<n;i++) {
798 if (mask[i]) {
799 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
800 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
801 if (r < s) {
802 /* passed */
803 fail[i] = 0;
804 }
805 else {
806 fail[i] = 1;
807 mask[i] = 0;
808 }
809 }
810 else {
811 fail[i] = 0;
812 }
813 }
814 break;
815 case GL_LEQUAL:
816 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
817 for (i=0;i<n;i++) {
818 if (mask[i]) {
819 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
820 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
821 if (r <= s) {
822 /* pass */
823 fail[i] = 0;
824 }
825 else {
826 fail[i] = 1;
827 mask[i] = 0;
828 }
829 }
830 else {
831 fail[i] = 0;
832 }
833 }
834 break;
835 case GL_GREATER:
836 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
837 for (i=0;i<n;i++) {
838 if (mask[i]) {
839 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
840 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
841 if (r > s) {
842 /* passed */
843 fail[i] = 0;
844 }
845 else {
846 fail[i] = 1;
847 mask[i] = 0;
848 }
849 }
850 else {
851 fail[i] = 0;
852 }
853 }
854 break;
855 case GL_GEQUAL:
856 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
857 for (i=0;i<n;i++) {
858 if (mask[i]) {
859 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
860 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
861 if (r >= s) {
862 /* passed */
863 fail[i] = 0;
864 }
865 else {
866 fail[i] = 1;
867 mask[i] = 0;
868 }
869 }
870 else {
871 fail[i] = 0;
872 }
873 }
874 break;
875 case GL_EQUAL:
876 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
877 for (i=0;i<n;i++) {
878 if (mask[i]) {
879 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
880 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
881 if (r == s) {
882 /* passed */
883 fail[i] = 0;
884 }
885 else {
886 fail[i] = 1;
887 mask[i] = 0;
888 }
889 }
890 else {
891 fail[i] = 0;
892 }
893 }
894 break;
895 case GL_NOTEQUAL:
896 r = (GLstencil) (ctx->Stencil.Ref & ctx->Stencil.ValueMask);
897 for (i=0;i<n;i++) {
898 if (mask[i]) {
899 GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]);
900 s = (GLstencil) (*sptr & ctx->Stencil.ValueMask);
901 if (r != s) {
902 /* passed */
903 fail[i] = 0;
904 }
905 else {
906 fail[i] = 1;
907 mask[i] = 0;
908 }
909 }
910 else {
911 fail[i] = 0;
912 }
913 }
914 break;
915 case GL_ALWAYS:
916 /* always pass */
917 for (i=0;i<n;i++) {
918 fail[i] = 0;
919 }
920 break;
921 default:
922 gl_problem(ctx, "Bad stencil func in gl_stencil_pixels");
923 return 0;
924 }
925
926 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc, fail );
927
928 return (allfail) ? 0 : 1;
929}
930
931
932
933
934/*
935 * Apply the combination depth-buffer/stencil operator to a span of pixels.
936 * Input: n - number of pixels in the span
937 * x, y - array of [n] pixels to stencil
938 * z - array [n] of z values
939 * Input: mask - array [n] of flags (1=test this pixel, 0=skip the pixel)
940 * Output: mask - array [n] of flags (1=depth test passed, 0=failed)
941 */
942void gl_depth_stencil_pixels( GLcontext *ctx,
943 GLuint n, const GLint x[], const GLint y[],
944 const GLdepth z[], GLubyte mask[] )
945{
946 if (ctx->Depth.Test==GL_FALSE) {
947 /*
948 * No depth buffer, just apply zpass stencil function to active pixels.
949 */
950 apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.ZPassFunc, mask );
951 }
952 else {
953 /*
954 * Perform depth buffering, then apply zpass or zfail stencil function.
955 */
956 GLubyte passmask[PB_SIZE], failmask[PB_SIZE], oldmask[PB_SIZE];
957 GLuint i;
958
959 /* save the current mask bits */
960 MEMCPY(oldmask, mask, n * sizeof(GLubyte));
961
962 /* apply the depth test */
963 if (ctx->Driver.DepthTestPixels)
964 (*ctx->Driver.DepthTestPixels)( ctx, n, x, y, z, mask );
965
966 /* Set the stencil pass/fail flags according to result of depth testing.
967 * if oldmask[i] == 0 then
968 * Don't touch the stencil value
969 * else if oldmask[i] and newmask[i] then
970 * Depth test passed
971 * else
972 * assert(oldmask[i] && !newmask[i])
973 * Depth test failed
974 * endif
975 */
976 for (i=0;i<n;i++) {
977 ASSERT(mask[i] == 0 || mask[i] == 1);
978 passmask[i] = oldmask[i] & mask[i];
979 failmask[i] = oldmask[i] & (mask[i] ^ 1);
980 }
981
982 /* apply the pass and fail operations */
983 apply_stencil_op_to_pixels( ctx, n, x, y,
984 ctx->Stencil.ZFailFunc, failmask );
985 apply_stencil_op_to_pixels( ctx, n, x, y,
986 ctx->Stencil.ZPassFunc, passmask );
987 }
988
989}
990
991
992
993/*
994 * Return a span of stencil values from the stencil buffer.
995 * Input: n - how many pixels
996 * x,y - location of first pixel
997 * Output: stencil - the array of stencil values
998 */
999void gl_read_stencil_span( GLcontext *ctx,
1000 GLuint n, GLint x, GLint y, GLstencil stencil[] )
1001{
1002 if (ctx->Buffer->Stencil) {
1003 const GLstencil *s = STENCIL_ADDRESS( x, y );
1004#if STENCIL_BITS == 8
1005 MEMCPY( stencil, s, n * sizeof(GLstencil) );
1006#else
1007 GLuint i;
1008 for (i=0;i<n;i++)
1009 stencil[i] = s[i];
1010#endif
1011 }
1012}
1013
1014
1015
1016/*
1017 * Write a span of stencil values to the stencil buffer.
1018 * Input: n - how many pixels
1019 * x,y - location of first pixel
1020 * stencil - the array of stencil values
1021 */
1022void gl_write_stencil_span( GLcontext *ctx,
1023 GLuint n, GLint x, GLint y,
1024 const GLstencil stencil[] )
1025{
1026 if (ctx->Buffer->Stencil) {
1027 GLstencil *s = STENCIL_ADDRESS( x, y );
1028#if STENCIL_BITS == 8
1029 MEMCPY( s, stencil, n * sizeof(GLstencil) );
1030#else
1031 GLuint i;
1032 for (i=0;i<n;i++)
1033 s[i] = stencil[i];
1034#endif
1035 }
1036}
1037
1038
1039
1040/*
1041 * Allocate a new stencil buffer. If there's an old one it will be
1042 * deallocated first. The new stencil buffer will be uninitialized.
1043 */
1044void gl_alloc_stencil_buffer( GLcontext *ctx )
1045{
1046 GLuint buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
1047
1048 /* deallocate current stencil buffer if present */
1049 if (ctx->Buffer->Stencil) {
1050 FREE(ctx->Buffer->Stencil);
1051 ctx->Buffer->Stencil = NULL;
1052 }
1053
1054 /* allocate new stencil buffer */
1055 ctx->Buffer->Stencil = (GLstencil *) MALLOC(buffersize * sizeof(GLstencil));
1056 if (!ctx->Buffer->Stencil) {
1057 /* out of memory */
1058 gl_set_enable( ctx, GL_STENCIL_TEST, GL_FALSE );
1059 gl_error( ctx, GL_OUT_OF_MEMORY, "gl_alloc_stencil_buffer" );
1060 }
1061}
1062
1063
1064
1065
1066/*
1067 * Clear the stencil buffer. If the stencil buffer doesn't exist yet we'll
1068 * allocate it now.
1069 */
1070void gl_clear_stencil_buffer( GLcontext *ctx )
1071{
1072 if (ctx->Visual->StencilBits==0 || !ctx->Buffer->Stencil) {
1073 /* no stencil buffer */
1074 return;
1075 }
1076
1077 if (ctx->Scissor.Enabled) {
1078 /* clear scissor region only */
1079 const GLint width = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1;
1080 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1081 /* must apply mask to the clear */
1082 GLint y;
1083 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
1084 GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y );
1085 GLint x;
1086 const GLstencil mask = ctx->Stencil.WriteMask;
1087 const GLstencil invMask = ~mask;
1088 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1089 for (x = 0; x < width; x++) {
1090 ptr[x] = (ptr[x] & invMask) | clearVal;
1091 }
1092 }
1093 }
1094 else {
1095 /* no masking */
1096 GLint y;
1097 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
1098 GLstencil *ptr = STENCIL_ADDRESS( ctx->Buffer->Xmin, y );
1099#if STENCIL_BITS==8
1100 MEMSET( ptr, ctx->Stencil.Clear, width * sizeof(GLstencil) );
1101#else
1102 GLint x;
1103 for (x = 0; x < width; x++)
1104 ptr[x] = ctx->Stencil.Clear;
1105#endif
1106 }
1107 }
1108 }
1109 else {
1110 /* clear whole stencil buffer */
1111 if (ctx->Stencil.WriteMask != STENCIL_MAX) {
1112 /* must apply mask to the clear */
1113 const GLuint n = ctx->Buffer->Width * ctx->Buffer->Height;
1114 GLstencil *buffer = ctx->Buffer->Stencil;
1115 const GLstencil mask = ctx->Stencil.WriteMask;
1116 const GLstencil invMask = ~mask;
1117 const GLstencil clearVal = (ctx->Stencil.Clear & mask);
1118 GLuint i;
1119 for (i = 0; i < n; i++) {
1120 buffer[i] = (buffer[i] & invMask) | clearVal;
1121 }
1122 }
1123 else {
1124 /* clear whole buffer without masking */
1125 const GLuint n = ctx->Buffer->Width * ctx->Buffer->Height;
1126 GLstencil *buffer = ctx->Buffer->Stencil;
1127
1128#if STENCIL_BITS==8
1129 MEMSET(buffer, ctx->Stencil.Clear, n * sizeof(GLstencil) );
1130#else
1131 GLuint i;
1132 for (i = 0; i < n; i++) {
1133 buffer[i] = ctx->Stencil.Clear;
1134 }
1135#endif
1136 }
1137 }
1138}
Note: See TracBrowser for help on using the repository browser.