added missing \'s
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /* $Id: s_copypix.c,v 1.21 2001/06/26 21:15:36 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 */
56 static GLboolean
57 regions_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 */
96 static void
97 copy_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 */
310 static void
311 copy_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
582 static 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 */
710 static 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 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
840 static 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
925 void
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 }