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