Initial revision
[mesa.git] / src / mesa / main / depth.c
1 /* $Id: depth.c,v 1.1 1999/08/19 00:55:41 jtg 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 /*
29 * Depth buffer functions
30 */
31
32
33 #ifdef PC_HEADER
34 #include "all.h"
35 #else
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include "context.h"
40 #include "enums.h"
41 #include "depth.h"
42 #include "macros.h"
43 #include "types.h"
44 #ifdef XFree86Server
45 #include "GL/xf86glx.h"
46 #endif
47 #endif
48
49
50
51 /**********************************************************************/
52 /***** API Functions *****/
53 /**********************************************************************/
54
55
56
57 void gl_ClearDepth( GLcontext* ctx, GLclampd depth )
58 {
59 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glClearDepth");
60 ctx->Depth.Clear = (GLfloat) CLAMP( depth, 0.0, 1.0 );
61 if (ctx->Driver.ClearDepth)
62 (*ctx->Driver.ClearDepth)( ctx, ctx->Depth.Clear );
63 }
64
65
66
67 void gl_DepthFunc( GLcontext* ctx, GLenum func )
68 {
69 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDepthFunc");
70
71 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
72 fprintf(stderr, "glDepthFunc %s\n", gl_lookup_enum_by_nr(func));
73
74
75 switch (func) {
76 case GL_NEVER:
77 case GL_LESS: /* (default) pass if incoming z < stored z */
78 case GL_GEQUAL:
79 case GL_LEQUAL:
80 case GL_GREATER:
81 case GL_NOTEQUAL:
82 case GL_EQUAL:
83 case GL_ALWAYS:
84 if (ctx->Depth.Func != func) {
85 ctx->Depth.Func = func;
86 ctx->NewState |= NEW_RASTER_OPS;
87 if (ctx->Driver.DepthFunc) {
88 (*ctx->Driver.DepthFunc)( ctx, func );
89 }
90 }
91 break;
92 default:
93 gl_error( ctx, GL_INVALID_ENUM, "glDepth.Func" );
94 }
95 }
96
97
98
99 void gl_DepthMask( GLcontext* ctx, GLboolean flag )
100 {
101 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDepthMask");
102
103 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
104 fprintf(stderr, "glDepthMask %d\n", flag);
105
106 /*
107 * GL_TRUE indicates depth buffer writing is enabled (default)
108 * GL_FALSE indicates depth buffer writing is disabled
109 */
110 if (ctx->Depth.Mask != flag) {
111 ctx->Depth.Mask = flag;
112 ctx->NewState |= NEW_RASTER_OPS;
113 if (ctx->Driver.DepthMask) {
114 (*ctx->Driver.DepthMask)( ctx, flag );
115 }
116 }
117 }
118
119
120
121 /**********************************************************************/
122 /***** Depth Testing Functions *****/
123 /**********************************************************************/
124
125
126 /*
127 * Depth test horizontal spans of fragments. These functions are called
128 * via ctx->Driver.depth_test_span only.
129 *
130 * Input: n - number of pixels in the span
131 * x, y - location of leftmost pixel in span in window coords
132 * z - array [n] of integer depth values
133 * In/Out: mask - array [n] of flags (1=draw pixel, 0=don't draw)
134 * Return: number of pixels which passed depth test
135 */
136
137
138 /*
139 * glDepthFunc( any ) and glDepthMask( GL_TRUE or GL_FALSE ).
140 */
141 GLuint gl_depth_test_span_generic( GLcontext* ctx,
142 GLuint n, GLint x, GLint y,
143 const GLdepth z[],
144 GLubyte mask[] )
145 {
146 GLdepth *zptr = Z_ADDRESS( ctx, x, y );
147 GLubyte *m = mask;
148 GLuint i;
149 GLuint passed = 0;
150
151 /* switch cases ordered from most frequent to less frequent */
152 switch (ctx->Depth.Func) {
153 case GL_LESS:
154 if (ctx->Depth.Mask) {
155 /* Update Z buffer */
156 for (i=0; i<n; i++,zptr++,m++) {
157 if (*m) {
158 if (z[i] < *zptr) {
159 /* pass */
160 *zptr = z[i];
161 passed++;
162 }
163 else {
164 /* fail */
165 *m = 0;
166 }
167 }
168 }
169 }
170 else {
171 /* Don't update Z buffer */
172 for (i=0; i<n; i++,zptr++,m++) {
173 if (*m) {
174 if (z[i] < *zptr) {
175 /* pass */
176 passed++;
177 }
178 else {
179 *m = 0;
180 }
181 }
182 }
183 }
184 break;
185 case GL_LEQUAL:
186 if (ctx->Depth.Mask) {
187 /* Update Z buffer */
188 for (i=0;i<n;i++,zptr++,m++) {
189 if (*m) {
190 if (z[i] <= *zptr) {
191 *zptr = z[i];
192 passed++;
193 }
194 else {
195 *m = 0;
196 }
197 }
198 }
199 }
200 else {
201 /* Don't update Z buffer */
202 for (i=0;i<n;i++,zptr++,m++) {
203 if (*m) {
204 if (z[i] <= *zptr) {
205 /* pass */
206 passed++;
207 }
208 else {
209 *m = 0;
210 }
211 }
212 }
213 }
214 break;
215 case GL_GEQUAL:
216 if (ctx->Depth.Mask) {
217 /* Update Z buffer */
218 for (i=0;i<n;i++,zptr++,m++) {
219 if (*m) {
220 if (z[i] >= *zptr) {
221 *zptr = z[i];
222 passed++;
223 }
224 else {
225 *m = 0;
226 }
227 }
228 }
229 }
230 else {
231 /* Don't update Z buffer */
232 for (i=0;i<n;i++,zptr++,m++) {
233 if (*m) {
234 if (z[i] >= *zptr) {
235 /* pass */
236 passed++;
237 }
238 else {
239 *m = 0;
240 }
241 }
242 }
243 }
244 break;
245 case GL_GREATER:
246 if (ctx->Depth.Mask) {
247 /* Update Z buffer */
248 for (i=0;i<n;i++,zptr++,m++) {
249 if (*m) {
250 if (z[i] > *zptr) {
251 *zptr = z[i];
252 passed++;
253 }
254 else {
255 *m = 0;
256 }
257 }
258 }
259 }
260 else {
261 /* Don't update Z buffer */
262 for (i=0;i<n;i++,zptr++,m++) {
263 if (*m) {
264 if (z[i] > *zptr) {
265 /* pass */
266 passed++;
267 }
268 else {
269 *m = 0;
270 }
271 }
272 }
273 }
274 break;
275 case GL_NOTEQUAL:
276 if (ctx->Depth.Mask) {
277 /* Update Z buffer */
278 for (i=0;i<n;i++,zptr++,m++) {
279 if (*m) {
280 if (z[i] != *zptr) {
281 *zptr = z[i];
282 passed++;
283 }
284 else {
285 *m = 0;
286 }
287 }
288 }
289 }
290 else {
291 /* Don't update Z buffer */
292 for (i=0;i<n;i++,zptr++,m++) {
293 if (*m) {
294 if (z[i] != *zptr) {
295 /* pass */
296 passed++;
297 }
298 else {
299 *m = 0;
300 }
301 }
302 }
303 }
304 break;
305 case GL_EQUAL:
306 if (ctx->Depth.Mask) {
307 /* Update Z buffer */
308 for (i=0;i<n;i++,zptr++,m++) {
309 if (*m) {
310 if (z[i] == *zptr) {
311 *zptr = z[i];
312 passed++;
313 }
314 else {
315 *m =0;
316 }
317 }
318 }
319 }
320 else {
321 /* Don't update Z buffer */
322 for (i=0;i<n;i++,zptr++,m++) {
323 if (*m) {
324 if (z[i] == *zptr) {
325 /* pass */
326 passed++;
327 }
328 else {
329 *m =0;
330 }
331 }
332 }
333 }
334 break;
335 case GL_ALWAYS:
336 if (ctx->Depth.Mask) {
337 /* Update Z buffer */
338 for (i=0;i<n;i++,zptr++,m++) {
339 if (*m) {
340 *zptr = z[i];
341 passed++;
342 }
343 }
344 }
345 else {
346 /* Don't update Z buffer or mask */
347 passed = n;
348 }
349 break;
350 case GL_NEVER:
351 for (i=0;i<n;i++) {
352 mask[i] = 0;
353 }
354 break;
355 default:
356 gl_problem(ctx, "Bad depth func in gl_depth_test_span_generic");
357 } /*switch*/
358
359 return passed;
360 }
361
362
363
364 /*
365 * glDepthFunc(GL_LESS) and glDepthMask(GL_TRUE).
366 */
367 GLuint gl_depth_test_span_less( GLcontext* ctx,
368 GLuint n, GLint x, GLint y, const GLdepth z[],
369 GLubyte mask[] )
370 {
371 GLdepth *zptr = Z_ADDRESS( ctx, x, y );
372 GLuint i;
373 GLuint passed = 0;
374
375 for (i=0; i<n; i++) {
376 if (mask[i]) {
377 if (z[i] < zptr[i]) {
378 /* pass */
379 zptr[i] = z[i];
380 passed++;
381 }
382 else {
383 /* fail */
384 mask[i] = 0;
385 }
386 }
387 }
388 return passed;
389 }
390
391
392 /*
393 * glDepthFunc(GL_GREATER) and glDepthMask(GL_TRUE).
394 */
395 GLuint gl_depth_test_span_greater( GLcontext* ctx,
396 GLuint n, GLint x, GLint y,
397 const GLdepth z[],
398 GLubyte mask[] )
399 {
400 GLdepth *zptr = Z_ADDRESS( ctx, x, y );
401 GLuint i;
402 GLuint passed = 0;
403
404 for (i=0; i<n; i++) {
405 if (mask[i]) {
406 if (z[i] > zptr[i]) {
407 /* pass */
408 zptr[i] = z[i];
409 passed++;
410 }
411 else {
412 /* fail */
413 mask[i] = 0;
414 }
415 }
416 }
417 return passed;
418 }
419
420
421
422 /*
423 * Depth test an array of randomly positioned fragments.
424 */
425
426
427 #define ZADDR_SETUP GLdepth *depthbuffer = ctx->Buffer->Depth; \
428 GLint width = ctx->Buffer->Width;
429
430 #define ZADDR( X, Y ) (depthbuffer + (Y) * width + (X) )
431
432
433
434 /*
435 * glDepthFunc( any ) and glDepthMask( GL_TRUE or GL_FALSE ).
436 */
437 void gl_depth_test_pixels_generic( GLcontext* ctx,
438 GLuint n, const GLint x[], const GLint y[],
439 const GLdepth z[], GLubyte mask[] )
440 {
441 register GLdepth *zptr;
442 register GLuint i;
443
444 /* switch cases ordered from most frequent to less frequent */
445 switch (ctx->Depth.Func) {
446 case GL_LESS:
447 if (ctx->Depth.Mask) {
448 /* Update Z buffer */
449 for (i=0; i<n; i++) {
450 if (mask[i]) {
451 zptr = Z_ADDRESS(ctx,x[i],y[i]);
452 if (z[i] < *zptr) {
453 /* pass */
454 *zptr = z[i];
455 }
456 else {
457 /* fail */
458 mask[i] = 0;
459 }
460 }
461 }
462 }
463 else {
464 /* Don't update Z buffer */
465 for (i=0; i<n; i++) {
466 if (mask[i]) {
467 zptr = Z_ADDRESS(ctx,x[i],y[i]);
468 if (z[i] < *zptr) {
469 /* pass */
470 }
471 else {
472 /* fail */
473 mask[i] = 0;
474 }
475 }
476 }
477 }
478 break;
479 case GL_LEQUAL:
480 if (ctx->Depth.Mask) {
481 /* Update Z buffer */
482 for (i=0; i<n; i++) {
483 if (mask[i]) {
484 zptr = Z_ADDRESS(ctx,x[i],y[i]);
485 if (z[i] <= *zptr) {
486 /* pass */
487 *zptr = z[i];
488 }
489 else {
490 /* fail */
491 mask[i] = 0;
492 }
493 }
494 }
495 }
496 else {
497 /* Don't update Z buffer */
498 for (i=0; i<n; i++) {
499 if (mask[i]) {
500 zptr = Z_ADDRESS(ctx,x[i],y[i]);
501 if (z[i] <= *zptr) {
502 /* pass */
503 }
504 else {
505 /* fail */
506 mask[i] = 0;
507 }
508 }
509 }
510 }
511 break;
512 case GL_GEQUAL:
513 if (ctx->Depth.Mask) {
514 /* Update Z buffer */
515 for (i=0; i<n; i++) {
516 if (mask[i]) {
517 zptr = Z_ADDRESS(ctx,x[i],y[i]);
518 if (z[i] >= *zptr) {
519 /* pass */
520 *zptr = z[i];
521 }
522 else {
523 /* fail */
524 mask[i] = 0;
525 }
526 }
527 }
528 }
529 else {
530 /* Don't update Z buffer */
531 for (i=0; i<n; i++) {
532 if (mask[i]) {
533 zptr = Z_ADDRESS(ctx,x[i],y[i]);
534 if (z[i] >= *zptr) {
535 /* pass */
536 }
537 else {
538 /* fail */
539 mask[i] = 0;
540 }
541 }
542 }
543 }
544 break;
545 case GL_GREATER:
546 if (ctx->Depth.Mask) {
547 /* Update Z buffer */
548 for (i=0; i<n; i++) {
549 if (mask[i]) {
550 zptr = Z_ADDRESS(ctx,x[i],y[i]);
551 if (z[i] > *zptr) {
552 /* pass */
553 *zptr = z[i];
554 }
555 else {
556 /* fail */
557 mask[i] = 0;
558 }
559 }
560 }
561 }
562 else {
563 /* Don't update Z buffer */
564 for (i=0; i<n; i++) {
565 if (mask[i]) {
566 zptr = Z_ADDRESS(ctx,x[i],y[i]);
567 if (z[i] > *zptr) {
568 /* pass */
569 }
570 else {
571 /* fail */
572 mask[i] = 0;
573 }
574 }
575 }
576 }
577 break;
578 case GL_NOTEQUAL:
579 if (ctx->Depth.Mask) {
580 /* Update Z buffer */
581 for (i=0; i<n; i++) {
582 if (mask[i]) {
583 zptr = Z_ADDRESS(ctx,x[i],y[i]);
584 if (z[i] != *zptr) {
585 /* pass */
586 *zptr = z[i];
587 }
588 else {
589 /* fail */
590 mask[i] = 0;
591 }
592 }
593 }
594 }
595 else {
596 /* Don't update Z buffer */
597 for (i=0; i<n; i++) {
598 if (mask[i]) {
599 zptr = Z_ADDRESS(ctx,x[i],y[i]);
600 if (z[i] != *zptr) {
601 /* pass */
602 }
603 else {
604 /* fail */
605 mask[i] = 0;
606 }
607 }
608 }
609 }
610 break;
611 case GL_EQUAL:
612 if (ctx->Depth.Mask) {
613 /* Update Z buffer */
614 for (i=0; i<n; i++) {
615 if (mask[i]) {
616 zptr = Z_ADDRESS(ctx,x[i],y[i]);
617 if (z[i] == *zptr) {
618 /* pass */
619 *zptr = z[i];
620 }
621 else {
622 /* fail */
623 mask[i] = 0;
624 }
625 }
626 }
627 }
628 else {
629 /* Don't update Z buffer */
630 for (i=0; i<n; i++) {
631 if (mask[i]) {
632 zptr = Z_ADDRESS(ctx,x[i],y[i]);
633 if (z[i] == *zptr) {
634 /* pass */
635 }
636 else {
637 /* fail */
638 mask[i] = 0;
639 }
640 }
641 }
642 }
643 break;
644 case GL_ALWAYS:
645 if (ctx->Depth.Mask) {
646 /* Update Z buffer */
647 for (i=0; i<n; i++) {
648 if (mask[i]) {
649 zptr = Z_ADDRESS(ctx,x[i],y[i]);
650 *zptr = z[i];
651 }
652 }
653 }
654 else {
655 /* Don't update Z buffer or mask */
656 }
657 break;
658 case GL_NEVER:
659 /* depth test never passes */
660 for (i=0;i<n;i++) {
661 mask[i] = 0;
662 }
663 break;
664 default:
665 gl_problem(ctx, "Bad depth func in gl_depth_test_pixels_generic");
666 } /*switch*/
667 }
668
669
670
671 /*
672 * glDepthFunc( GL_LESS ) and glDepthMask( GL_TRUE ).
673 */
674 void gl_depth_test_pixels_less( GLcontext* ctx,
675 GLuint n, const GLint x[], const GLint y[],
676 const GLdepth z[], GLubyte mask[] )
677 {
678 GLdepth *zptr;
679 GLuint i;
680
681 for (i=0; i<n; i++) {
682 if (mask[i]) {
683 zptr = Z_ADDRESS(ctx,x[i],y[i]);
684 if (z[i] < *zptr) {
685 /* pass */
686 *zptr = z[i];
687 }
688 else {
689 /* fail */
690 mask[i] = 0;
691 }
692 }
693 }
694 }
695
696
697 /*
698 * glDepthFunc( GL_GREATER ) and glDepthMask( GL_TRUE ).
699 */
700 void gl_depth_test_pixels_greater( GLcontext* ctx,
701 GLuint n, const GLint x[], const GLint y[],
702 const GLdepth z[], GLubyte mask[] )
703 {
704 GLdepth *zptr;
705 GLuint i;
706
707 for (i=0; i<n; i++) {
708 if (mask[i]) {
709 zptr = Z_ADDRESS(ctx,x[i],y[i]);
710 if (z[i] > *zptr) {
711 /* pass */
712 *zptr = z[i];
713 }
714 else {
715 /* fail */
716 mask[i] = 0;
717 }
718 }
719 }
720 }
721
722
723
724
725 /**********************************************************************/
726 /***** Read Depth Buffer *****/
727 /**********************************************************************/
728
729
730 /*
731 * Return a span of depth values from the depth buffer as floats in [0,1].
732 * This function is only called through Driver.read_depth_span_float()
733 * Input: n - how many pixels
734 * x,y - location of first pixel
735 * Output: depth - the array of depth values
736 */
737 void gl_read_depth_span_float( GLcontext* ctx,
738 GLuint n, GLint x, GLint y, GLfloat depth[] )
739 {
740 GLdepth *zptr;
741 GLfloat scale;
742 GLuint i;
743
744 scale = 1.0F / DEPTH_SCALE;
745
746 if (ctx->Buffer->Depth) {
747 zptr = Z_ADDRESS( ctx, x, y );
748 for (i=0;i<n;i++) {
749 depth[i] = (GLfloat) zptr[i] * scale;
750 }
751 }
752 else {
753 for (i=0;i<n;i++) {
754 depth[i] = 0.0F;
755 }
756 }
757 }
758
759
760 /*
761 * Return a span of depth values from the depth buffer as integers in
762 * [0,MAX_DEPTH].
763 * This function is only called through Driver.read_depth_span_int()
764 * Input: n - how many pixels
765 * x,y - location of first pixel
766 * Output: depth - the array of depth values
767 */
768 void gl_read_depth_span_int( GLcontext* ctx,
769 GLuint n, GLint x, GLint y, GLdepth depth[] )
770 {
771 if (ctx->Buffer->Depth) {
772 GLdepth *zptr = Z_ADDRESS( ctx, x, y );
773 MEMCPY( depth, zptr, n * sizeof(GLdepth) );
774 }
775 else {
776 GLuint i;
777 for (i=0;i<n;i++) {
778 depth[i] = 0;
779 }
780 }
781 }
782
783
784
785 /**********************************************************************/
786 /***** Allocate and Clear Depth Buffer *****/
787 /**********************************************************************/
788
789
790
791 /*
792 * Allocate a new depth buffer. If there's already a depth buffer allocated
793 * it will be free()'d. The new depth buffer will be uniniitalized.
794 * This function is only called through Driver.alloc_depth_buffer.
795 */
796 void gl_alloc_depth_buffer( GLcontext* ctx )
797 {
798 /* deallocate current depth buffer if present */
799 if (ctx->Buffer->Depth) {
800 free(ctx->Buffer->Depth);
801 ctx->Buffer->Depth = NULL;
802 }
803
804 /* allocate new depth buffer, but don't initialize it */
805 ctx->Buffer->Depth = (GLdepth *) malloc( ctx->Buffer->Width
806 * ctx->Buffer->Height
807 * sizeof(GLdepth) );
808 if (!ctx->Buffer->Depth) {
809 /* out of memory */
810 ctx->Depth.Test = GL_FALSE;
811 gl_error( ctx, GL_OUT_OF_MEMORY, "Couldn't allocate depth buffer" );
812 }
813 }
814
815
816
817
818 /*
819 * Clear the depth buffer. If the depth buffer doesn't exist yet we'll
820 * allocate it now.
821 * This function is only called through Driver.clear_depth_buffer.
822 */
823 void gl_clear_depth_buffer( GLcontext* ctx )
824 {
825 GLdepth clear_value = (GLdepth) (ctx->Depth.Clear * DEPTH_SCALE);
826
827 if (ctx->Visual->DepthBits==0 || !ctx->Buffer->Depth || !ctx->Depth.Mask) {
828 /* no depth buffer, or writing to it is disabled */
829 return;
830 }
831
832 /* The loops in this function have been written so the IRIX 5.3
833 * C compiler can unroll them. Hopefully other compilers can too!
834 */
835
836 if (ctx->Scissor.Enabled) {
837 /* only clear scissor region */
838 GLint y;
839 for (y=ctx->Buffer->Ymin; y<=ctx->Buffer->Ymax; y++) {
840 GLdepth *d = Z_ADDRESS( ctx, ctx->Buffer->Xmin, y );
841 GLint n = ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1;
842 do {
843 *d++ = clear_value;
844 n--;
845 } while (n);
846 }
847 }
848 else {
849 /* clear whole buffer */
850 if (sizeof(GLdepth)==2 && (clear_value&0xff)==(clear_value>>8)) {
851 /* lower and upper bytes of clear_value are same, use MEMSET */
852 MEMSET( ctx->Buffer->Depth, clear_value&0xff,
853 2*ctx->Buffer->Width*ctx->Buffer->Height);
854 }
855 else {
856 GLdepth *d = ctx->Buffer->Depth;
857 GLint n = ctx->Buffer->Width * ctx->Buffer->Height;
858 while (n>=16) {
859 d[0] = clear_value; d[1] = clear_value;
860 d[2] = clear_value; d[3] = clear_value;
861 d[4] = clear_value; d[5] = clear_value;
862 d[6] = clear_value; d[7] = clear_value;
863 d[8] = clear_value; d[9] = clear_value;
864 d[10] = clear_value; d[11] = clear_value;
865 d[12] = clear_value; d[13] = clear_value;
866 d[14] = clear_value; d[15] = clear_value;
867 d += 16;
868 n -= 16;
869 }
870 while (n>0) {
871 *d++ = clear_value;
872 n--;
873 }
874 }
875 }
876 }
877
878
879