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