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