s_copypix.c revision 4923e1926ad7b7eb7de017eda8e7db64d357e5c8
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 */ 52static GLboolean 53regions_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 */ 95static void 96float_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 */ 112static void 113chan_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 */ 129static void 130copy_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 */ 270static void 271copy_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 425static void 426copy_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 */ 542static void 543copy_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 649static void 650copy_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 743void 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} 773