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