s_copypix.c revision 3622f4f27fe51edff0717e4a42623f62e2936e90
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include "glheader.h"
27#include "context.h"
28#include "colormac.h"
29#include "convolve.h"
30#include "histogram.h"
31#include "image.h"
32#include "macros.h"
33#include "imports.h"
34#include "pixel.h"
35
36#include "s_context.h"
37#include "s_depth.h"
38#include "s_pixeltex.h"
39#include "s_span.h"
40#include "s_stencil.h"
41#include "s_texture.h"
42#include "s_zoom.h"
43
44
45
46/*
47 * Determine if there's overlap in an image copy.
48 * This test also compensates for the fact that copies are done from
49 * bottom to top and overlaps can sometimes be handled correctly
50 * without making a temporary image copy.
51 */
52static GLboolean
53regions_overlap(GLint srcx, GLint srcy,
54                GLint dstx, GLint dsty,
55                GLint width, GLint height,
56                GLfloat zoomX, GLfloat zoomY)
57{
58   if (zoomX == 1.0 && zoomY == 1.0) {
59      /* no zoom */
60      if (srcx >= dstx + width || (srcx + width <= dstx)) {
61         return GL_FALSE;
62      }
63      else if (srcy < dsty) { /* this is OK */
64         return GL_FALSE;
65      }
66      else if (srcy > dsty + height) {
67         return GL_FALSE;
68      }
69      else {
70         return GL_TRUE;
71      }
72   }
73   else {
74      /* add one pixel of slop when zooming, just to be safe */
75      if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
76         return GL_FALSE;
77      }
78      else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
79         return GL_FALSE;
80      }
81      else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
82         return GL_FALSE;
83      }
84      else {
85         return GL_TRUE;
86      }
87   }
88}
89
90
91/**
92 * Convert GLfloat[n][4] colors to GLchan[n][4].
93 * XXX maybe move into image.c
94 */
95static void
96float_span_to_chan(GLuint n, CONST GLfloat in[][4], GLchan out[][4])
97{
98   GLuint i;
99   for (i = 0; i < n; i++) {
100      UNCLAMPED_FLOAT_TO_CHAN(out[i][RCOMP], in[i][RCOMP]);
101      UNCLAMPED_FLOAT_TO_CHAN(out[i][GCOMP], in[i][GCOMP]);
102      UNCLAMPED_FLOAT_TO_CHAN(out[i][BCOMP], in[i][BCOMP]);
103      UNCLAMPED_FLOAT_TO_CHAN(out[i][ACOMP], in[i][ACOMP]);
104   }
105}
106
107
108/**
109 * Convert GLchan[n][4] colors to GLfloat[n][4].
110 * XXX maybe move into image.c
111 */
112static void
113chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4])
114{
115   GLuint i;
116   for (i = 0; i < n; i++) {
117      out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]);
118      out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]);
119      out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]);
120      out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]);
121   }
122}
123
124
125
126/*
127 * RGBA copypixels with convolution.
128 */
129static void
130copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
131                      GLint width, GLint height, GLint destx, GLint desty)
132{
133   struct gl_renderbuffer *drawRb = NULL;
134   GLboolean quick_draw;
135   GLint row;
136   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
137   const GLuint transferOps = ctx->_ImageTransferState;
138   GLfloat *dest, *tmpImage, *convImage;
139   struct sw_span span;
140
141   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
142
143   if (ctx->Depth.Test)
144      _swrast_span_default_z(ctx, &span);
145   if (ctx->Fog.Enabled)
146      _swrast_span_default_fog(ctx, &span);
147
148
149   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
150       && !zoom
151       && destx >= 0
152       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
153      quick_draw = GL_TRUE;
154      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
155   }
156   else {
157      quick_draw = GL_FALSE;
158   }
159
160   /* allocate space for GLfloat image */
161   tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
162   if (!tmpImage) {
163      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
164      return;
165   }
166   convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
167   if (!convImage) {
168      FREE(tmpImage);
169      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
170      return;
171   }
172
173   /* read source image */
174   dest = tmpImage;
175   for (row = 0; row < height; row++) {
176      GLchan rgba[MAX_WIDTH][4];
177      /* Read GLchan and convert to GLfloat */
178      _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
179                             width, srcx, srcy + row, rgba);
180      chan_span_to_float(width, (CONST GLchan (*)[4]) rgba,
181                         (GLfloat (*)[4]) dest);
182      dest += 4 * width;
183   }
184
185   /* do the image transfer ops which preceed convolution */
186   for (row = 0; row < height; row++) {
187      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
188      _mesa_apply_rgba_transfer_ops(ctx,
189                                    transferOps & IMAGE_PRE_CONVOLUTION_BITS,
190                                    width, rgba);
191   }
192
193   /* do convolution */
194   if (ctx->Pixel.Convolution2DEnabled) {
195      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
196   }
197   else {
198      ASSERT(ctx->Pixel.Separable2DEnabled);
199      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
200   }
201   FREE(tmpImage);
202
203   /* do remaining post-convolution image transfer ops */
204   for (row = 0; row < height; row++) {
205      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
206      _mesa_apply_rgba_transfer_ops(ctx,
207                                    transferOps & IMAGE_POST_CONVOLUTION_BITS,
208                                    width, rgba);
209   }
210
211   /* write the new image */
212   for (row = 0; row < height; row++) {
213      const GLfloat *src = convImage + row * width * 4;
214      GLint dy;
215
216      /* convert floats back to chan */
217      float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba);
218
219      if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
220         span.end = width;
221         _swrast_pixel_texture(ctx, &span);
222      }
223
224      /* write row to framebuffer */
225
226      dy = desty + row;
227      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
228         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
229      }
230      else if (zoom) {
231         span.x = destx;
232         span.y = dy;
233         span.end = width;
234         _swrast_write_zoomed_rgba_span(ctx, &span,
235                                     (CONST GLchan (*)[4])span.array->rgba,
236                                     desty, 0);
237      }
238      else {
239         span.x = destx;
240         span.y = dy;
241         span.end = width;
242         _swrast_write_rgba_span(ctx, &span);
243      }
244   }
245
246   FREE(convImage);
247}
248
249
250/*
251 * RGBA copypixels
252 */
253static void
254copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
255                 GLint width, GLint height, GLint destx, GLint desty)
256{
257   struct gl_renderbuffer *drawRb;
258   GLchan *tmpImage,*p;
259   GLboolean quick_draw;
260   GLint sy, dy, stepy, j;
261   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
262   GLint overlapping;
263   const GLuint transferOps = ctx->_ImageTransferState;
264   struct sw_span span;
265
266   if (!ctx->ReadBuffer->_ColorReadBuffer) {
267      /* no readbuffer - OK */
268      return;
269   }
270
271   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
272
273   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
274      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
275      return;
276   }
277
278   /* Determine if copy should be done bottom-to-top or top-to-bottom */
279   if (srcy < desty) {
280      /* top-down  max-to-min */
281      sy = srcy + height - 1;
282      dy = desty + height - 1;
283      stepy = -1;
284   }
285   else {
286      /* bottom-up  min-to-max */
287      sy = srcy;
288      dy = desty;
289      stepy = 1;
290   }
291
292   if (ctx->DrawBuffer == ctx->ReadBuffer) {
293      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
294                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
295   }
296   else {
297      overlapping = GL_FALSE;
298   }
299
300   if (ctx->Depth.Test)
301      _swrast_span_default_z(ctx, &span);
302   if (ctx->Fog.Enabled)
303      _swrast_span_default_fog(ctx, &span);
304
305   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
306       && !zoom
307       && destx >= 0
308       && destx + width <= (GLint) ctx->DrawBuffer->Width) {
309      quick_draw = GL_TRUE;
310      drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
311   }
312   else {
313      quick_draw = GL_FALSE;
314      drawRb = NULL;
315   }
316
317   if (overlapping) {
318      GLint ssy = sy;
319      tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
320      if (!tmpImage) {
321         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
322         return;
323      }
324      /* read the source image */
325      p = tmpImage;
326      for (j = 0; j < height; j++, ssy += stepy) {
327         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
328                                 width, srcx, ssy, (GLchan (*)[4]) p );
329         p += width * 4;
330      }
331      p = tmpImage;
332   }
333   else {
334      tmpImage = NULL;  /* silence compiler warnings */
335      p = NULL;
336   }
337
338   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
339      /* Get source pixels */
340      if (overlapping) {
341         /* get from buffered image */
342         ASSERT(width < MAX_WIDTH);
343         MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4);
344         p += width * 4;
345      }
346      else {
347         /* get from framebuffer */
348         ASSERT(width < MAX_WIDTH);
349         _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
350                                 width, srcx, sy, span.array->rgba );
351      }
352
353      if (transferOps) {
354         GLfloat rgbaFloat[MAX_WIDTH][4];
355         /* convert to float, transfer, convert back to chan */
356         chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba,
357                            rgbaFloat);
358         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat);
359         float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat,
360                            span.array->rgba);
361      }
362
363      if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
364         span.end = width;
365         _swrast_pixel_texture(ctx, &span);
366      }
367
368      /* Write color span */
369      if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
370         drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
371      }
372      else if (zoom) {
373         span.x = destx;
374         span.y = dy;
375         span.end = width;
376         _swrast_write_zoomed_rgba_span(ctx, &span,
377                                     (CONST GLchan (*)[4]) span.array->rgba,
378                                     desty, 0);
379      }
380      else {
381         span.x = destx;
382         span.y = dy;
383         span.end = width;
384         _swrast_write_rgba_span(ctx, &span);
385      }
386   }
387
388   if (overlapping)
389      FREE(tmpImage);
390}
391
392
393static void
394copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
395                GLint width, GLint height,
396                GLint destx, GLint desty )
397{
398   GLuint *tmpImage,*p;
399   GLint sy, dy, stepy;
400   GLint j;
401   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
402   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
403   GLint overlapping;
404   struct sw_span span;
405
406   if (!ctx->ReadBuffer->_ColorReadBuffer) {
407      /* no readbuffer - OK */
408      return;
409   }
410
411   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
412
413   /* Determine if copy should be bottom-to-top or top-to-bottom */
414   if (srcy<desty) {
415      /* top-down  max-to-min */
416      sy = srcy + height - 1;
417      dy = desty + height - 1;
418      stepy = -1;
419   }
420   else {
421      /* bottom-up  min-to-max */
422      sy = srcy;
423      dy = desty;
424      stepy = 1;
425   }
426
427   if (ctx->DrawBuffer == ctx->ReadBuffer) {
428      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
429                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
430   }
431   else {
432      overlapping = GL_FALSE;
433   }
434
435   if (ctx->Depth.Test)
436      _swrast_span_default_z(ctx, &span);
437   if (ctx->Fog.Enabled)
438      _swrast_span_default_fog(ctx, &span);
439
440   if (overlapping) {
441      GLint ssy = sy;
442      tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
443      if (!tmpImage) {
444         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
445         return;
446      }
447      /* read the image */
448      p = tmpImage;
449      for (j = 0; j < height; j++, ssy += stepy) {
450         _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
451                                  width, srcx, ssy, p );
452         p += width;
453      }
454      p = tmpImage;
455   }
456   else {
457      tmpImage = NULL;  /* silence compiler warning */
458      p = NULL;
459   }
460
461   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
462      /* Get color indexes */
463      if (overlapping) {
464         MEMCPY(span.array->index, p, width * sizeof(GLuint));
465         p += width;
466      }
467      else {
468         _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
469                                  width, srcx, sy, span.array->index );
470      }
471
472      /* Apply shift, offset, look-up table */
473      if (shift_or_offset) {
474         _mesa_shift_and_offset_ci( ctx, width, span.array->index );
475      }
476      if (ctx->Pixel.MapColorFlag) {
477         _mesa_map_ci( ctx, width, span.array->index );
478      }
479
480      /* write color indexes */
481      span.x = destx;
482      span.y = dy;
483      span.end = width;
484      if (zoom)
485         _swrast_write_zoomed_index_span(ctx, &span, desty, 0);
486      else
487         _swrast_write_index_span(ctx, &span);
488   }
489
490   if (overlapping)
491      FREE(tmpImage);
492}
493
494
495
496/*
497 * TODO: Optimize!!!!
498 */
499static void
500copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
501                   GLint width, GLint height,
502                   GLint destx, GLint desty )
503{
504   const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
505   struct gl_renderbuffer *readRb
506      = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
507   GLfloat *p, *tmpImage;
508   GLint sy, dy, stepy;
509   GLint i, j;
510   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
511   GLint overlapping;
512   struct sw_span span;
513
514   if (!readRb) {
515      /* no readbuffer - OK */
516      return;
517   }
518
519   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
520
521   if (!ctx->Visual.depthBits) {
522      _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
523      return;
524   }
525
526   /* Determine if copy should be bottom-to-top or top-to-bottom */
527   if (srcy<desty) {
528      /* top-down  max-to-min */
529      sy = srcy + height - 1;
530      dy = desty + height - 1;
531      stepy = -1;
532   }
533   else {
534      /* bottom-up  min-to-max */
535      sy = srcy;
536      dy = desty;
537      stepy = 1;
538   }
539
540   if (ctx->DrawBuffer == ctx->ReadBuffer) {
541      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
542                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
543   }
544   else {
545      overlapping = GL_FALSE;
546   }
547
548   _swrast_span_default_color(ctx, &span);
549   if (ctx->Fog.Enabled)
550      _swrast_span_default_fog(ctx, &span);
551
552   if (overlapping) {
553      GLint ssy = sy;
554      tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
555      if (!tmpImage) {
556         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
557         return;
558      }
559      p = tmpImage;
560      for (j = 0; j < height; j++, ssy += stepy) {
561         _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
562         p += width;
563      }
564      p = tmpImage;
565   }
566   else {
567      tmpImage = NULL;  /* silence compiler warning */
568      p = NULL;
569   }
570
571   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
572      GLfloat depth[MAX_WIDTH];
573      float sum = 0;
574      /* get depth values */
575      if (overlapping) {
576         MEMCPY(depth, p, width * sizeof(GLfloat));
577         p += width;
578      }
579      else {
580         _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
581      }
582
583      /* apply scale and bias */
584      for (i = 0; i < width; i++) {
585         GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
586         sum += d;
587         span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * depthMax);
588      }
589
590      /* write depth values */
591      span.x = destx;
592      span.y = dy;
593      span.end = width;
594      if (ctx->Visual.rgbMode) {
595         if (zoom)
596            _swrast_write_zoomed_rgba_span( ctx, &span,
597                            (const GLchan (*)[4])span.array->rgba, desty, 0 );
598         else
599            _swrast_write_rgba_span(ctx, &span);
600      }
601      else {
602         if (zoom)
603            _swrast_write_zoomed_index_span( ctx, &span, desty, 0 );
604         else
605            _swrast_write_index_span(ctx, &span);
606      }
607   }
608
609   if (overlapping)
610      FREE(tmpImage);
611}
612
613
614
615static void
616copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
617                     GLint width, GLint height,
618                     GLint destx, GLint desty )
619{
620   struct gl_renderbuffer *rb
621      = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
622   GLint sy, dy, stepy;
623   GLint j;
624   GLstencil *p, *tmpImage;
625   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
626   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
627   GLint overlapping;
628
629   if (!ctx->Visual.stencilBits) {
630      _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
631      return;
632   }
633
634   if (!rb) {
635      /* no readbuffer - OK */
636      return;
637   }
638
639   /* Determine if copy should be bottom-to-top or top-to-bottom */
640   if (srcy < desty) {
641      /* top-down  max-to-min */
642      sy = srcy + height - 1;
643      dy = desty + height - 1;
644      stepy = -1;
645   }
646   else {
647      /* bottom-up  min-to-max */
648      sy = srcy;
649      dy = desty;
650      stepy = 1;
651   }
652
653   if (ctx->DrawBuffer == ctx->ReadBuffer) {
654      overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
655                                    ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
656   }
657   else {
658      overlapping = GL_FALSE;
659   }
660
661   if (overlapping) {
662      GLint ssy = sy;
663      tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
664      if (!tmpImage) {
665         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
666         return;
667      }
668      p = tmpImage;
669      for (j = 0; j < height; j++, ssy += stepy) {
670         _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
671         p += width;
672      }
673      p = tmpImage;
674   }
675   else {
676      tmpImage = NULL;  /* silence compiler warning */
677      p = NULL;
678   }
679
680   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
681      GLstencil stencil[MAX_WIDTH];
682
683      /* Get stencil values */
684      if (overlapping) {
685         MEMCPY(stencil, p, width * sizeof(GLstencil));
686         p += width;
687      }
688      else {
689         _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
690      }
691
692      /* Apply shift, offset, look-up table */
693      if (shift_or_offset) {
694         _mesa_shift_and_offset_stencil( ctx, width, stencil );
695      }
696      if (ctx->Pixel.MapStencilFlag) {
697         _mesa_map_stencil( ctx, width, stencil );
698      }
699
700      /* Write stencil values */
701      if (zoom) {
702         _swrast_write_zoomed_stencil_span( ctx, width, destx, dy,
703                                          stencil, desty, 0 );
704      }
705      else {
706         _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
707      }
708   }
709
710   if (overlapping)
711      FREE(tmpImage);
712}
713
714
715
716void
717_swrast_CopyPixels( GLcontext *ctx,
718		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
719		    GLint destx, GLint desty,
720		    GLenum type )
721{
722   SWcontext *swrast = SWRAST_CONTEXT(ctx);
723   RENDER_START(swrast,ctx);
724
725   if (swrast->NewState)
726      _swrast_validate_derived( ctx );
727
728   if (type == GL_COLOR && ctx->Visual.rgbMode) {
729      copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
730   }
731   else if (type == GL_COLOR && !ctx->Visual.rgbMode) {
732      copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
733   }
734   else if (type == GL_DEPTH) {
735      copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
736   }
737   else if (type == GL_STENCIL) {
738      copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
739   }
740   else {
741      _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
742   }
743
744   RENDER_FINISH(swrast,ctx);
745}
746