s_copypix.c revision 833d96aa913dcb0c5ca085cc7ebee3df90f7fbf8
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 */ 50static GLboolean 51regions_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 */ 93static void 94copy_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 */ 247static void 248copy_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 418static void 419copy_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 */ 535static void 536copy_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 642static void 643copy_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 736void 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} 766