Make _SAT instructions compile correctly.
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "glheader.h"
27 #include "context.h"
28 #include "colormac.h"
29 #include "convolve.h"
30 #include "histogram.h"
31 #include "image.h"
32 #include "macros.h"
33 #include "imports.h"
34 #include "pixel.h"
35
36 #include "s_context.h"
37 #include "s_depth.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 * Convert GLfloat[n][4] colors to GLchan[n][4].
93 * XXX maybe move into image.c
94 */
95 static void
96 float_span_to_chan(GLuint n, CONST GLfloat in[][4], GLchan out[][4])
97 {
98 GLuint i;
99 for (i = 0; i < n; i++) {
100 UNCLAMPED_FLOAT_TO_CHAN(out[i][RCOMP], in[i][RCOMP]);
101 UNCLAMPED_FLOAT_TO_CHAN(out[i][GCOMP], in[i][GCOMP]);
102 UNCLAMPED_FLOAT_TO_CHAN(out[i][BCOMP], in[i][BCOMP]);
103 UNCLAMPED_FLOAT_TO_CHAN(out[i][ACOMP], in[i][ACOMP]);
104 }
105 }
106
107
108 /**
109 * Convert GLchan[n][4] colors to GLfloat[n][4].
110 * XXX maybe move into image.c
111 */
112 static void
113 chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4])
114 {
115 GLuint i;
116 for (i = 0; i < n; i++) {
117 out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]);
118 out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]);
119 out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]);
120 out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]);
121 }
122 }
123
124
125
126 /*
127 * RGBA copypixels with convolution.
128 */
129 static void
130 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
131 GLint width, GLint height, GLint destx, GLint desty)
132 {
133 SWcontext *swrast = SWRAST_CONTEXT(ctx);
134 GLboolean quick_draw;
135 GLint row;
136 GLboolean changeBuffer;
137 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
138 const GLuint transferOps = ctx->_ImageTransferState;
139 GLfloat *dest, *tmpImage, *convImage;
140 struct sw_span span;
141
142 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
143
144 if (ctx->Depth.Test)
145 _swrast_span_default_z(ctx, &span);
146 if (ctx->Fog.Enabled)
147 _swrast_span_default_fog(ctx, &span);
148
149
150 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
151 && !zoom
152 && destx >= 0
153 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
154 quick_draw = GL_TRUE;
155 }
156 else {
157 quick_draw = GL_FALSE;
158 }
159
160 /* If read and draw buffer are different we must do buffer switching */
161 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
162 || ctx->DrawBuffer != ctx->ReadBuffer;
163
164
165 /* allocate space for GLfloat image */
166 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
167 if (!tmpImage) {
168 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
169 return;
170 }
171 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
172 if (!convImage) {
173 FREE(tmpImage);
174 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
175 return;
176 }
177
178 dest = tmpImage;
179
180 if (changeBuffer) {
181 /* choose the read buffer */
182 _swrast_use_read_buffer(ctx);
183 }
184
185 /* read source image */
186 dest = tmpImage;
187 for (row = 0; row < height; row++) {
188 GLchan rgba[MAX_WIDTH][4];
189 /* Read GLchan and convert to GLfloat */
190 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx,
191 srcy + row, rgba);
192 chan_span_to_float(width, (CONST GLchan (*)[4]) rgba,
193 (GLfloat (*)[4]) dest);
194 }
195
196 if (changeBuffer) {
197 /* restore default src/dst buffer */
198 _swrast_use_draw_buffer(ctx);
199 }
200
201 /* do the image transfer ops which preceed convolution */
202 for (row = 0; row < height; row++) {
203 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
204 _mesa_apply_rgba_transfer_ops(ctx,
205 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
206 width, rgba);
207 }
208
209 /* do convolution */
210 if (ctx->Pixel.Convolution2DEnabled) {
211 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
212 }
213 else {
214 ASSERT(ctx->Pixel.Separable2DEnabled);
215 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
216 }
217 FREE(tmpImage);
218
219 /* do remaining post-convolution image transfer ops */
220 for (row = 0; row < height; row++) {
221 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
222 _mesa_apply_rgba_transfer_ops(ctx,
223 transferOps & IMAGE_POST_CONVOLUTION_BITS,
224 width, rgba);
225 }
226
227 /* write the new image */
228 for (row = 0; row < height; row++) {
229 const GLfloat *src = convImage + row * width * 4;
230 GLint dy;
231
232 /* convert floats back to chan */
233 float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba);
234
235 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
236 span.end = width;
237 _swrast_pixel_texture(ctx, &span);
238 }
239
240 /* write row to framebuffer */
241
242 dy = desty + row;
243 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
244 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
245 (const GLchan (*)[4])span.array->rgba, NULL );
246 }
247 else if (zoom) {
248 span.x = destx;
249 span.y = dy;
250 span.end = width;
251 _swrast_write_zoomed_rgba_span(ctx, &span,
252 (CONST GLchan (*)[4])span.array->rgba,
253 desty, 0);
254 }
255 else {
256 span.x = destx;
257 span.y = dy;
258 span.end = width;
259 _swrast_write_rgba_span(ctx, &span);
260 }
261 }
262
263 FREE(convImage);
264 }
265
266
267 /*
268 * RGBA copypixels
269 */
270 static void
271 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
272 GLint width, GLint height, GLint destx, GLint desty)
273 {
274 SWcontext *swrast = SWRAST_CONTEXT(ctx);
275 GLchan *tmpImage,*p;
276 GLboolean quick_draw;
277 GLint sy, dy, stepy, j;
278 GLboolean changeBuffer;
279 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
280 GLint overlapping;
281 const GLuint transferOps = ctx->_ImageTransferState;
282 struct sw_span span;
283
284 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
285
286 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
287 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
288 return;
289 }
290
291 /* Determine if copy should be done bottom-to-top or top-to-bottom */
292 if (srcy < desty) {
293 /* top-down max-to-min */
294 sy = srcy + height - 1;
295 dy = desty + height - 1;
296 stepy = -1;
297 }
298 else {
299 /* bottom-up min-to-max */
300 sy = srcy;
301 dy = desty;
302 stepy = 1;
303 }
304
305 if (ctx->DrawBuffer == ctx->ReadBuffer) {
306 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
307 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
308 }
309 else {
310 overlapping = GL_FALSE;
311 }
312
313 if (ctx->Depth.Test)
314 _swrast_span_default_z(ctx, &span);
315 if (ctx->Fog.Enabled)
316 _swrast_span_default_fog(ctx, &span);
317
318 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
319 && !zoom
320 && destx >= 0
321 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
322 quick_draw = GL_TRUE;
323 }
324 else {
325 quick_draw = GL_FALSE;
326 }
327
328 /* If read and draw buffer are different we must do buffer switching */
329 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
330 || ctx->DrawBuffer != ctx->ReadBuffer;
331
332 if (overlapping) {
333 GLint ssy = sy;
334 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
335 if (!tmpImage) {
336 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
337 return;
338 }
339 /* setup source */
340 if (changeBuffer)
341 _swrast_use_read_buffer(ctx);
342 /* read the source image */
343 p = tmpImage;
344 for (j = 0; j < height; j++, ssy += stepy) {
345 _swrast_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
346 (GLchan (*)[4]) p );
347 p += width * 4;
348 }
349 p = tmpImage;
350 /* restore dest */
351 if (changeBuffer) {
352 _swrast_use_draw_buffer(ctx);
353 changeBuffer = GL_FALSE;
354 }
355 }
356 else {
357 tmpImage = NULL; /* silence compiler warnings */
358 p = NULL;
359 }
360
361 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
362 /* Get source pixels */
363 if (overlapping) {
364 /* get from buffered image */
365 ASSERT(width < MAX_WIDTH);
366 MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4);
367 p += width * 4;
368 }
369 else {
370 /* get from framebuffer */
371 if (changeBuffer)
372 _swrast_use_read_buffer(ctx);
373 ASSERT(width < MAX_WIDTH);
374 _swrast_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy,
375 span.array->rgba );
376 if (changeBuffer)
377 _swrast_use_draw_buffer(ctx);
378 }
379
380 if (transferOps) {
381 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */
382 CHECKARRAY(rgbaFloat, return);
383
384 /* convert to float, transfer, convert back to chan */
385 chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba,
386 rgbaFloat);
387 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat);
388 float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat,
389 span.array->rgba);
390
391 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */
392 }
393
394 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
395 span.end = width;
396 _swrast_pixel_texture(ctx, &span);
397 }
398
399 /* Write color span */
400 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
401 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
402 (const GLchan (*)[4])span.array->rgba, NULL );
403 }
404 else if (zoom) {
405 span.x = destx;
406 span.y = dy;
407 span.end = width;
408 _swrast_write_zoomed_rgba_span(ctx, &span,
409 (CONST GLchan (*)[4]) span.array->rgba,
410 desty, 0);
411 }
412 else {
413 span.x = destx;
414 span.y = dy;
415 span.end = width;
416 _swrast_write_rgba_span(ctx, &span);
417 }
418 }
419
420 if (overlapping)
421 FREE(tmpImage);
422 }
423
424
425 static void
426 copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
427 GLint width, GLint height,
428 GLint destx, GLint desty )
429 {
430 GLuint *tmpImage,*p;
431 GLint sy, dy, stepy;
432 GLint j;
433 GLboolean changeBuffer;
434 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
435 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
436 GLint overlapping;
437 struct sw_span span;
438
439 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
440
441 /* Determine if copy should be bottom-to-top or top-to-bottom */
442 if (srcy<desty) {
443 /* top-down max-to-min */
444 sy = srcy + height - 1;
445 dy = desty + height - 1;
446 stepy = -1;
447 }
448 else {
449 /* bottom-up min-to-max */
450 sy = srcy;
451 dy = desty;
452 stepy = 1;
453 }
454
455 if (ctx->DrawBuffer == ctx->ReadBuffer) {
456 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
457 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
458 }
459 else {
460 overlapping = GL_FALSE;
461 }
462
463 if (ctx->Depth.Test)
464 _swrast_span_default_z(ctx, &span);
465 if (ctx->Fog.Enabled)
466 _swrast_span_default_fog(ctx, &span);
467
468 /* If read and draw buffer are different we must do buffer switching */
469 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
470 || ctx->DrawBuffer != ctx->ReadBuffer;
471
472 if (overlapping) {
473 GLint ssy = sy;
474 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
475 if (!tmpImage) {
476 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
477 return;
478 }
479 /* setup source */
480 if (changeBuffer)
481 _swrast_use_read_buffer(ctx);
482 /* read the image */
483 p = tmpImage;
484 for (j = 0; j < height; j++, ssy += stepy) {
485 _swrast_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
486 p += width;
487 }
488 p = tmpImage;
489 /* restore to draw buffer */
490 if (changeBuffer) {
491 _swrast_use_draw_buffer(ctx);
492 changeBuffer = GL_FALSE;
493 }
494 }
495 else {
496 tmpImage = NULL; /* silence compiler warning */
497 p = NULL;
498 }
499
500 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
501 /* Get color indexes */
502 if (overlapping) {
503 MEMCPY(span.array->index, p, width * sizeof(GLuint));
504 p += width;
505 }
506 else {
507 if (changeBuffer)
508 _swrast_use_read_buffer(ctx);
509 _swrast_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy,
510 span.array->index );
511 if (changeBuffer)
512 _swrast_use_draw_buffer(ctx);
513 }
514
515 /* Apply shift, offset, look-up table */
516 if (shift_or_offset) {
517 _mesa_shift_and_offset_ci( ctx, width, span.array->index );
518 }
519 if (ctx->Pixel.MapColorFlag) {
520 _mesa_map_ci( ctx, width, span.array->index );
521 }
522
523 /* write color indexes */
524 span.x = destx;
525 span.y = dy;
526 span.end = width;
527 if (zoom)
528 _swrast_write_zoomed_index_span(ctx, &span, desty, 0);
529 else
530 _swrast_write_index_span(ctx, &span);
531 }
532
533 if (overlapping)
534 FREE(tmpImage);
535 }
536
537
538
539 /*
540 * TODO: Optimize!!!!
541 */
542 static void
543 copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
544 GLint width, GLint height,
545 GLint destx, GLint desty )
546 {
547 GLfloat *p, *tmpImage;
548 GLint sy, dy, stepy;
549 GLint i, j;
550 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
551 GLint overlapping;
552 struct sw_span span;
553
554 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
555
556 if (!ctx->Visual.depthBits) {
557 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
558 return;
559 }
560
561 /* Determine if copy should be bottom-to-top or top-to-bottom */
562 if (srcy<desty) {
563 /* top-down max-to-min */
564 sy = srcy + height - 1;
565 dy = desty + height - 1;
566 stepy = -1;
567 }
568 else {
569 /* bottom-up min-to-max */
570 sy = srcy;
571 dy = desty;
572 stepy = 1;
573 }
574
575 if (ctx->DrawBuffer == ctx->ReadBuffer) {
576 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
577 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
578 }
579 else {
580 overlapping = GL_FALSE;
581 }
582
583 _swrast_span_default_color(ctx, &span);
584 if (ctx->Fog.Enabled)
585 _swrast_span_default_fog(ctx, &span);
586
587 if (overlapping) {
588 GLint ssy = sy;
589 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
590 if (!tmpImage) {
591 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
592 return;
593 }
594 p = tmpImage;
595 for (j = 0; j < height; j++, ssy += stepy) {
596 _swrast_read_depth_span_float(ctx, width, srcx, ssy, p);
597 p += width;
598 }
599 p = tmpImage;
600 }
601 else {
602 tmpImage = NULL; /* silence compiler warning */
603 p = NULL;
604 }
605
606 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
607 GLfloat depth[MAX_WIDTH];
608
609 /* get depth values */
610 if (overlapping) {
611 MEMCPY(depth, p, width * sizeof(GLfloat));
612 p += width;
613 }
614 else {
615 _swrast_read_depth_span_float(ctx, width, srcx, sy, depth);
616 }
617
618 /* apply scale and bias */
619 for (i = 0; i < width; i++) {
620 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
621 span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax);
622 }
623
624 /* write depth values */
625 span.x = destx;
626 span.y = dy;
627 span.end = width;
628 if (ctx->Visual.rgbMode) {
629 if (zoom)
630 _swrast_write_zoomed_rgba_span( ctx, &span,
631 (const GLchan (*)[4])span.array->rgba, desty, 0 );
632 else
633 _swrast_write_rgba_span(ctx, &span);
634 }
635 else {
636 if (zoom)
637 _swrast_write_zoomed_index_span( ctx, &span, desty, 0 );
638 else
639 _swrast_write_index_span(ctx, &span);
640 }
641 }
642
643 if (overlapping)
644 FREE(tmpImage);
645 }
646
647
648
649 static void
650 copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
651 GLint width, GLint height,
652 GLint destx, GLint desty )
653 {
654 GLint sy, dy, stepy;
655 GLint j;
656 GLstencil *p, *tmpImage;
657 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
658 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
659 GLint overlapping;
660
661 if (!ctx->Visual.stencilBits) {
662 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
663 return;
664 }
665
666 /* Determine if copy should be bottom-to-top or top-to-bottom */
667 if (srcy < desty) {
668 /* top-down max-to-min */
669 sy = srcy + height - 1;
670 dy = desty + height - 1;
671 stepy = -1;
672 }
673 else {
674 /* bottom-up min-to-max */
675 sy = srcy;
676 dy = desty;
677 stepy = 1;
678 }
679
680 if (ctx->DrawBuffer == ctx->ReadBuffer) {
681 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
682 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
683 }
684 else {
685 overlapping = GL_FALSE;
686 }
687
688 if (overlapping) {
689 GLint ssy = sy;
690 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
691 if (!tmpImage) {
692 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
693 return;
694 }
695 p = tmpImage;
696 for (j = 0; j < height; j++, ssy += stepy) {
697 _swrast_read_stencil_span( ctx, width, srcx, ssy, p );
698 p += width;
699 }
700 p = tmpImage;
701 }
702 else {
703 tmpImage = NULL; /* silence compiler warning */
704 p = NULL;
705 }
706
707 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
708 GLstencil stencil[MAX_WIDTH];
709
710 /* Get stencil values */
711 if (overlapping) {
712 MEMCPY(stencil, p, width * sizeof(GLstencil));
713 p += width;
714 }
715 else {
716 _swrast_read_stencil_span( ctx, width, srcx, sy, stencil );
717 }
718
719 /* Apply shift, offset, look-up table */
720 if (shift_or_offset) {
721 _mesa_shift_and_offset_stencil( ctx, width, stencil );
722 }
723 if (ctx->Pixel.MapStencilFlag) {
724 _mesa_map_stencil( ctx, width, stencil );
725 }
726
727 /* Write stencil values */
728 if (zoom) {
729 _swrast_write_zoomed_stencil_span( ctx, width, destx, dy,
730 stencil, desty, 0 );
731 }
732 else {
733 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
734 }
735 }
736
737 if (overlapping)
738 FREE(tmpImage);
739 }
740
741
742
743 void
744 _swrast_CopyPixels( GLcontext *ctx,
745 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
746 GLint destx, GLint desty,
747 GLenum type )
748 {
749 SWcontext *swrast = SWRAST_CONTEXT(ctx);
750 RENDER_START(swrast,ctx);
751
752 if (swrast->NewState)
753 _swrast_validate_derived( ctx );
754
755 if (type == GL_COLOR && ctx->Visual.rgbMode) {
756 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
757 }
758 else if (type == GL_COLOR && !ctx->Visual.rgbMode) {
759 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
760 }
761 else if (type == GL_DEPTH) {
762 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
763 }
764 else if (type == GL_STENCIL) {
765 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
766 }
767 else {
768 _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
769 }
770
771 RENDER_FINISH(swrast,ctx);
772 }