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