s_copypix.c revision 9927f1978da8530416f699d084dda099720e43e6
1/* $Id: s_copypix.c,v 1.27 2002/01/10 16:54:29 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.5
6 *
7 * Copyright (C) 1999-2001  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 "mem.h"
35#include "mmath.h"
36#include "pixel.h"
37
38#include "s_context.h"
39#include "s_depth.h"
40#include "s_fog.h"
41#include "s_histogram.h"
42#include "s_pixeltex.h"
43#include "s_span.h"
44#include "s_stencil.h"
45#include "s_texture.h"
46#include "s_zoom.h"
47
48
49
50/*
51 * Determine if there's overlap in an image copy.
52 * This test also compensates for the fact that copies are done from
53 * bottom to top and overlaps can sometimes be handled correctly
54 * without making a temporary image copy.
55 */
56static GLboolean
57regions_overlap(GLint srcx, GLint srcy,
58                GLint dstx, GLint dsty,
59                GLint width, GLint height,
60                GLfloat zoomX, GLfloat zoomY)
61{
62   if (zoomX == 1.0 && zoomY == 1.0) {
63      /* no zoom */
64      if (srcx >= dstx + width || (srcx + width <= dstx)) {
65         return GL_FALSE;
66      }
67      else if (srcy < dsty) { /* this is OK */
68         return GL_FALSE;
69      }
70      else {
71         return GL_TRUE;
72      }
73   }
74   else {
75      /* add one pixel of slop when zooming, just to be safe */
76      if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
77         return GL_FALSE;
78      }
79      else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
80         return GL_FALSE;
81      }
82      else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
83         return GL_FALSE;
84      }
85      else {
86         return GL_TRUE;
87      }
88   }
89}
90
91
92
93/*
94 * RGBA copypixels with convolution.
95 */
96static void
97copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
98                      GLint width, GLint height, GLint destx, GLint desty)
99{
100   SWcontext *swrast = SWRAST_CONTEXT(ctx);
101   GLdepth zspan[MAX_WIDTH];
102   GLfloat fogSpan[MAX_WIDTH];
103   GLboolean quick_draw;
104   GLint row;
105   GLboolean changeBuffer;
106   GLchan *saveReadAlpha;
107   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
108   const GLuint transferOps = ctx->_ImageTransferState;
109   GLfloat *dest, *tmpImage, *convImage;
110
111   if (ctx->Depth.Test || ctx->Fog.Enabled) {
112      /* fill in array of z values */
113      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
114      GLfloat fog;
115      GLint i;
116
117      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
118         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
119      else
120         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
121
122      for (i = 0; i < width; i++) {
123         zspan[i] = z;
124         fogSpan[i] = fog;
125      }
126   }
127
128   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
129       && !zoom
130       && destx >= 0
131       && destx + width <= ctx->DrawBuffer->Width) {
132      quick_draw = GL_TRUE;
133   }
134   else {
135      quick_draw = GL_FALSE;
136   }
137
138   /* If read and draw buffer are different we must do buffer switching */
139   saveReadAlpha = ctx->ReadBuffer->Alpha;
140   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
141               || ctx->DrawBuffer != ctx->ReadBuffer;
142
143
144   /* allocate space for GLfloat image */
145   tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
146   if (!tmpImage) {
147      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
148      return;
149   }
150   convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
151   if (!convImage) {
152      FREE(tmpImage);
153      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
154      return;
155   }
156
157   dest = tmpImage;
158
159   if (changeBuffer) {
160      (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
161                                    ctx->Pixel.DriverReadBuffer );
162      if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
163         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
164      else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
165         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
166      else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
167         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
168      else
169         ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
170   }
171
172   /* read source image */
173   dest = tmpImage;
174   for (row = 0; row < height; row++) {
175      GLchan rgba[MAX_WIDTH][4];
176      GLint i;
177      _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba);
178      /* convert GLchan to GLfloat */
179      for (i = 0; i < width; i++) {
180         *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF);
181         *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF);
182         *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF);
183         *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF);
184      }
185   }
186
187   /* read from the draw buffer again (in case of blending) */
188   if (changeBuffer) {
189      (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
190                                    ctx->Color.DriverDrawBuffer );
191      ctx->ReadBuffer->Alpha = saveReadAlpha;
192   }
193
194   /* do image transfer ops up until convolution */
195   for (row = 0; row < height; row++) {
196      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
197
198      /* scale & bias */
199      if (transferOps & IMAGE_SCALE_BIAS_BIT) {
200         _mesa_scale_and_bias_rgba(ctx, width, rgba,
201                                   ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
202                                   ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
203                                   ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
204                                   ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
205      }
206      /* color map lookup */
207      if (transferOps & IMAGE_MAP_COLOR_BIT) {
208         _mesa_map_rgba(ctx, width, rgba);
209      }
210      /* GL_COLOR_TABLE lookup */
211      if (transferOps & IMAGE_COLOR_TABLE_BIT) {
212         _mesa_lookup_rgba(&ctx->ColorTable, width, rgba);
213      }
214   }
215
216   /* do convolution */
217   if (ctx->Pixel.Convolution2DEnabled) {
218      _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
219   }
220   else {
221      ASSERT(ctx->Pixel.Separable2DEnabled);
222      _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
223   }
224   FREE(tmpImage);
225
226   /* do remaining image transfer ops */
227   for (row = 0; row < height; row++) {
228      GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
229
230      /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
231      if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
232         _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba);
233      }
234      /* color matrix */
235      if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
236         _mesa_transform_rgba(ctx, width, rgba);
237      }
238      /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
239      if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
240         _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba);
241      }
242      /* update histogram count */
243      if (transferOps & IMAGE_HISTOGRAM_BIT) {
244         _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba);
245      }
246      /* update min/max */
247      if (transferOps & IMAGE_MIN_MAX_BIT) {
248         _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba);
249      }
250   }
251
252   for (row = 0; row < height; row++) {
253      const GLfloat *src = convImage + row * width * 4;
254      GLchan rgba[MAX_WIDTH][4];
255      GLint i, dy;
256
257      /* clamp to [0,1] and convert float back to chan */
258      for (i = 0; i < width; i++) {
259         GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF);
260         GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF);
261         GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF);
262         GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF);
263         rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
264         rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
265         rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
266         rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
267      }
268
269      if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
270         GLchan primary_rgba[MAX_WIDTH][4];
271         GLuint unit;
272         DEFMARRAY(GLfloat, texcoord, MAX_WIDTH, 4);  /* mac 32k limitation */
273         CHECKARRAY(texcoord, return); /* mac 32k limitation */
274
275         /* XXX not sure how multitexture is supposed to work here */
276
277         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
278
279         for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
280            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
281                              texcoord);
282            _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL,
283                                           (CONST GLchan (*)[4]) primary_rgba,
284                                           rgba);
285         }
286         UNDEFARRAY(texcoord);  /* mac 32k limitation */
287      }
288
289      /* write row to framebuffer */
290
291      dy = desty + row;
292      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
293         (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
294				       (const GLchan (*)[4])rgba, NULL );
295      }
296      else if (zoom) {
297         _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
298				    (const GLchan (*)[4])rgba, desty);
299      }
300      else {
301         _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
302                                NULL, GL_BITMAP );
303      }
304   }
305
306   FREE(convImage);
307}
308
309
310/*
311 * RGBA copypixels
312 */
313static void
314copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
315                 GLint width, GLint height, GLint destx, GLint desty)
316{
317   SWcontext *swrast = SWRAST_CONTEXT(ctx);
318   GLdepth zspan[MAX_WIDTH];
319   GLfloat fogSpan[MAX_WIDTH];
320   GLchan rgba[MAX_WIDTH][4];
321   GLchan *tmpImage,*p;
322   GLboolean quick_draw;
323   GLint sy, dy, stepy;
324   GLint i, j;
325   GLboolean changeBuffer;
326   GLchan *saveReadAlpha;
327   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
328   GLint overlapping;
329   const GLuint transferOps = ctx->_ImageTransferState;
330
331   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
332      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
333      return;
334   }
335
336   /* Determine if copy should be done bottom-to-top or top-to-bottom */
337   if (srcy < desty) {
338      /* top-down  max-to-min */
339      sy = srcy + height - 1;
340      dy = desty + height - 1;
341      stepy = -1;
342   }
343   else {
344      /* bottom-up  min-to-max */
345      sy = srcy;
346      dy = desty;
347      stepy = 1;
348   }
349
350   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
351                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
352
353   if (ctx->Depth.Test || ctx->Fog.Enabled) {
354      /* fill in array of z values */
355      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
356      GLfloat fog;
357
358      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
359         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
360      else
361         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
362
363      for (i=0;i<width;i++) {
364         zspan[i] = z;
365         fogSpan[i] = fog;
366      }
367   }
368
369   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
370       && !zoom
371       && destx >= 0
372       && destx + width <= ctx->DrawBuffer->Width) {
373      quick_draw = GL_TRUE;
374   }
375   else {
376      quick_draw = GL_FALSE;
377   }
378
379   /* If read and draw buffer are different we must do buffer switching */
380   saveReadAlpha = ctx->ReadBuffer->Alpha;
381   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
382                  || ctx->DrawBuffer != ctx->ReadBuffer;
383
384   (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
385                                 ctx->Pixel.DriverReadBuffer );
386
387   if (overlapping) {
388      GLint ssy = sy;
389      tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
390      if (!tmpImage) {
391         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
392         return;
393      }
394      p = tmpImage;
395      if (changeBuffer) {
396         (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
397                                       ctx->Pixel.DriverReadBuffer );
398         if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
399            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
400         else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
401            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
402         else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
403            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
404         else
405            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
406      }
407      for (j = 0; j < height; j++, ssy += stepy) {
408         _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
409                            (GLchan (*)[4]) p );
410         p += (width * sizeof(GLchan) * 4);
411      }
412      p = tmpImage;
413   }
414   else {
415      tmpImage = NULL;  /* silence compiler warnings */
416      p = NULL;
417   }
418
419   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
420      /* Get source pixels */
421      if (overlapping) {
422         /* get from buffered image */
423         MEMCPY(rgba, p, width * sizeof(GLchan) * 4);
424         p += (width * sizeof(GLchan) * 4);
425      }
426      else {
427         /* get from framebuffer */
428         if (changeBuffer) {
429            (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
430                                          ctx->Pixel.DriverReadBuffer );
431            if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
432               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
433            }
434            else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
435               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
436            }
437            else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
438               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
439            }
440            else {
441               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
442            }
443         }
444         _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
445      }
446
447      if (changeBuffer) {
448         /* read from the draw buffer again (in case of blending) */
449         (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
450                                       ctx->Color.DriverDrawBuffer );
451         ctx->ReadBuffer->Alpha = saveReadAlpha;
452      }
453
454      if (transferOps) {
455         const GLfloat scale = (1.0F / CHAN_MAXF);
456         GLint k;
457         DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4);  /* mac 32k limitation */
458         CHECKARRAY(rgbaFloat, return);
459
460         /* convert chan to float */
461         for (k = 0; k < width; k++) {
462            rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale;
463            rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale;
464            rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale;
465            rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale;
466         }
467         /* scale & bias */
468         if (transferOps & IMAGE_SCALE_BIAS_BIT) {
469            _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
470                                   ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
471                                   ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
472                                   ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
473                                   ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
474         }
475         /* color map lookup */
476         if (transferOps & IMAGE_MAP_COLOR_BIT) {
477            _mesa_map_rgba(ctx, width, rgbaFloat);
478         }
479         /* GL_COLOR_TABLE lookup */
480         if (transferOps & IMAGE_COLOR_TABLE_BIT) {
481            _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
482         }
483         /* convolution */
484         if (transferOps & IMAGE_CONVOLUTION_BIT) {
485            /* XXX to do */
486         }
487         /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */
488         if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) {
489            _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
490                                      ctx->Pixel.PostConvolutionScale[RCOMP],
491                                      ctx->Pixel.PostConvolutionScale[GCOMP],
492                                      ctx->Pixel.PostConvolutionScale[BCOMP],
493                                      ctx->Pixel.PostConvolutionScale[ACOMP],
494                                      ctx->Pixel.PostConvolutionBias[RCOMP],
495                                      ctx->Pixel.PostConvolutionBias[GCOMP],
496                                      ctx->Pixel.PostConvolutionBias[BCOMP],
497                                      ctx->Pixel.PostConvolutionBias[ACOMP]);
498         }
499         /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
500         if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
501            _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
502         }
503         /* color matrix */
504         if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
505            _mesa_transform_rgba(ctx, width, rgbaFloat);
506         }
507         /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
508         if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
509            _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
510         }
511         /* update histogram count */
512         if (transferOps & IMAGE_HISTOGRAM_BIT) {
513            _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
514         }
515         /* update min/max */
516         if (transferOps & IMAGE_MIN_MAX_BIT) {
517            _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
518         }
519         /* clamp to [0,1] and convert float back to chan */
520         for (k = 0; k < width; k++) {
521            GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
522            GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
523            GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
524            GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
525            rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
526            rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
527            rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
528            rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
529         }
530         UNDEFARRAY(rgbaFloat);  /* mac 32k limitation */
531      }
532
533      if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
534         GLuint unit;
535         GLchan primary_rgba[MAX_WIDTH][4];
536         DEFMARRAY(GLfloat, texcoord, MAX_WIDTH, 4);  /* mac 32k limitation */
537         CHECKARRAY(texcoord, return); /* mac 32k limitation */
538
539         /* XXX not sure how multitexture is supposed to work here */
540         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
541
542         for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
543            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
544                              texcoord);
545            _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL,
546                                           (CONST GLchan (*)[4]) primary_rgba,
547                                           rgba);
548         }
549
550         UNDEFARRAY(texcoord);  /* mac 32k limitation */
551      }
552
553      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
554         (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
555				       (const GLchan (*)[4])rgba, NULL );
556      }
557      else if (zoom) {
558         _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
559				    (const GLchan (*)[4])rgba, desty);
560      }
561      else {
562         _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
563                                NULL, GL_BITMAP );
564      }
565   }
566
567   /* Restore pixel source to be the draw buffer (for blending, etc) */
568   (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
569                                 ctx->Color.DriverDrawBuffer );
570
571   if (overlapping)
572      FREE(tmpImage);
573}
574
575
576static void copy_ci_pixels( GLcontext *ctx,
577                            GLint srcx, GLint srcy, GLint width, GLint height,
578                            GLint destx, GLint desty )
579{
580   SWcontext *swrast = SWRAST_CONTEXT(ctx);
581   GLdepth zspan[MAX_WIDTH];
582   GLfloat fogSpan[MAX_WIDTH];
583   GLuint *tmpImage,*p;
584   GLint sy, dy, stepy;
585   GLint i, j;
586   GLboolean changeBuffer;
587   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
588   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
589   GLint overlapping;
590
591   /* Determine if copy should be bottom-to-top or top-to-bottom */
592   if (srcy<desty) {
593      /* top-down  max-to-min */
594      sy = srcy + height - 1;
595      dy = desty + height - 1;
596      stepy = -1;
597   }
598   else {
599      /* bottom-up  min-to-max */
600      sy = srcy;
601      dy = desty;
602      stepy = 1;
603   }
604
605   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
606                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
607
608   if (ctx->Depth.Test || ctx->Fog.Enabled) {
609      /* fill in array of z values */
610      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
611      GLfloat fog;
612
613      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
614         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
615      else
616         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
617
618      for (i=0;i<width;i++) {
619         zspan[i] = z;
620         fogSpan[i] = fog;
621      }
622   }
623
624   /* If read and draw buffer are different we must do buffer switching */
625   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
626               || ctx->DrawBuffer != ctx->ReadBuffer;
627
628   (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
629                                 ctx->Pixel.DriverReadBuffer );
630
631   if (overlapping) {
632      GLint ssy = sy;
633      tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
634      if (!tmpImage) {
635         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
636         return;
637      }
638      p = tmpImage;
639      if (changeBuffer) {
640         (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
641                                       ctx->Pixel.DriverReadBuffer );
642      }
643      for (j = 0; j < height; j++, ssy += stepy) {
644         _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
645         p += width;
646      }
647      p = tmpImage;
648   }
649   else {
650      tmpImage = NULL;  /* silence compiler warning */
651      p = NULL;
652   }
653
654   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
655      GLuint indexes[MAX_WIDTH];
656      if (overlapping) {
657         MEMCPY(indexes, p, width * sizeof(GLuint));
658         p += width;
659      }
660      else {
661         if (changeBuffer) {
662            (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
663                                          ctx->Pixel.DriverReadBuffer );
664         }
665         _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
666      }
667
668      if (changeBuffer) {
669         /* set read buffer back to draw buffer (in case of logicops) */
670         (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
671                                       ctx->Color.DriverDrawBuffer );
672      }
673
674      if (shift_or_offset) {
675         _mesa_shift_and_offset_ci( ctx, width, indexes );
676      }
677      if (ctx->Pixel.MapColorFlag) {
678         _mesa_map_ci( ctx, width, indexes );
679      }
680
681      if (zoom) {
682         _mesa_write_zoomed_index_span(ctx, width, destx, dy, zspan, fogSpan,
683                                       indexes, desty );
684      }
685      else {
686         _old_write_index_span(ctx, width, destx, dy, zspan, fogSpan, indexes,
687                                NULL, GL_BITMAP);
688      }
689   }
690
691   /* Restore pixel source to be the draw buffer (for blending, etc) */
692   (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
693                                 ctx->Color.DriverDrawBuffer );
694
695   if (overlapping)
696      FREE(tmpImage);
697}
698
699
700
701/*
702 * TODO: Optimize!!!!
703 */
704static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
705                               GLint width, GLint height,
706                               GLint destx, GLint desty )
707{
708   GLfloat depth[MAX_WIDTH];
709   GLdepth zspan[MAX_WIDTH];
710   GLfloat fogSpan[MAX_WIDTH];
711   GLfloat *p, *tmpImage;
712   GLuint indexes[MAX_WIDTH];
713   GLint sy, dy, stepy;
714   GLint i, j;
715   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
716   GLint overlapping;
717   DEFMARRAY(GLchan, rgba, MAX_WIDTH, 4);  /* mac 32k limitation */
718   CHECKARRAY(rgba, return);  /* mac 32k limitation */
719
720   if (!ctx->Visual.depthBits) {
721      _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
722      UNDEFARRAY(rgba);  /* mac 32k limitation */
723      return;
724   }
725
726   /* Determine if copy should be bottom-to-top or top-to-bottom */
727   if (srcy<desty) {
728      /* top-down  max-to-min */
729      sy = srcy + height - 1;
730      dy = desty + height - 1;
731      stepy = -1;
732   }
733   else {
734      /* bottom-up  min-to-max */
735      sy = srcy;
736      dy = desty;
737      stepy = 1;
738   }
739
740   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
741                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
742
743   /* setup colors or indexes */
744   if (ctx->Visual.rgbMode) {
745      GLchan r, g, b, a;
746      UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]);
747      UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]);
748      UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]);
749      UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]);
750      for (i = 0; i < width; i++) {
751         rgba[i][RCOMP] = r;
752         rgba[i][GCOMP] = g;
753         rgba[i][BCOMP] = b;
754         rgba[i][ACOMP] = a;
755      }
756   }
757   else {
758      for (i = 0; i < width; i++) {
759         indexes[i] = ctx->Current.Index;
760      }
761   }
762
763   if (ctx->Fog.Enabled) {
764      GLfloat fog;
765
766      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
767         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
768      else
769         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
770
771      for (i = 0; i < width; i++) {
772         fogSpan[i] = fog;
773      }
774   }
775
776   if (overlapping) {
777      GLint ssy = sy;
778      tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
779      if (!tmpImage) {
780         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
781         UNDEFARRAY(rgba);  /* mac 32k limitation */
782         return;
783      }
784      p = tmpImage;
785      for (j = 0; j < height; j++, ssy += stepy) {
786         _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
787         p += width;
788      }
789      p = tmpImage;
790   }
791   else {
792      tmpImage = NULL;  /* silence compiler warning */
793      p = NULL;
794   }
795
796   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
797      if (overlapping) {
798         MEMCPY(depth, p, width * sizeof(GLfloat));
799         p += width;
800      }
801      else {
802         _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
803      }
804
805      for (i = 0; i < width; i++) {
806         GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
807         zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax);
808      }
809
810      if (ctx->Visual.rgbMode) {
811         if (zoom) {
812            _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan,
813                                   fogSpan, (const GLchan (*)[4])rgba, desty );
814         }
815         else {
816            _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
817                                   (GLchan (*)[4])rgba, NULL, GL_BITMAP);
818         }
819      }
820      else {
821         if (zoom) {
822            _mesa_write_zoomed_index_span( ctx, width, destx, dy,
823                                           zspan, fogSpan, indexes, desty );
824         }
825         else {
826            _old_write_index_span( ctx, width, destx, dy,
827                                    zspan, fogSpan, indexes, NULL, GL_BITMAP );
828         }
829      }
830   }
831
832   UNDEFARRAY(rgba);  /* mac 32k limitation */
833
834   if (overlapping)
835      FREE(tmpImage);
836}
837
838
839
840static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
841                                 GLint width, GLint height,
842                                 GLint destx, GLint desty )
843{
844   GLint sy, dy, stepy;
845   GLint j;
846   GLstencil *p, *tmpImage;
847   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
848   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
849   GLint overlapping;
850
851   if (!ctx->Visual.stencilBits) {
852      _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
853      return;
854   }
855
856   /* Determine if copy should be bottom-to-top or top-to-bottom */
857   if (srcy < desty) {
858      /* top-down  max-to-min */
859      sy = srcy + height - 1;
860      dy = desty + height - 1;
861      stepy = -1;
862   }
863   else {
864      /* bottom-up  min-to-max */
865      sy = srcy;
866      dy = desty;
867      stepy = 1;
868   }
869
870   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
871                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
872
873   if (overlapping) {
874      GLint ssy = sy;
875      tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
876      if (!tmpImage) {
877         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
878         return;
879      }
880      p = tmpImage;
881      for (j = 0; j < height; j++, ssy += stepy) {
882         _mesa_read_stencil_span( ctx, width, srcx, ssy, p );
883         p += width;
884      }
885      p = tmpImage;
886   }
887   else {
888      tmpImage = NULL;  /* silence compiler warning */
889      p = NULL;
890   }
891
892   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
893      GLstencil stencil[MAX_WIDTH];
894
895      if (overlapping) {
896         MEMCPY(stencil, p, width * sizeof(GLstencil));
897         p += width;
898      }
899      else {
900         _mesa_read_stencil_span( ctx, width, srcx, sy, stencil );
901      }
902
903      if (shift_or_offset) {
904         _mesa_shift_and_offset_stencil( ctx, width, stencil );
905      }
906      if (ctx->Pixel.MapStencilFlag) {
907         _mesa_map_stencil( ctx, width, stencil );
908      }
909
910      if (zoom) {
911         _mesa_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
912      }
913      else {
914         _mesa_write_stencil_span( ctx, width, destx, dy, stencil );
915      }
916   }
917
918   if (overlapping)
919      FREE(tmpImage);
920}
921
922
923
924
925void
926_swrast_CopyPixels( GLcontext *ctx,
927		    GLint srcx, GLint srcy, GLsizei width, GLsizei height,
928		    GLint destx, GLint desty,
929		    GLenum type )
930{
931   SWcontext *swrast = SWRAST_CONTEXT(ctx);
932   RENDER_START(swrast,ctx);
933
934   if (swrast->NewState)
935      _swrast_validate_derived( ctx );
936
937   if (type == GL_COLOR && ctx->Visual.rgbMode) {
938      copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
939   }
940   else if (type == GL_COLOR && !ctx->Visual.rgbMode) {
941      copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
942   }
943   else if (type == GL_DEPTH) {
944      copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
945   }
946   else if (type == GL_STENCIL) {
947      copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
948   }
949   else {
950      _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
951   }
952
953   RENDER_FINISH(swrast,ctx);
954}
955