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