2c6bd2631239d7a5db3764cb6361258c4592c863
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /* $Id: s_copypix.c,v 1.38 2002/06/15 03:03:11 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 = swrast->span;
111
112 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
113
114 if (ctx->Depth.Test)
115 _mesa_span_default_z(ctx, span);
116 if (ctx->Fog.Enabled)
117 _mesa_span_default_fog(ctx, span);
118
119
120 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
121 && !zoom
122 && destx >= 0
123 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
124 quick_draw = GL_TRUE;
125 }
126 else {
127 quick_draw = GL_FALSE;
128 }
129
130 /* If read and draw buffer are different we must do buffer switching */
131 saveReadAlpha = ctx->ReadBuffer->Alpha;
132 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
133 || ctx->DrawBuffer != ctx->ReadBuffer;
134
135
136 /* allocate space for GLfloat image */
137 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
138 if (!tmpImage) {
139 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
140 return;
141 }
142 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
143 if (!convImage) {
144 FREE(tmpImage);
145 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
146 return;
147 }
148
149 dest = tmpImage;
150
151 if (changeBuffer) {
152 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
153 ctx->Pixel.DriverReadBuffer );
154 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
155 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
156 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
157 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
158 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
159 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
160 else
161 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
162 }
163
164 /* read source image */
165 dest = tmpImage;
166 for (row = 0; row < height; row++) {
167 GLchan rgba[MAX_WIDTH][4];
168 GLint i;
169 _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba);
170 /* convert GLchan to GLfloat */
171 for (i = 0; i < width; i++) {
172 *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF);
173 *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF);
174 *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF);
175 *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF);
176 }
177 }
178
179 /* read from the draw buffer again (in case of blending) */
180 if (changeBuffer) {
181 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
182 ctx->Color.DriverDrawBuffer );
183 ctx->ReadBuffer->Alpha = saveReadAlpha;
184 }
185
186 /* do image transfer ops up until convolution */
187 for (row = 0; row < height; row++) {
188 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
189
190 /* scale & bias */
191 if (transferOps & IMAGE_SCALE_BIAS_BIT) {
192 _mesa_scale_and_bias_rgba(ctx, width, rgba,
193 ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
194 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
195 ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
196 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
197 }
198 /* color map lookup */
199 if (transferOps & IMAGE_MAP_COLOR_BIT) {
200 _mesa_map_rgba(ctx, width, rgba);
201 }
202 /* GL_COLOR_TABLE lookup */
203 if (transferOps & IMAGE_COLOR_TABLE_BIT) {
204 _mesa_lookup_rgba(&ctx->ColorTable, width, rgba);
205 }
206 }
207
208 /* do convolution */
209 if (ctx->Pixel.Convolution2DEnabled) {
210 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
211 }
212 else {
213 ASSERT(ctx->Pixel.Separable2DEnabled);
214 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
215 }
216 FREE(tmpImage);
217
218 /* do remaining image transfer ops */
219 for (row = 0; row < height; row++) {
220 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
221
222 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
223 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
224 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba);
225 }
226 /* color matrix */
227 if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
228 _mesa_transform_rgba(ctx, width, rgba);
229 }
230 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
231 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
232 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba);
233 }
234 /* update histogram count */
235 if (transferOps & IMAGE_HISTOGRAM_BIT) {
236 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba);
237 }
238 /* update min/max */
239 if (transferOps & IMAGE_MIN_MAX_BIT) {
240 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba);
241 }
242 }
243
244 for (row = 0; row < height; row++) {
245 const GLfloat *src = convImage + row * width * 4;
246 GLint i, dy;
247
248 /* clamp to [0,1] and convert float back to chan */
249 for (i = 0; i < width; i++) {
250 GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF);
251 GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF);
252 GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF);
253 GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF);
254 span->color.rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
255 span->color.rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
256 span->color.rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
257 span->color.rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
258 }
259
260 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
261 span->end = width;
262 _swrast_pixel_texture(ctx, span);
263 }
264
265 /* write row to framebuffer */
266
267 dy = desty + row;
268 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
269 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
270 (const GLchan (*)[4])span->color.rgba, NULL );
271 }
272 else if (zoom) {
273 span->x = destx;
274 span->y = dy;
275 span->end = width;
276 _mesa_write_zoomed_rgba_span(ctx, span,
277 (CONST GLchan (*)[4])span->color.rgba,
278 desty);
279 }
280 else {
281 span->x = destx;
282 span->y = dy;
283 span->end = width;
284 _mesa_write_rgba_span(ctx, span);
285 }
286 }
287
288 FREE(convImage);
289 }
290
291
292 /*
293 * RGBA copypixels
294 */
295 static void
296 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
297 GLint width, GLint height, GLint destx, GLint desty)
298 {
299 SWcontext *swrast = SWRAST_CONTEXT(ctx);
300 GLchan *tmpImage,*p;
301 GLboolean quick_draw;
302 GLint sy, dy, stepy, j;
303 GLboolean changeBuffer;
304 GLchan *saveReadAlpha;
305 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
306 GLint overlapping;
307 const GLuint transferOps = ctx->_ImageTransferState;
308 struct sw_span *span = swrast->span;
309
310 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
311
312 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
313 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
314 return;
315 }
316
317 /* Determine if copy should be done bottom-to-top or top-to-bottom */
318 if (srcy < desty) {
319 /* top-down max-to-min */
320 sy = srcy + height - 1;
321 dy = desty + height - 1;
322 stepy = -1;
323 }
324 else {
325 /* bottom-up min-to-max */
326 sy = srcy;
327 dy = desty;
328 stepy = 1;
329 }
330
331 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
332 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
333
334 if (ctx->Depth.Test)
335 _mesa_span_default_z(ctx, span);
336 if (ctx->Fog.Enabled)
337 _mesa_span_default_fog(ctx, span);
338
339 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
340 && !zoom
341 && destx >= 0
342 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
343 quick_draw = GL_TRUE;
344 }
345 else {
346 quick_draw = GL_FALSE;
347 }
348
349 /* If read and draw buffer are different we must do buffer switching */
350 saveReadAlpha = ctx->ReadBuffer->Alpha;
351 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
352 || ctx->DrawBuffer != ctx->ReadBuffer;
353
354 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
355 ctx->Pixel.DriverReadBuffer );
356
357 if (overlapping) {
358 GLint ssy = sy;
359 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
360 if (!tmpImage) {
361 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
362 return;
363 }
364 p = tmpImage;
365 if (changeBuffer) {
366 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
367 ctx->Pixel.DriverReadBuffer );
368 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
369 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
370 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
371 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
372 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
373 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
374 else
375 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
376 }
377 for (j = 0; j < height; j++, ssy += stepy) {
378 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
379 (GLchan (*)[4]) p );
380 p += width * 4;
381 }
382 p = tmpImage;
383 }
384 else {
385 tmpImage = NULL; /* silence compiler warnings */
386 p = NULL;
387 }
388
389 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
390 /* Get source pixels */
391 if (overlapping) {
392 /* get from buffered image */
393 MEMCPY(span->color.rgba, p, width * sizeof(GLchan) * 4);
394 p += width * 4;
395 }
396 else {
397 /* get from framebuffer */
398 if (changeBuffer) {
399 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
400 ctx->Pixel.DriverReadBuffer );
401 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
402 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
403 }
404 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
405 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
406 }
407 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
408 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
409 }
410 else {
411 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
412 }
413 }
414 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, span->color.rgba );
415 }
416
417 if (changeBuffer) {
418 /* read from the draw buffer again (in case of blending) */
419 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
420 ctx->Color.DriverDrawBuffer );
421 ctx->ReadBuffer->Alpha = saveReadAlpha;
422 }
423
424 if (transferOps) {
425 const GLfloat scale = (1.0F / CHAN_MAXF);
426 GLint k;
427 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */
428 CHECKARRAY(rgbaFloat, return);
429
430 /* convert chan to float */
431 for (k = 0; k < width; k++) {
432 rgbaFloat[k][RCOMP] = (GLfloat) span->color.rgba[k][RCOMP] * scale;
433 rgbaFloat[k][GCOMP] = (GLfloat) span->color.rgba[k][GCOMP] * scale;
434 rgbaFloat[k][BCOMP] = (GLfloat) span->color.rgba[k][BCOMP] * scale;
435 rgbaFloat[k][ACOMP] = (GLfloat) span->color.rgba[k][ACOMP] * scale;
436 }
437 /* scale & bias */
438 if (transferOps & IMAGE_SCALE_BIAS_BIT) {
439 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
440 ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
441 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
442 ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
443 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
444 }
445 /* color map lookup */
446 if (transferOps & IMAGE_MAP_COLOR_BIT) {
447 _mesa_map_rgba(ctx, width, rgbaFloat);
448 }
449 /* GL_COLOR_TABLE lookup */
450 if (transferOps & IMAGE_COLOR_TABLE_BIT) {
451 _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
452 }
453 /* convolution */
454 if (transferOps & IMAGE_CONVOLUTION_BIT) {
455 abort(); /* should never get here; caught at top of function */
456 }
457 /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */
458 if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) {
459 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
460 ctx->Pixel.PostConvolutionScale[RCOMP],
461 ctx->Pixel.PostConvolutionScale[GCOMP],
462 ctx->Pixel.PostConvolutionScale[BCOMP],
463 ctx->Pixel.PostConvolutionScale[ACOMP],
464 ctx->Pixel.PostConvolutionBias[RCOMP],
465 ctx->Pixel.PostConvolutionBias[GCOMP],
466 ctx->Pixel.PostConvolutionBias[BCOMP],
467 ctx->Pixel.PostConvolutionBias[ACOMP]);
468 }
469 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
470 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
471 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
472 }
473 /* color matrix */
474 if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
475 _mesa_transform_rgba(ctx, width, rgbaFloat);
476 }
477 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
478 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
479 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
480 }
481 /* update histogram count */
482 if (transferOps & IMAGE_HISTOGRAM_BIT) {
483 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
484 }
485 /* update min/max */
486 if (transferOps & IMAGE_MIN_MAX_BIT) {
487 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
488 }
489 /* clamp to [0,1] and convert float back to chan */
490 for (k = 0; k < width; k++) {
491 GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
492 GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
493 GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
494 GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
495 span->color.rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
496 span->color.rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
497 span->color.rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
498 span->color.rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
499 }
500 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */
501 }
502
503 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
504 span->end = width;
505 _swrast_pixel_texture(ctx, span);
506 }
507
508 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
509 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
510 (const GLchan (*)[4])span->color.rgba, NULL );
511 }
512 else if (zoom) {
513 span->x = destx;
514 span->y = dy;
515 span->end = width;
516 _mesa_write_zoomed_rgba_span(ctx, span,
517 (CONST GLchan (*)[4]) span->color.rgba,
518 desty);
519 }
520 else {
521 span->x = destx;
522 span->y = dy;
523 span->end = width;
524 _mesa_write_rgba_span(ctx, span);
525 }
526 }
527
528 /* Restore pixel source to be the draw buffer (for blending, etc) */
529 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
530 ctx->Color.DriverDrawBuffer );
531
532 if (overlapping)
533 FREE(tmpImage);
534 }
535
536
537 static void copy_ci_pixels( GLcontext *ctx,
538 GLint srcx, GLint srcy, GLint width, GLint height,
539 GLint destx, GLint desty )
540 {
541 SWcontext *swrast = SWRAST_CONTEXT(ctx);
542 GLuint *tmpImage,*p;
543 GLint sy, dy, stepy;
544 GLint j;
545 GLboolean changeBuffer;
546 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
547 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
548 GLint overlapping;
549 struct sw_span *span = swrast->span;
550
551 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
552
553 /* Determine if copy should be bottom-to-top or top-to-bottom */
554 if (srcy<desty) {
555 /* top-down max-to-min */
556 sy = srcy + height - 1;
557 dy = desty + height - 1;
558 stepy = -1;
559 }
560 else {
561 /* bottom-up min-to-max */
562 sy = srcy;
563 dy = desty;
564 stepy = 1;
565 }
566
567 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
568 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
569
570 if (ctx->Depth.Test)
571 _mesa_span_default_z(ctx, span);
572 if (ctx->Fog.Enabled)
573 _mesa_span_default_fog(ctx, span);
574
575 /* If read and draw buffer are different we must do buffer switching */
576 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
577 || ctx->DrawBuffer != ctx->ReadBuffer;
578
579 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
580 ctx->Pixel.DriverReadBuffer );
581
582 if (overlapping) {
583 GLint ssy = sy;
584 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
585 if (!tmpImage) {
586 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
587 return;
588 }
589 p = tmpImage;
590 if (changeBuffer) {
591 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
592 ctx->Pixel.DriverReadBuffer );
593 }
594 for (j = 0; j < height; j++, ssy += stepy) {
595 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
596 p += width;
597 }
598 p = tmpImage;
599 }
600 else {
601 tmpImage = NULL; /* silence compiler warning */
602 p = NULL;
603 }
604
605 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
606 if (overlapping) {
607 MEMCPY(span->color.index, p, width * sizeof(GLuint));
608 p += width;
609 }
610 else {
611 if (changeBuffer) {
612 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
613 ctx->Pixel.DriverReadBuffer );
614 }
615 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy,
616 span->color.index );
617 }
618
619 if (changeBuffer) {
620 /* set read buffer back to draw buffer (in case of logicops) */
621 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
622 ctx->Color.DriverDrawBuffer );
623 }
624
625 if (shift_or_offset) {
626 _mesa_shift_and_offset_ci( ctx, width, span->color.index );
627 }
628 if (ctx->Pixel.MapColorFlag) {
629 _mesa_map_ci( ctx, width, span->color.index );
630 }
631
632 span->x = destx;
633 span->y = dy;
634 span->end = width;
635 if (zoom)
636 _mesa_write_zoomed_index_span(ctx, span, desty);
637 else
638 _mesa_write_index_span(ctx, span);
639 }
640
641 /* Restore pixel source to be the draw buffer (for blending, etc) */
642 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
643 ctx->Color.DriverDrawBuffer );
644
645 if (overlapping)
646 FREE(tmpImage);
647 }
648
649
650
651 /*
652 * TODO: Optimize!!!!
653 */
654 static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
655 GLint width, GLint height,
656 GLint destx, GLint desty )
657 {
658 GLfloat depth[MAX_WIDTH];
659 GLfloat *p, *tmpImage;
660 GLint sy, dy, stepy;
661 GLint i, j;
662 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
663 GLint overlapping;
664 struct sw_span *span = SWRAST_CONTEXT(ctx)->span;
665
666 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
667
668 if (!ctx->Visual.depthBits) {
669 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
670 return;
671 }
672
673 /* Determine if copy should be bottom-to-top or top-to-bottom */
674 if (srcy<desty) {
675 /* top-down max-to-min */
676 sy = srcy + height - 1;
677 dy = desty + height - 1;
678 stepy = -1;
679 }
680 else {
681 /* bottom-up min-to-max */
682 sy = srcy;
683 dy = desty;
684 stepy = 1;
685 }
686
687 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
688 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
689
690 _mesa_span_default_color(ctx, span);
691 if (ctx->Fog.Enabled)
692 _mesa_span_default_fog(ctx, span);
693
694 if (overlapping) {
695 GLint ssy = sy;
696 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
697 if (!tmpImage) {
698 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
699 return;
700 }
701 p = tmpImage;
702 for (j = 0; j < height; j++, ssy += stepy) {
703 _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
704 p += width;
705 }
706 p = tmpImage;
707 }
708 else {
709 tmpImage = NULL; /* silence compiler warning */
710 p = NULL;
711 }
712
713 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
714 if (overlapping) {
715 MEMCPY(depth, p, width * sizeof(GLfloat));
716 p += width;
717 }
718 else {
719 _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
720 }
721
722 for (i = 0; i < width; i++) {
723 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
724 span->zArray[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax);
725 }
726
727 span->x = destx;
728 span->y = dy;
729 span->end = width;
730 if (ctx->Visual.rgbMode) {
731 if (zoom)
732 _mesa_write_zoomed_rgba_span( ctx, span,
733 (const GLchan (*)[4])span->color.rgba,
734 desty );
735 else
736 _mesa_write_rgba_span(ctx, span);
737 }
738 else {
739 if (zoom)
740 _mesa_write_zoomed_index_span( ctx, span, desty );
741 else
742 _mesa_write_index_span(ctx, span);
743 }
744 }
745
746 if (overlapping)
747 FREE(tmpImage);
748 }
749
750
751
752 static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
753 GLint width, GLint height,
754 GLint destx, GLint desty )
755 {
756 GLint sy, dy, stepy;
757 GLint j;
758 GLstencil *p, *tmpImage;
759 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
760 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
761 GLint overlapping;
762
763 if (!ctx->Visual.stencilBits) {
764 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
765 return;
766 }
767
768 /* Determine if copy should be bottom-to-top or top-to-bottom */
769 if (srcy < desty) {
770 /* top-down max-to-min */
771 sy = srcy + height - 1;
772 dy = desty + height - 1;
773 stepy = -1;
774 }
775 else {
776 /* bottom-up min-to-max */
777 sy = srcy;
778 dy = desty;
779 stepy = 1;
780 }
781
782 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
783 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
784
785 if (overlapping) {
786 GLint ssy = sy;
787 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
788 if (!tmpImage) {
789 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
790 return;
791 }
792 p = tmpImage;
793 for (j = 0; j < height; j++, ssy += stepy) {
794 _mesa_read_stencil_span( ctx, width, srcx, ssy, p );
795 p += width;
796 }
797 p = tmpImage;
798 }
799 else {
800 tmpImage = NULL; /* silence compiler warning */
801 p = NULL;
802 }
803
804 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
805 GLstencil stencil[MAX_WIDTH];
806
807 if (overlapping) {
808 MEMCPY(stencil, p, width * sizeof(GLstencil));
809 p += width;
810 }
811 else {
812 _mesa_read_stencil_span( ctx, width, srcx, sy, stencil );
813 }
814
815 if (shift_or_offset) {
816 _mesa_shift_and_offset_stencil( ctx, width, stencil );
817 }
818 if (ctx->Pixel.MapStencilFlag) {
819 _mesa_map_stencil( ctx, width, stencil );
820 }
821
822 if (zoom) {
823 _mesa_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
824 }
825 else {
826 _mesa_write_stencil_span( ctx, width, destx, dy, stencil );
827 }
828 }
829
830 if (overlapping)
831 FREE(tmpImage);
832 }
833
834
835
836
837 void
838 _swrast_CopyPixels( GLcontext *ctx,
839 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
840 GLint destx, GLint desty,
841 GLenum type )
842 {
843 SWcontext *swrast = SWRAST_CONTEXT(ctx);
844 RENDER_START(swrast,ctx);
845
846 if (swrast->NewState)
847 _swrast_validate_derived( ctx );
848
849 if (type == GL_COLOR && ctx->Visual.rgbMode) {
850 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
851 }
852 else if (type == GL_COLOR && !ctx->Visual.rgbMode) {
853 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
854 }
855 else if (type == GL_DEPTH) {
856 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
857 }
858 else if (type == GL_STENCIL) {
859 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
860 }
861 else {
862 _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
863 }
864
865 RENDER_FINISH(swrast,ctx);
866 }