s_copypix.c revision e4b2356c07d31fbeeabb13b2fb47db703b473080
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.3 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 struct gl_renderbuffer *drawRb = NULL; 135 GLboolean quick_draw; 136 GLint row; 137 GLboolean changeBuffer; 138 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 139 const GLuint transferOps = ctx->_ImageTransferState; 140 GLfloat *dest, *tmpImage, *convImage; 141 struct sw_span span; 142 143 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 144 145 if (ctx->Depth.Test) 146 _swrast_span_default_z(ctx, &span); 147 if (ctx->Fog.Enabled) 148 _swrast_span_default_fog(ctx, &span); 149 150 151 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 152 && !zoom 153 && destx >= 0 154 && destx + width <= (GLint) ctx->DrawBuffer->Width) { 155 quick_draw = GL_TRUE; 156 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0]; 157 } 158 else { 159 quick_draw = GL_FALSE; 160 } 161 162 /* If read and draw buffer are different we must do buffer switching */ 163 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] 164 || ctx->DrawBuffer != ctx->ReadBuffer; 165 166 167 /* allocate space for GLfloat image */ 168 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 169 if (!tmpImage) { 170 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 171 return; 172 } 173 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 174 if (!convImage) { 175 FREE(tmpImage); 176 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 177 return; 178 } 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->_ColorReadBuffer, 191 width, srcx, srcy + row, rgba); 192 chan_span_to_float(width, (CONST GLchan (*)[4]) rgba, 193 (GLfloat (*)[4]) dest); 194 dest += 4 * width; 195 } 196 197 if (changeBuffer) { 198 /* restore default src/dst buffer */ 199 _swrast_use_draw_buffer(ctx); 200 } 201 202 /* do the image transfer ops which preceed convolution */ 203 for (row = 0; row < height; row++) { 204 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); 205 _mesa_apply_rgba_transfer_ops(ctx, 206 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 207 width, rgba); 208 } 209 210 /* do convolution */ 211 if (ctx->Pixel.Convolution2DEnabled) { 212 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 213 } 214 else { 215 ASSERT(ctx->Pixel.Separable2DEnabled); 216 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 217 } 218 FREE(tmpImage); 219 220 /* do remaining post-convolution image transfer ops */ 221 for (row = 0; row < height; row++) { 222 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); 223 _mesa_apply_rgba_transfer_ops(ctx, 224 transferOps & IMAGE_POST_CONVOLUTION_BITS, 225 width, rgba); 226 } 227 228 /* write the new image */ 229 for (row = 0; row < height; row++) { 230 const GLfloat *src = convImage + row * width * 4; 231 GLint dy; 232 233 /* convert floats back to chan */ 234 float_span_to_chan(width, (const GLfloat (*)[4]) src, span.array->rgba); 235 236 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { 237 span.end = width; 238 _swrast_pixel_texture(ctx, &span); 239 } 240 241 /* write row to framebuffer */ 242 243 dy = desty + row; 244 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { 245#if OLD_RENDERBUFFER 246 if (swrast->Driver.WriteRGBASpan) 247 swrast->Driver.WriteRGBASpan(ctx, drawRb, width, destx, dy, 248 (const GLchan (*)[4]) span.array->rgba, NULL); 249 else 250#endif 251 drawRb->PutRow(ctx, drawRb, width, destx, dy, 252 span.array->rgba, NULL); 253 } 254 else if (zoom) { 255 span.x = destx; 256 span.y = dy; 257 span.end = width; 258 _swrast_write_zoomed_rgba_span(ctx, &span, 259 (CONST GLchan (*)[4])span.array->rgba, 260 desty, 0); 261 } 262 else { 263 span.x = destx; 264 span.y = dy; 265 span.end = width; 266 _swrast_write_rgba_span(ctx, &span); 267 } 268 } 269 270 FREE(convImage); 271} 272 273 274/* 275 * RGBA copypixels 276 */ 277static void 278copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 279 GLint width, GLint height, GLint destx, GLint desty) 280{ 281 SWcontext *swrast = SWRAST_CONTEXT(ctx); 282 struct gl_renderbuffer *drawRb; 283 GLchan *tmpImage,*p; 284 GLboolean quick_draw; 285 GLint sy, dy, stepy, j; 286 GLboolean changeBuffer; 287 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 288 GLint overlapping; 289 const GLuint transferOps = ctx->_ImageTransferState; 290 struct sw_span span; 291 292 if (!ctx->ReadBuffer->_ColorReadBuffer) { 293 /* no readbuffer - OK */ 294 return; 295 } 296 297 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 298 299 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 300 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); 301 return; 302 } 303 304 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 305 if (srcy < desty) { 306 /* top-down max-to-min */ 307 sy = srcy + height - 1; 308 dy = desty + height - 1; 309 stepy = -1; 310 } 311 else { 312 /* bottom-up min-to-max */ 313 sy = srcy; 314 dy = desty; 315 stepy = 1; 316 } 317 318 if (ctx->DrawBuffer == ctx->ReadBuffer) { 319 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 320 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 321 } 322 else { 323 overlapping = GL_FALSE; 324 } 325 326 if (ctx->Depth.Test) 327 _swrast_span_default_z(ctx, &span); 328 if (ctx->Fog.Enabled) 329 _swrast_span_default_fog(ctx, &span); 330 331 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 332 && !zoom 333 && destx >= 0 334 && destx + width <= (GLint) ctx->DrawBuffer->Width) { 335 quick_draw = GL_TRUE; 336 drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0][0]; 337 } 338 else { 339 quick_draw = GL_FALSE; 340 drawRb = NULL; 341 } 342 343 /* If read and draw buffer are different we must do buffer switching */ 344 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] 345 || ctx->DrawBuffer != ctx->ReadBuffer; 346 347 if (overlapping) { 348 GLint ssy = sy; 349 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); 350 if (!tmpImage) { 351 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 352 return; 353 } 354 /* setup source */ 355 if (changeBuffer) 356 _swrast_use_read_buffer(ctx); 357 /* read the source image */ 358 p = tmpImage; 359 for (j = 0; j < height; j++, ssy += stepy) { 360 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 361 width, srcx, ssy, (GLchan (*)[4]) p ); 362 p += width * 4; 363 } 364 p = tmpImage; 365 /* restore dest */ 366 if (changeBuffer) { 367 _swrast_use_draw_buffer(ctx); 368 changeBuffer = GL_FALSE; 369 } 370 } 371 else { 372 tmpImage = NULL; /* silence compiler warnings */ 373 p = NULL; 374 } 375 376 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 377 /* Get source pixels */ 378 if (overlapping) { 379 /* get from buffered image */ 380 ASSERT(width < MAX_WIDTH); 381 MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4); 382 p += width * 4; 383 } 384 else { 385 /* get from framebuffer */ 386 if (changeBuffer) 387 _swrast_use_read_buffer(ctx); 388 ASSERT(width < MAX_WIDTH); 389 _swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 390 width, srcx, sy, span.array->rgba ); 391 if (changeBuffer) 392 _swrast_use_draw_buffer(ctx); 393 } 394 395 if (transferOps) { 396 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */ 397 CHECKARRAY(rgbaFloat, return); 398 399 /* convert to float, transfer, convert back to chan */ 400 chan_span_to_float(width, (CONST GLchan (*)[4]) span.array->rgba, 401 rgbaFloat); 402 _mesa_apply_rgba_transfer_ops(ctx, transferOps, width, rgbaFloat); 403 float_span_to_chan(width, (CONST GLfloat (*)[4]) rgbaFloat, 404 span.array->rgba); 405 406 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */ 407 } 408 409 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { 410 span.end = width; 411 _swrast_pixel_texture(ctx, &span); 412 } 413 414 /* Write color span */ 415 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { 416#if OLD_RENDERBUFFER 417 if (swrast->Driver.WriteRGBASpan) 418 swrast->Driver.WriteRGBASpan(ctx, drawRb, width, destx, dy, 419 (const GLchan (*)[4])span.array->rgba, NULL); 420 else 421#endif 422 drawRb->PutRow(ctx, drawRb, width, destx, dy, span.array->rgba, NULL); 423 424 } 425 else if (zoom) { 426 span.x = destx; 427 span.y = dy; 428 span.end = width; 429 _swrast_write_zoomed_rgba_span(ctx, &span, 430 (CONST GLchan (*)[4]) span.array->rgba, 431 desty, 0); 432 } 433 else { 434 span.x = destx; 435 span.y = dy; 436 span.end = width; 437 _swrast_write_rgba_span(ctx, &span); 438 } 439 } 440 441 if (overlapping) 442 FREE(tmpImage); 443} 444 445 446static void 447copy_ci_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 448 GLint width, GLint height, 449 GLint destx, GLint desty ) 450{ 451 GLuint *tmpImage,*p; 452 GLint sy, dy, stepy; 453 GLint j; 454 GLboolean changeBuffer; 455 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 456 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 457 GLint overlapping; 458 struct sw_span span; 459 460 if (!ctx->ReadBuffer->_ColorReadBuffer) { 461 /* no readbuffer - OK */ 462 return; 463 } 464 465 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); 466 467 /* Determine if copy should be bottom-to-top or top-to-bottom */ 468 if (srcy<desty) { 469 /* top-down max-to-min */ 470 sy = srcy + height - 1; 471 dy = desty + height - 1; 472 stepy = -1; 473 } 474 else { 475 /* bottom-up min-to-max */ 476 sy = srcy; 477 dy = desty; 478 stepy = 1; 479 } 480 481 if (ctx->DrawBuffer == ctx->ReadBuffer) { 482 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 483 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 484 } 485 else { 486 overlapping = GL_FALSE; 487 } 488 489 if (ctx->Depth.Test) 490 _swrast_span_default_z(ctx, &span); 491 if (ctx->Fog.Enabled) 492 _swrast_span_default_fog(ctx, &span); 493 494 /* If read and draw buffer are different we must do buffer switching */ 495 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer[0] 496 || ctx->DrawBuffer != ctx->ReadBuffer; 497 498 if (overlapping) { 499 GLint ssy = sy; 500 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); 501 if (!tmpImage) { 502 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 503 return; 504 } 505 /* setup source */ 506 if (changeBuffer) 507 _swrast_use_read_buffer(ctx); 508 /* read the image */ 509 p = tmpImage; 510 for (j = 0; j < height; j++, ssy += stepy) { 511 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 512 width, srcx, ssy, p ); 513 p += width; 514 } 515 p = tmpImage; 516 /* restore to draw buffer */ 517 if (changeBuffer) { 518 _swrast_use_draw_buffer(ctx); 519 changeBuffer = GL_FALSE; 520 } 521 } 522 else { 523 tmpImage = NULL; /* silence compiler warning */ 524 p = NULL; 525 } 526 527 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 528 /* Get color indexes */ 529 if (overlapping) { 530 MEMCPY(span.array->index, p, width * sizeof(GLuint)); 531 p += width; 532 } 533 else { 534 if (changeBuffer) 535 _swrast_use_read_buffer(ctx); 536 _swrast_read_index_span( ctx, ctx->ReadBuffer->_ColorReadBuffer, 537 width, srcx, sy, span.array->index ); 538 if (changeBuffer) 539 _swrast_use_draw_buffer(ctx); 540 } 541 542 /* Apply shift, offset, look-up table */ 543 if (shift_or_offset) { 544 _mesa_shift_and_offset_ci( ctx, width, span.array->index ); 545 } 546 if (ctx->Pixel.MapColorFlag) { 547 _mesa_map_ci( ctx, width, span.array->index ); 548 } 549 550 /* write color indexes */ 551 span.x = destx; 552 span.y = dy; 553 span.end = width; 554 if (zoom) 555 _swrast_write_zoomed_index_span(ctx, &span, desty, 0); 556 else 557 _swrast_write_index_span(ctx, &span); 558 } 559 560 if (overlapping) 561 FREE(tmpImage); 562} 563 564 565 566/* 567 * TODO: Optimize!!!! 568 */ 569static void 570copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 571 GLint width, GLint height, 572 GLint destx, GLint desty ) 573{ 574 const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF; 575 struct gl_renderbuffer *readRb 576 = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; 577 GLfloat *p, *tmpImage; 578 GLint sy, dy, stepy; 579 GLint i, j; 580 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 581 GLint overlapping; 582 struct sw_span span; 583 584 if (!readRb) { 585 /* no readbuffer - OK */ 586 return; 587 } 588 589 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); 590 591 if (!ctx->Visual.depthBits) { 592 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 593 return; 594 } 595 596 /* Determine if copy should be bottom-to-top or top-to-bottom */ 597 if (srcy<desty) { 598 /* top-down max-to-min */ 599 sy = srcy + height - 1; 600 dy = desty + height - 1; 601 stepy = -1; 602 } 603 else { 604 /* bottom-up min-to-max */ 605 sy = srcy; 606 dy = desty; 607 stepy = 1; 608 } 609 610 if (ctx->DrawBuffer == ctx->ReadBuffer) { 611 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 612 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 613 } 614 else { 615 overlapping = GL_FALSE; 616 } 617 618 _swrast_span_default_color(ctx, &span); 619 if (ctx->Fog.Enabled) 620 _swrast_span_default_fog(ctx, &span); 621 622 if (overlapping) { 623 GLint ssy = sy; 624 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); 625 if (!tmpImage) { 626 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 627 return; 628 } 629 p = tmpImage; 630 for (j = 0; j < height; j++, ssy += stepy) { 631 _swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p); 632 p += width; 633 } 634 p = tmpImage; 635 } 636 else { 637 tmpImage = NULL; /* silence compiler warning */ 638 p = NULL; 639 } 640 641 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 642 GLfloat depth[MAX_WIDTH]; 643 float sum = 0; 644 /* get depth values */ 645 if (overlapping) { 646 MEMCPY(depth, p, width * sizeof(GLfloat)); 647 p += width; 648 } 649 else { 650 _swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth); 651 } 652 653 /* apply scale and bias */ 654 for (i = 0; i < width; i++) { 655 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 656 sum += d; 657 span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * depthMax); 658 } 659 660 /* write depth values */ 661 span.x = destx; 662 span.y = dy; 663 span.end = width; 664 if (ctx->Visual.rgbMode) { 665 if (zoom) 666 _swrast_write_zoomed_rgba_span( ctx, &span, 667 (const GLchan (*)[4])span.array->rgba, desty, 0 ); 668 else 669 _swrast_write_rgba_span(ctx, &span); 670 } 671 else { 672 if (zoom) 673 _swrast_write_zoomed_index_span( ctx, &span, desty, 0 ); 674 else 675 _swrast_write_index_span(ctx, &span); 676 } 677 } 678 679 if (overlapping) 680 FREE(tmpImage); 681} 682 683 684 685static void 686copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 687 GLint width, GLint height, 688 GLint destx, GLint desty ) 689{ 690 struct gl_renderbuffer *rb 691 = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; 692 GLint sy, dy, stepy; 693 GLint j; 694 GLstencil *p, *tmpImage; 695 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 696 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 697 GLint overlapping; 698 699 if (!ctx->Visual.stencilBits) { 700 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 701 return; 702 } 703 704 if (!rb) { 705 /* no readbuffer - OK */ 706 return; 707 } 708 709 /* Determine if copy should be bottom-to-top or top-to-bottom */ 710 if (srcy < desty) { 711 /* top-down max-to-min */ 712 sy = srcy + height - 1; 713 dy = desty + height - 1; 714 stepy = -1; 715 } 716 else { 717 /* bottom-up min-to-max */ 718 sy = srcy; 719 dy = desty; 720 stepy = 1; 721 } 722 723 if (ctx->DrawBuffer == ctx->ReadBuffer) { 724 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 725 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 726 } 727 else { 728 overlapping = GL_FALSE; 729 } 730 731 if (overlapping) { 732 GLint ssy = sy; 733 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil)); 734 if (!tmpImage) { 735 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 736 return; 737 } 738 p = tmpImage; 739 for (j = 0; j < height; j++, ssy += stepy) { 740 _swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p ); 741 p += width; 742 } 743 p = tmpImage; 744 } 745 else { 746 tmpImage = NULL; /* silence compiler warning */ 747 p = NULL; 748 } 749 750 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 751 GLstencil stencil[MAX_WIDTH]; 752 753 /* Get stencil values */ 754 if (overlapping) { 755 MEMCPY(stencil, p, width * sizeof(GLstencil)); 756 p += width; 757 } 758 else { 759 _swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil ); 760 } 761 762 /* Apply shift, offset, look-up table */ 763 if (shift_or_offset) { 764 _mesa_shift_and_offset_stencil( ctx, width, stencil ); 765 } 766 if (ctx->Pixel.MapStencilFlag) { 767 _mesa_map_stencil( ctx, width, stencil ); 768 } 769 770 /* Write stencil values */ 771 if (zoom) { 772 _swrast_write_zoomed_stencil_span( ctx, width, destx, dy, 773 stencil, desty, 0 ); 774 } 775 else { 776 _swrast_write_stencil_span( ctx, width, destx, dy, stencil ); 777 } 778 } 779 780 if (overlapping) 781 FREE(tmpImage); 782} 783 784 785 786void 787_swrast_CopyPixels( GLcontext *ctx, 788 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 789 GLint destx, GLint desty, 790 GLenum type ) 791{ 792 SWcontext *swrast = SWRAST_CONTEXT(ctx); 793 RENDER_START(swrast,ctx); 794 795 if (swrast->NewState) 796 _swrast_validate_derived( ctx ); 797 798 if (type == GL_COLOR && ctx->Visual.rgbMode) { 799 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 800 } 801 else if (type == GL_COLOR && !ctx->Visual.rgbMode) { 802 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 803 } 804 else if (type == GL_DEPTH) { 805 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 806 } 807 else if (type == GL_STENCIL) { 808 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 809 } 810 else { 811 _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); 812 } 813 814 RENDER_FINISH(swrast,ctx); 815} 816