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