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