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