Removed the GL_SGIX/SGIS_pixel_texture extensions. Same thing can be
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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_span.h"
39 #include "s_stencil.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 * Convert GLfloat[n][4] colors to GLchan[n][4].
91 * XXX maybe move into image.c
92 */
93 static void
94 float_span_to_chan(GLuint n, CONST GLfloat in[][4], GLchan out[][4])
95 {
96 GLuint i;
97 for (i = 0; i < n; i++) {
98 UNCLAMPED_FLOAT_TO_CHAN(out[i][RCOMP], in[i][RCOMP]);
99 UNCLAMPED_FLOAT_TO_CHAN(out[i][GCOMP], in[i][GCOMP]);
100 UNCLAMPED_FLOAT_TO_CHAN(out[i][BCOMP], in[i][BCOMP]);
101 UNCLAMPED_FLOAT_TO_CHAN(out[i][ACOMP], in[i][ACOMP]);
102 }
103 }
104
105
106 /**
107 * Convert GLchan[n][4] colors to GLfloat[n][4].
108 * XXX maybe move into image.c
109 */
110 static void
111 chan_span_to_float(GLuint n, CONST GLchan in[][4], GLfloat out[][4])
112 {
113 GLuint i;
114 for (i = 0; i < n; i++) {
115 out[i][RCOMP] = CHAN_TO_FLOAT(in[i][RCOMP]);
116 out[i][GCOMP] = CHAN_TO_FLOAT(in[i][GCOMP]);
117 out[i][BCOMP] = CHAN_TO_FLOAT(in[i][BCOMP]);
118 out[i][ACOMP] = CHAN_TO_FLOAT(in[i][ACOMP]);
119 }
120 }
121
122
123
124 /*
125 * RGBA copypixels with convolution.
126 */
127 static void
128 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
129 GLint width, GLint height, GLint destx, GLint desty)
130 {
131 SWcontext *swrast = SWRAST_CONTEXT(ctx);
132 struct gl_renderbuffer *drawRb = NULL;
133 GLboolean quick_draw;
134 GLint row;
135 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
136 const GLuint transferOps = ctx->_ImageTransferState;
137 GLfloat *dest, *tmpImage, *convImage;
138 struct sw_span span;
139
140 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
141
142 if (ctx->Depth.Test)
143 _swrast_span_default_z(ctx, &span);
144 if (swrast->_FogEnabled)
145 _swrast_span_default_fog(ctx, &span);
146
147
148 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
149 && !zoom
150 && destx >= 0
151 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
152 quick_draw = GL_TRUE;
153 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
154 }
155 else {
156 quick_draw = GL_FALSE;
157 }
158
159 /* allocate space for GLfloat image */
160 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
161 if (!tmpImage) {
162 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
163 return;
164 }
165 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
166 if (!convImage) {
167 _mesa_free(tmpImage);
168 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
169 return;
170 }
171
172 /* read source image */
173 dest = tmpImage;
174 for (row = 0; row < height; row++) {
175 GLchan rgba[MAX_WIDTH][4];
176 /* Read GLchan and convert to GLfloat */
177 _swrast_read_rgba_span(ctx, ctx->ReadBuffer->_ColorReadBuffer,
178 width, srcx, srcy + row, rgba);
179 chan_span_to_float(width, (CONST GLchan (*)[4]) rgba,
180 (GLfloat (*)[4]) dest);
181 dest += 4 * width;
182 }
183
184 /* do the image transfer ops which preceed convolution */
185 for (row = 0; row < height; row++) {
186 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
187 _mesa_apply_rgba_transfer_ops(ctx,
188 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
189 width, rgba);
190 }
191
192 /* do convolution */
193 if (ctx->Pixel.Convolution2DEnabled) {
194 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
195 }
196 else {
197 ASSERT(ctx->Pixel.Separable2DEnabled);
198 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
199 }
200 _mesa_free(tmpImage);
201
202 /* do remaining post-convolution image transfer ops */
203 for (row = 0; row < height; row++) {
204 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
205 _mesa_apply_rgba_transfer_ops(ctx,
206 transferOps & IMAGE_POST_CONVOLUTION_BITS,
207 width, rgba);
208 }
209
210 /* write the new image */
211 for (row = 0; row < height; row++) {
212 const GLfloat *src = convImage + row * width * 4;
213 GLint dy;
214
215 /* convert floats back to chan */
216 float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba);
217
218 /* write row to framebuffer */
219 dy = desty + row;
220 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
221 drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
222 }
223 else {
224 span.x = destx;
225 span.y = dy;
226 span.end = width;
227 if (zoom) {
228 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span,
229 (CONST GLchan (*)[4])span.array->rgba);
230 }
231 else {
232 _swrast_write_rgba_span(ctx, &span);
233 }
234 }
235 }
236
237 _mesa_free(convImage);
238 }
239
240
241 /*
242 * RGBA copypixels
243 */
244 static void
245 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
246 GLint width, GLint height, GLint destx, GLint desty)
247 {
248 SWcontext *swrast = SWRAST_CONTEXT(ctx);
249 struct gl_renderbuffer *drawRb;
250 GLchan *tmpImage,*p;
251 GLboolean quick_draw;
252 GLint sy, dy, stepy, j;
253 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
254 GLint overlapping;
255 const GLuint transferOps = ctx->_ImageTransferState;
256 struct sw_span span;
257
258 if (!ctx->ReadBuffer->_ColorReadBuffer) {
259 /* no readbuffer - OK */
260 return;
261 }
262
263 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
264
265 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
266 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
267 return;
268 }
269
270 /* Determine if copy should be done bottom-to-top or top-to-bottom */
271 if (srcy < desty) {
272 /* top-down max-to-min */
273 sy = srcy + height - 1;
274 dy = desty + height - 1;
275 stepy = -1;
276 }
277 else {
278 /* bottom-up min-to-max */
279 sy = srcy;
280 dy = desty;
281 stepy = 1;
282 }
283
284 if (ctx->DrawBuffer == ctx->ReadBuffer) {
285 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
286 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
287 }
288 else {
289 overlapping = GL_FALSE;
290 }
291
292 if (ctx->Depth.Test)
293 _swrast_span_default_z(ctx, &span);
294 if (swrast->_FogEnabled)
295 _swrast_span_default_fog(ctx, &span);
296
297 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
298 && !zoom
299 && destx >= 0
300 && destx + width <= (GLint) ctx->DrawBuffer->Width) {
301 quick_draw = GL_TRUE;
302 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0];
303 }
304 else {
305 quick_draw = GL_FALSE;
306 drawRb = NULL;
307 }
308
309 if (overlapping) {
310 GLint ssy = sy;
311 tmpImage = (GLchan *) _mesa_malloc(width * height * sizeof(GLchan) * 4);
312 if (!tmpImage) {
313 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
314 return;
315 }
316 /* read the source image */
317 p = tmpImage;
318 for (j = 0; j < height; j++, ssy += stepy) {
319 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
320 width, srcx, ssy, (GLchan (*)[4]) p );
321 p += width * 4;
322 }
323 p = tmpImage;
324 }
325 else {
326 tmpImage = NULL; /* silence compiler warnings */
327 p = NULL;
328 }
329
330 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
331 /* Get source pixels */
332 if (overlapping) {
333 /* get from buffered image */
334 ASSERT(width < MAX_WIDTH);
335 _mesa_memcpy(span.array->rgba, p, width * sizeof(GLchan) * 4);
336 p += width * 4;
337 }
338 else {
339 /* get from framebuffer */
340 ASSERT(width < MAX_WIDTH);
341 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
342 width, srcx, sy, span.array->rgba );
343 }
344
345 if (transferOps) {
346 GLfloat rgbaFloat[MAX_WIDTH][4];
347 /* convert to float, transfer, convert back to chan */
348 chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba,
349 rgbaFloat);
350 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat);
351 float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat,
352 span.array->rgba);
353 }
354
355 /* Write color span */
356 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) {
357 drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL);
358 }
359 else {
360 span.x = destx;
361 span.y = dy;
362 span.end = width;
363 if (zoom) {
364 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span,
365 (CONST GLchan (*)[4]) span.array->rgba);
366 }
367 else {
368 _swrast_write_rgba_span(ctx, &span);
369 }
370 }
371 }
372
373 if (overlapping)
374 _mesa_free(tmpImage);
375 }
376
377
378 static void
379 copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
380 GLint width, GLint height,
381 GLint destx, GLint desty )
382 {
383 SWcontext *swrast = SWRAST_CONTEXT(ctx);
384 GLuint *tmpImage,*p;
385 GLint sy, dy, stepy;
386 GLint j;
387 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
388 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
389 GLint overlapping;
390 struct sw_span span;
391
392 if (!ctx->ReadBuffer->_ColorReadBuffer) {
393 /* no readbuffer - OK */
394 return;
395 }
396
397 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX);
398
399 /* Determine if copy should be bottom-to-top or top-to-bottom */
400 if (srcy<desty) {
401 /* top-down max-to-min */
402 sy = srcy + height - 1;
403 dy = desty + height - 1;
404 stepy = -1;
405 }
406 else {
407 /* bottom-up min-to-max */
408 sy = srcy;
409 dy = desty;
410 stepy = 1;
411 }
412
413 if (ctx->DrawBuffer == ctx->ReadBuffer) {
414 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
415 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
416 }
417 else {
418 overlapping = GL_FALSE;
419 }
420
421 if (ctx->Depth.Test)
422 _swrast_span_default_z(ctx, &span);
423 if (swrast->_FogEnabled)
424 _swrast_span_default_fog(ctx, &span);
425
426 if (overlapping) {
427 GLint ssy = sy;
428 tmpImage = (GLuint *) _mesa_malloc(width * height * sizeof(GLuint));
429 if (!tmpImage) {
430 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
431 return;
432 }
433 /* read the image */
434 p = tmpImage;
435 for (j = 0; j < height; j++, ssy += stepy) {
436 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
437 width, srcx, ssy, p );
438 p += width;
439 }
440 p = tmpImage;
441 }
442 else {
443 tmpImage = NULL; /* silence compiler warning */
444 p = NULL;
445 }
446
447 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
448 /* Get color indexes */
449 if (overlapping) {
450 _mesa_memcpy(span.array->index, p, width * sizeof(GLuint));
451 p += width;
452 }
453 else {
454 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
455 width, srcx, sy, span.array->index );
456 }
457
458 /* Apply shift, offset, look-up table */
459 if (shift_or_offset) {
460 _mesa_shift_and_offset_ci( ctx, width, span.array->index );
461 }
462 if (ctx->Pixel.MapColorFlag) {
463 _mesa_map_ci( ctx, width, span.array->index );
464 }
465
466 /* write color indexes */
467 span.x = destx;
468 span.y = dy;
469 span.end = width;
470 if (zoom)
471 _swrast_write_zoomed_index_span(ctx, destx, desty, &span);
472 else
473 _swrast_write_index_span(ctx, &span);
474 }
475
476 if (overlapping)
477 _mesa_free(tmpImage);
478 }
479
480
481
482 /*
483 * TODO: Optimize!!!!
484 */
485 static void
486 copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
487 GLint width, GLint height,
488 GLint destx, GLint desty )
489 {
490 SWcontext *swrast = SWRAST_CONTEXT(ctx);
491 struct gl_framebuffer *fb = ctx->ReadBuffer;
492 struct gl_renderbuffer *readRb = fb->_DepthBuffer;
493 const GLfloat depthMax = fb->_DepthMaxF;
494 GLfloat *p, *tmpImage;
495 GLint sy, dy, stepy;
496 GLint i, j;
497 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
498 GLint overlapping;
499 struct sw_span span;
500
501 if (!readRb) {
502 /* no readbuffer - OK */
503 return;
504 }
505
506 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z);
507
508 /* Determine if copy should be bottom-to-top or top-to-bottom */
509 if (srcy<desty) {
510 /* top-down max-to-min */
511 sy = srcy + height - 1;
512 dy = desty + height - 1;
513 stepy = -1;
514 }
515 else {
516 /* bottom-up min-to-max */
517 sy = srcy;
518 dy = desty;
519 stepy = 1;
520 }
521
522 if (ctx->DrawBuffer == ctx->ReadBuffer) {
523 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
524 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
525 }
526 else {
527 overlapping = GL_FALSE;
528 }
529
530 _swrast_span_default_color(ctx, &span);
531 if (swrast->_FogEnabled)
532 _swrast_span_default_fog(ctx, &span);
533
534 if (overlapping) {
535 GLint ssy = sy;
536 tmpImage = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
537 if (!tmpImage) {
538 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
539 return;
540 }
541 p = tmpImage;
542 for (j = 0; j < height; j++, ssy += stepy) {
543 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
544 p += width;
545 }
546 p = tmpImage;
547 }
548 else {
549 tmpImage = NULL; /* silence compiler warning */
550 p = NULL;
551 }
552
553 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
554 GLfloat depth[MAX_WIDTH];
555 /* get depth values */
556 if (overlapping) {
557 _mesa_memcpy(depth, p, width * sizeof(GLfloat));
558 p += width;
559 }
560 else {
561 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
562 }
563
564 /* apply scale and bias */
565 for (i = 0; i < width; i++) {
566 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
567 span.array->z[i] = (GLuint) (CLAMP(d, 0.0F, 1.0F) * depthMax);
568 }
569
570 /* write depth values */
571 span.x = destx;
572 span.y = dy;
573 span.end = width;
574 if (fb->Visual.rgbMode) {
575 if (zoom)
576 _swrast_write_zoomed_rgba_span(ctx, destx, desty, &span,
577 (const GLchan (*)[4]) span.array->rgba);
578 else
579 _swrast_write_rgba_span(ctx, &span);
580 }
581 else {
582 if (zoom)
583 _swrast_write_zoomed_index_span(ctx, destx, desty, &span);
584 else
585 _swrast_write_index_span(ctx, &span);
586 }
587 }
588
589 if (overlapping)
590 _mesa_free(tmpImage);
591 }
592
593
594
595 static void
596 copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
597 GLint width, GLint height,
598 GLint destx, GLint desty )
599 {
600 struct gl_framebuffer *fb = ctx->ReadBuffer;
601 struct gl_renderbuffer *rb = fb->_StencilBuffer;
602 GLint sy, dy, stepy;
603 GLint j;
604 GLstencil *p, *tmpImage;
605 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
606 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
607 GLint overlapping;
608
609 if (!rb) {
610 /* no readbuffer - OK */
611 return;
612 }
613
614 /* Determine if copy should be bottom-to-top or top-to-bottom */
615 if (srcy < desty) {
616 /* top-down max-to-min */
617 sy = srcy + height - 1;
618 dy = desty + height - 1;
619 stepy = -1;
620 }
621 else {
622 /* bottom-up min-to-max */
623 sy = srcy;
624 dy = desty;
625 stepy = 1;
626 }
627
628 if (ctx->DrawBuffer == ctx->ReadBuffer) {
629 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
630 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
631 }
632 else {
633 overlapping = GL_FALSE;
634 }
635
636 if (overlapping) {
637 GLint ssy = sy;
638 tmpImage = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
639 if (!tmpImage) {
640 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
641 return;
642 }
643 p = tmpImage;
644 for (j = 0; j < height; j++, ssy += stepy) {
645 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
646 p += width;
647 }
648 p = tmpImage;
649 }
650 else {
651 tmpImage = NULL; /* silence compiler warning */
652 p = NULL;
653 }
654
655 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
656 GLstencil stencil[MAX_WIDTH];
657
658 /* Get stencil values */
659 if (overlapping) {
660 _mesa_memcpy(stencil, p, width * sizeof(GLstencil));
661 p += width;
662 }
663 else {
664 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
665 }
666
667 /* Apply shift, offset, look-up table */
668 if (shift_or_offset) {
669 _mesa_shift_and_offset_stencil( ctx, width, stencil );
670 }
671 if (ctx->Pixel.MapStencilFlag) {
672 _mesa_map_stencil( ctx, width, stencil );
673 }
674
675 /* Write stencil values */
676 if (zoom) {
677 _swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
678 destx, dy, stencil);
679 }
680 else {
681 _swrast_write_stencil_span( ctx, width, destx, dy, stencil );
682 }
683 }
684
685 if (overlapping)
686 _mesa_free(tmpImage);
687 }
688
689
690 /**
691 * This isn't terribly efficient. If a driver really has combined
692 * depth/stencil buffers the driver should implement an optimized
693 * CopyPixels function.
694 */
695 static void
696 copy_depth_stencil_pixels(GLcontext *ctx,
697 const GLint srcX, const GLint srcY,
698 const GLint width, const GLint height,
699 const GLint destX, const GLint destY)
700 {
701 struct gl_renderbuffer *stencilReadRb, *depthReadRb, *depthDrawRb;
702 GLint sy, dy, stepy;
703 GLint j;
704 GLstencil *tempStencilImage = NULL, *stencilPtr = NULL;
705 GLfloat *tempDepthImage = NULL, *depthPtr = NULL;
706 const GLfloat depthScale = ctx->DrawBuffer->_DepthMaxF;
707 const GLuint stencilMask = ctx->Stencil.WriteMask[0];
708 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
709 const GLboolean shiftOrOffset
710 = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
711 const GLboolean scaleOrBias
712 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
713 GLint overlapping;
714
715 depthDrawRb = ctx->DrawBuffer->_DepthBuffer;
716 depthReadRb = ctx->ReadBuffer->_DepthBuffer;
717 stencilReadRb = ctx->ReadBuffer->_StencilBuffer;
718
719 ASSERT(depthDrawRb);
720 ASSERT(depthReadRb);
721 ASSERT(stencilReadRb);
722
723 /* Determine if copy should be bottom-to-top or top-to-bottom */
724 if (srcY < destY) {
725 /* top-down max-to-min */
726 sy = srcY + height - 1;
727 dy = destY + height - 1;
728 stepy = -1;
729 }
730 else {
731 /* bottom-up min-to-max */
732 sy = srcY;
733 dy = destY;
734 stepy = 1;
735 }
736
737 if (ctx->DrawBuffer == ctx->ReadBuffer) {
738 overlapping = regions_overlap(srcX, srcY, destX, destY, width, height,
739 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
740 }
741 else {
742 overlapping = GL_FALSE;
743 }
744
745 if (overlapping) {
746 GLint ssy = sy;
747
748 if (stencilMask != 0x0) {
749 tempStencilImage
750 = (GLstencil *) _mesa_malloc(width * height * sizeof(GLstencil));
751 if (!tempStencilImage) {
752 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
753 return;
754 }
755
756 /* get copy of stencil pixels */
757 stencilPtr = tempStencilImage;
758 for (j = 0; j < height; j++, ssy += stepy) {
759 _swrast_read_stencil_span(ctx, stencilReadRb,
760 width, srcX, ssy, stencilPtr);
761 stencilPtr += width;
762 }
763 stencilPtr = tempStencilImage;
764 }
765
766 if (ctx->Depth.Mask) {
767 tempDepthImage
768 = (GLfloat *) _mesa_malloc(width * height * sizeof(GLfloat));
769 if (!tempDepthImage) {
770 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
771 _mesa_free(tempStencilImage);
772 return;
773 }
774
775 /* get copy of depth pixels */
776 depthPtr = tempDepthImage;
777 for (j = 0; j < height; j++, ssy += stepy) {
778 _swrast_read_depth_span_float(ctx, depthReadRb,
779 width, srcX, ssy, depthPtr);
780 depthPtr += width;
781 }
782 depthPtr = tempDepthImage;
783 }
784 }
785
786 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
787 if (stencilMask != 0x0) {
788 GLstencil stencil[MAX_WIDTH];
789
790 /* Get stencil values */
791 if (overlapping) {
792 _mesa_memcpy(stencil, stencilPtr, width * sizeof(GLstencil));
793 stencilPtr += width;
794 }
795 else {
796 _swrast_read_stencil_span(ctx, stencilReadRb,
797 width, srcX, sy, stencil);
798 }
799
800 /* Apply shift, offset, look-up table */
801 if (shiftOrOffset) {
802 _mesa_shift_and_offset_stencil(ctx, width, stencil);
803 }
804 if (ctx->Pixel.MapStencilFlag) {
805 _mesa_map_stencil(ctx, width, stencil);
806 }
807
808 /* Write values */
809 if (zoom) {
810 _swrast_write_zoomed_stencil_span(ctx, destX, destY, width,
811 destX, dy, stencil);
812 }
813 else {
814 _swrast_write_stencil_span( ctx, width, destX, dy, stencil );
815 }
816 }
817
818 if (ctx->Depth.Mask) {
819 GLfloat depth[MAX_WIDTH];
820 GLuint zVals32[MAX_WIDTH];
821 GLushort zVals16[MAX_WIDTH];
822 GLvoid *zVals;
823 GLuint zBytes;
824
825 /* get depth values */
826 if (overlapping) {
827 _mesa_memcpy(depth, depthPtr, width * sizeof(GLfloat));
828 depthPtr += width;
829 }
830 else {
831 _swrast_read_depth_span_float(ctx, depthReadRb,
832 width, srcX, sy, depth);
833 }
834
835 /* scale & bias */
836 if (scaleOrBias) {
837 _mesa_scale_and_bias_depth(ctx, width, depth);
838 }
839 /* convert to integer Z values */
840 if (depthDrawRb->DataType == GL_UNSIGNED_SHORT) {
841 GLint k;
842 for (k = 0; k < width; k++)
843 zVals16[k] = (GLushort) (depth[k] * depthScale);
844 zVals = zVals16;
845 zBytes = 2;
846 }
847 else {
848 GLint k;
849 for (k = 0; k < width; k++)
850 zVals32[k] = (GLuint) (depth[k] * depthScale);
851 zVals = zVals32;
852 zBytes = 4;
853 }
854
855 /* Write values */
856 if (zoom) {
857 _swrast_write_zoomed_z_span(ctx, destX, destY, width,
858 destX, dy, zVals);
859 }
860 else {
861 _swrast_put_row(ctx, depthDrawRb, width, destX, dy, zVals, zBytes);
862 }
863 }
864 }
865
866 if (tempStencilImage)
867 _mesa_free(tempStencilImage);
868
869 if (tempDepthImage)
870 _mesa_free(tempDepthImage);
871 }
872
873
874 /**
875 * Do software-based glCopyPixels.
876 * By time we get here, all parameters will have been error-checked.
877 */
878 void
879 _swrast_CopyPixels( GLcontext *ctx,
880 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
881 GLint destx, GLint desty, GLenum type )
882 {
883 SWcontext *swrast = SWRAST_CONTEXT(ctx);
884 RENDER_START(swrast,ctx);
885
886 if (swrast->NewState)
887 _swrast_validate_derived( ctx );
888
889 switch (type) {
890 case GL_COLOR:
891 if (ctx->Visual.rgbMode) {
892 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
893 }
894 else {
895 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
896 }
897 break;
898 case GL_DEPTH:
899 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
900 break;
901 case GL_STENCIL:
902 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
903 break;
904 case GL_DEPTH_STENCIL_EXT:
905 copy_depth_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
906 break;
907 default:
908 _mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
909 }
910
911 RENDER_FINISH(swrast,ctx);
912 }