s_copypix.c revision f431a3fb4dc1bf860203d79e54657e3a62bc50df
1/* $Id: s_copypix.c,v 1.23 2001/07/13 20:07:37 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         GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
271         GLchan primary_rgba[MAX_WIDTH][4];
272         GLuint unit;
273         /* XXX not sure how multitexture is supposed to work here */
274
275         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
276
277         for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
278            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
279                              s, t, r, q);
280            _swrast_texture_fragments(ctx, unit, width, s, t, r, NULL,
281                                      (CONST GLchan (*)[4]) primary_rgba,
282                                      rgba);
283         }
284      }
285
286      /* write row to framebuffer */
287
288      dy = desty + row;
289      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
290         (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
291				       (const GLchan (*)[4])rgba, NULL );
292      }
293      else if (zoom) {
294         _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
295				    (const GLchan (*)[4])rgba, desty);
296      }
297      else {
298         _mesa_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
299                                NULL, GL_BITMAP );
300      }
301   }
302
303   FREE(convImage);
304}
305
306
307/*
308 * RGBA copypixels
309 */
310static void
311copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
312                 GLint width, GLint height, GLint destx, GLint desty)
313{
314   SWcontext *swrast = SWRAST_CONTEXT(ctx);
315   GLdepth zspan[MAX_WIDTH];
316   GLfloat fogSpan[MAX_WIDTH];
317   GLchan rgba[MAX_WIDTH][4];
318   GLchan *tmpImage,*p;
319   GLboolean quick_draw;
320   GLint sy, dy, stepy;
321   GLint i, j;
322   GLboolean changeBuffer;
323   GLchan *saveReadAlpha;
324   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
325   GLint overlapping;
326   const GLuint transferOps = ctx->_ImageTransferState;
327
328   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
329      copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
330      return;
331   }
332
333   /* Determine if copy should be done bottom-to-top or top-to-bottom */
334   if (srcy < desty) {
335      /* top-down  max-to-min */
336      sy = srcy + height - 1;
337      dy = desty + height - 1;
338      stepy = -1;
339   }
340   else {
341      /* bottom-up  min-to-max */
342      sy = srcy;
343      dy = desty;
344      stepy = 1;
345   }
346
347   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
348                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
349
350   if (ctx->Depth.Test || ctx->Fog.Enabled) {
351      /* fill in array of z values */
352      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
353      GLfloat fog;
354
355      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
356         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
357      else
358         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
359
360      for (i=0;i<width;i++) {
361         zspan[i] = z;
362         fogSpan[i] = fog;
363      }
364   }
365
366   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
367       && !zoom
368       && destx >= 0
369       && destx + width <= ctx->DrawBuffer->Width) {
370      quick_draw = GL_TRUE;
371   }
372   else {
373      quick_draw = GL_FALSE;
374   }
375
376   /* If read and draw buffer are different we must do buffer switching */
377   saveReadAlpha = ctx->ReadBuffer->Alpha;
378   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
379                  || ctx->DrawBuffer != ctx->ReadBuffer;
380
381   (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
382                                 ctx->Pixel.DriverReadBuffer );
383
384   if (overlapping) {
385      GLint ssy = sy;
386      tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
387      if (!tmpImage) {
388         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
389         return;
390      }
391      p = tmpImage;
392      if (changeBuffer) {
393         (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
394                                       ctx->Pixel.DriverReadBuffer );
395         if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
396            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
397         else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
398            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
399         else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
400            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
401         else
402            ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
403      }
404      for (j = 0; j < height; j++, ssy += stepy) {
405         _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
406                            (GLchan (*)[4]) p );
407         p += (width * sizeof(GLchan) * 4);
408      }
409      p = tmpImage;
410   }
411   else {
412      tmpImage = NULL;  /* silence compiler warnings */
413      p = NULL;
414   }
415
416   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
417      /* Get source pixels */
418      if (overlapping) {
419         /* get from buffered image */
420         MEMCPY(rgba, p, width * sizeof(GLchan) * 4);
421         p += (width * sizeof(GLchan) * 4);
422      }
423      else {
424         /* get from framebuffer */
425         if (changeBuffer) {
426            (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
427                                          ctx->Pixel.DriverReadBuffer );
428            if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
429               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
430            }
431            else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
432               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
433            }
434            else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
435               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
436            }
437            else {
438               ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
439            }
440         }
441         _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
442      }
443
444      if (changeBuffer) {
445         /* read from the draw buffer again (in case of blending) */
446         (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
447                                       ctx->Color.DriverDrawBuffer );
448         ctx->ReadBuffer->Alpha = saveReadAlpha;
449      }
450
451      if (transferOps) {
452         const GLfloat scale = (1.0F / CHAN_MAXF);
453         GLint k;
454         DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4);  /* mac 32k limitation */
455         CHECKARRAY(rgbaFloat, return);
456
457         /* convert chan to float */
458         for (k = 0; k < width; k++) {
459            rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale;
460            rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale;
461            rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale;
462            rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale;
463         }
464         /* scale & bias */
465         if (transferOps & IMAGE_SCALE_BIAS_BIT) {
466            _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
467                                   ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
468                                   ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
469                                   ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
470                                   ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
471         }
472         /* color map lookup */
473         if (transferOps & IMAGE_MAP_COLOR_BIT) {
474            _mesa_map_rgba(ctx, width, rgbaFloat);
475         }
476         /* GL_COLOR_TABLE lookup */
477         if (transferOps & IMAGE_COLOR_TABLE_BIT) {
478            _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
479         }
480         /* convolution */
481         if (transferOps & IMAGE_CONVOLUTION_BIT) {
482            /* XXX to do */
483         }
484         /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */
485         if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) {
486            _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
487                                      ctx->Pixel.PostConvolutionScale[RCOMP],
488                                      ctx->Pixel.PostConvolutionScale[GCOMP],
489                                      ctx->Pixel.PostConvolutionScale[BCOMP],
490                                      ctx->Pixel.PostConvolutionScale[ACOMP],
491                                      ctx->Pixel.PostConvolutionBias[RCOMP],
492                                      ctx->Pixel.PostConvolutionBias[GCOMP],
493                                      ctx->Pixel.PostConvolutionBias[BCOMP],
494                                      ctx->Pixel.PostConvolutionBias[ACOMP]);
495         }
496         /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
497         if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
498            _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
499         }
500         /* color matrix */
501         if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
502            _mesa_transform_rgba(ctx, width, rgbaFloat);
503         }
504         /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
505         if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
506            _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
507         }
508         /* update histogram count */
509         if (transferOps & IMAGE_HISTOGRAM_BIT) {
510            _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
511         }
512         /* update min/max */
513         if (transferOps & IMAGE_MIN_MAX_BIT) {
514            _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
515         }
516         /* clamp to [0,1] and convert float back to chan */
517         for (k = 0; k < width; k++) {
518            GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
519            GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
520            GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
521            GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
522            rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
523            rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
524            rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
525            rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
526         }
527         UNDEFARRAY(rgbaFloat);  /* mac 32k limitation */
528      }
529
530      if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
531         GLuint unit;
532         GLchan primary_rgba[MAX_WIDTH][4];
533         DEFARRAY(GLfloat, s, MAX_WIDTH);  /* mac 32k limitation */
534         DEFARRAY(GLfloat, t, MAX_WIDTH);  /* mac 32k limitation */
535         DEFARRAY(GLfloat, r, MAX_WIDTH);  /* mac 32k limitation */
536         DEFARRAY(GLfloat, q, MAX_WIDTH);  /* mac 32k limitation */
537         CHECKARRAY(s, return); /* mac 32k limitation */
538         CHECKARRAY(t, return);
539         CHECKARRAY(r, return);
540         CHECKARRAY(q, return);
541
542         /* XXX not sure how multitexture is supposed to work here */
543         MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
544
545         for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
546            _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
547                              s, t, r, q);
548            _swrast_texture_fragments(ctx, unit, width, s, t, r, NULL,
549                                      (CONST GLchan (*)[4]) primary_rgba,
550                                      rgba);
551         }
552
553         UNDEFARRAY(s);  /* mac 32k limitation */
554         UNDEFARRAY(t);
555         UNDEFARRAY(r);
556         UNDEFARRAY(q);
557      }
558
559      if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
560         (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
561				       (const GLchan (*)[4])rgba, NULL );
562      }
563      else if (zoom) {
564         _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
565				    (const GLchan (*)[4])rgba, desty);
566      }
567      else {
568         _mesa_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
569                                NULL, GL_BITMAP );
570      }
571   }
572
573   /* Restore pixel source to be the draw buffer (for blending, etc) */
574   (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
575                                 ctx->Color.DriverDrawBuffer );
576
577   if (overlapping)
578      FREE(tmpImage);
579}
580
581
582static void copy_ci_pixels( GLcontext *ctx,
583                            GLint srcx, GLint srcy, GLint width, GLint height,
584                            GLint destx, GLint desty )
585{
586   SWcontext *swrast = SWRAST_CONTEXT(ctx);
587   GLdepth zspan[MAX_WIDTH];
588   GLfloat fogSpan[MAX_WIDTH];
589   GLuint *tmpImage,*p;
590   GLint sy, dy, stepy;
591   GLint i, j;
592   GLboolean changeBuffer;
593   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
594   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
595   GLint overlapping;
596
597   /* Determine if copy should be bottom-to-top or top-to-bottom */
598   if (srcy<desty) {
599      /* top-down  max-to-min */
600      sy = srcy + height - 1;
601      dy = desty + height - 1;
602      stepy = -1;
603   }
604   else {
605      /* bottom-up  min-to-max */
606      sy = srcy;
607      dy = desty;
608      stepy = 1;
609   }
610
611   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
612                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
613
614   if (ctx->Depth.Test || ctx->Fog.Enabled) {
615      /* fill in array of z values */
616      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
617      GLfloat fog;
618
619      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
620         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
621      else
622         fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
623
624      for (i=0;i<width;i++) {
625         zspan[i] = z;
626         fogSpan[i] = fog;
627      }
628   }
629
630   /* If read and draw buffer are different we must do buffer switching */
631   changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
632               || ctx->DrawBuffer != ctx->ReadBuffer;
633
634   (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
635                                 ctx->Pixel.DriverReadBuffer );
636
637   if (overlapping) {
638      GLint ssy = sy;
639      tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
640      if (!tmpImage) {
641         _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
642         return;
643      }
644      p = tmpImage;
645      if (changeBuffer) {
646         (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
647                                       ctx->Pixel.DriverReadBuffer );
648      }
649      for (j = 0; j < height; j++, ssy += stepy) {
650         _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
651         p += width;
652      }
653      p = tmpImage;
654   }
655   else {
656      tmpImage = NULL;  /* silence compiler warning */
657      p = NULL;
658   }
659
660   for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
661      GLuint indexes[MAX_WIDTH];
662      if (overlapping) {
663         MEMCPY(indexes, p, width * sizeof(GLuint));
664         p += width;
665      }
666      else {
667         if (changeBuffer) {
668            (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
669                                          ctx->Pixel.DriverReadBuffer );
670         }
671         _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
672      }
673
674      if (changeBuffer) {
675         /* set read buffer back to draw buffer (in case of logicops) */
676         (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
677                                       ctx->Color.DriverDrawBuffer );
678      }
679
680      if (shift_or_offset) {
681         _mesa_shift_and_offset_ci( ctx, width, indexes );
682      }
683      if (ctx->Pixel.MapColorFlag) {
684         _mesa_map_ci( ctx, width, indexes );
685      }
686
687      if (zoom) {
688         _mesa_write_zoomed_index_span(ctx, width, destx, dy, zspan, fogSpan,
689                                       indexes, desty );
690      }
691      else {
692         _mesa_write_index_span(ctx, width, destx, dy, zspan, fogSpan, indexes,
693                                NULL, GL_BITMAP);
694      }
695   }
696
697   /* Restore pixel source to be the draw buffer (for blending, etc) */
698   (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
699                                 ctx->Color.DriverDrawBuffer );
700
701   if (overlapping)
702      FREE(tmpImage);
703}
704
705
706
707/*
708 * TODO: Optimize!!!!
709 */
710static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
711                               GLint width, GLint height,
712                               GLint destx, GLint desty )
713{
714   GLfloat depth[MAX_WIDTH];
715   GLdepth zspan[MAX_WIDTH];
716   GLfloat fogSpan[MAX_WIDTH];
717   GLfloat *p, *tmpImage;
718   GLuint indexes[MAX_WIDTH];
719   GLint sy, dy, stepy;
720   GLint i, j;
721   const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
722   GLint overlapping;
723   DEFMARRAY(GLubyte, rgba, MAX_WIDTH, 4);  /* mac 32k limitation */
724   CHECKARRAY(rgba, return);  /* mac 32k limitation */
725
726   if (!ctx->Visual.depthBits) {
727      _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
728      UNDEFARRAY(rgba);  /* mac 32k limitation */
729      return;
730   }
731
732   /* Determine if copy should be bottom-to-top or top-to-bottom */
733   if (srcy<desty) {
734      /* top-down  max-to-min */
735      sy = srcy + height - 1;
736      dy = desty + height - 1;
737      stepy = -1;
738   }
739   else {
740      /* bottom-up  min-to-max */
741      sy = srcy;
742      dy = desty;
743      stepy = 1;
744   }
745
746   overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
747                                 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
748
749   /* setup colors or indexes */
750   if (ctx->Visual.rgbMode) {
751      GLuint *rgba32 = (GLuint *) rgba;
752      GLuint color = *(GLuint*)( ctx->Current.Color );
753      for (i = 0; i < width; i++) {
754         rgba32[i] = color;
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            _mesa_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            _mesa_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