s_copypix.c revision 4663bd50f1e2f219bd1b2a4d902b11b936512398
1/* $Id: s_copypix.c,v 1.42 2002/10/30 20:16:43 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 5.0 6 * 7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#include "glheader.h" 29#include "colormac.h" 30#include "context.h" 31#include "convolve.h" 32#include "feedback.h" 33#include "macros.h" 34#include "imports.h" 35#include "mmath.h" 36#include "pixel.h" 37 38#include "s_context.h" 39#include "s_depth.h" 40#include "s_histogram.h" 41#include "s_pixeltex.h" 42#include "s_span.h" 43#include "s_stencil.h" 44#include "s_texture.h" 45#include "s_zoom.h" 46 47 48 49/* 50 * Determine if there's overlap in an image copy. 51 * This test also compensates for the fact that copies are done from 52 * bottom to top and overlaps can sometimes be handled correctly 53 * without making a temporary image copy. 54 */ 55static GLboolean 56regions_overlap(GLint srcx, GLint srcy, 57 GLint dstx, GLint dsty, 58 GLint width, GLint height, 59 GLfloat zoomX, GLfloat zoomY) 60{ 61 if (zoomX == 1.0 && zoomY == 1.0) { 62 /* no zoom */ 63 if (srcx >= dstx + width || (srcx + width <= dstx)) { 64 return GL_FALSE; 65 } 66 else if (srcy < dsty) { /* this is OK */ 67 return GL_FALSE; 68 } 69 else if (srcy > dsty + height) { 70 return GL_FALSE; 71 } 72 else { 73 return GL_TRUE; 74 } 75 } 76 else { 77 /* add one pixel of slop when zooming, just to be safe */ 78 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { 79 return GL_FALSE; 80 } 81 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { 82 return GL_FALSE; 83 } 84 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { 85 return GL_FALSE; 86 } 87 else { 88 return GL_TRUE; 89 } 90 } 91} 92 93 94 95/* 96 * RGBA copypixels with convolution. 97 */ 98static void 99copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 100 GLint width, GLint height, GLint destx, GLint desty) 101{ 102 SWcontext *swrast = SWRAST_CONTEXT(ctx); 103 GLboolean quick_draw; 104 GLint row; 105 GLboolean changeBuffer; 106 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 107 const GLuint transferOps = ctx->_ImageTransferState; 108 GLfloat *dest, *tmpImage, *convImage; 109 struct sw_span span; 110 111 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 112 113 if (ctx->Depth.Test) 114 _mesa_span_default_z(ctx, &span); 115 if (ctx->Fog.Enabled) 116 _mesa_span_default_fog(ctx, &span); 117 118 119 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 120 && !zoom 121 && destx >= 0 122 && destx + width <= (GLint) ctx->DrawBuffer->Width) { 123 quick_draw = GL_TRUE; 124 } 125 else { 126 quick_draw = GL_FALSE; 127 } 128 129 /* If read and draw buffer are different we must do buffer switching */ 130 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 131 || ctx->DrawBuffer != ctx->ReadBuffer; 132 133 134 /* allocate space for GLfloat image */ 135 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 136 if (!tmpImage) { 137 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 138 return; 139 } 140 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 141 if (!convImage) { 142 FREE(tmpImage); 143 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 144 return; 145 } 146 147 dest = tmpImage; 148 149 if (changeBuffer) { 150 /* choose the read buffer */ 151 _swrast_use_read_buffer(ctx); 152 } 153 154 /* read source image */ 155 dest = tmpImage; 156 for (row = 0; row < height; row++) { 157 GLchan rgba[MAX_WIDTH][4]; 158 GLint i; 159 _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba); 160 /* convert GLchan to GLfloat */ 161 for (i = 0; i < width; i++) { 162 *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF); 163 *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF); 164 *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF); 165 *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF); 166 } 167 } 168 169 if (changeBuffer) { 170 /* restore default src/dst buffer */ 171 _swrast_use_draw_buffer(ctx); 172 } 173 174 /* do image transfer ops up until convolution */ 175 for (row = 0; row < height; row++) { 176 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); 177 178 /* scale & bias */ 179 if (transferOps & IMAGE_SCALE_BIAS_BIT) { 180 _mesa_scale_and_bias_rgba(ctx, width, rgba, 181 ctx->Pixel.RedScale, ctx->Pixel.GreenScale, 182 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, 183 ctx->Pixel.RedBias, ctx->Pixel.GreenBias, 184 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); 185 } 186 /* color map lookup */ 187 if (transferOps & IMAGE_MAP_COLOR_BIT) { 188 _mesa_map_rgba(ctx, width, rgba); 189 } 190 /* GL_COLOR_TABLE lookup */ 191 if (transferOps & IMAGE_COLOR_TABLE_BIT) { 192 _mesa_lookup_rgba(&ctx->ColorTable, width, rgba); 193 } 194 } 195 196 /* do convolution */ 197 if (ctx->Pixel.Convolution2DEnabled) { 198 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 199 } 200 else { 201 ASSERT(ctx->Pixel.Separable2DEnabled); 202 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 203 } 204 FREE(tmpImage); 205 206 /* do remaining image transfer ops */ 207 for (row = 0; row < height; row++) { 208 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); 209 210 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ 211 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { 212 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba); 213 } 214 /* color matrix */ 215 if (transferOps & IMAGE_COLOR_MATRIX_BIT) { 216 _mesa_transform_rgba(ctx, width, rgba); 217 } 218 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ 219 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { 220 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba); 221 } 222 /* update histogram count */ 223 if (transferOps & IMAGE_HISTOGRAM_BIT) { 224 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba); 225 } 226 /* update min/max */ 227 if (transferOps & IMAGE_MIN_MAX_BIT) { 228 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba); 229 } 230 } 231 232 for (row = 0; row < height; row++) { 233 const GLfloat *src = convImage + row * width * 4; 234 GLint i, dy; 235 236 /* clamp to [0,1] and convert float back to chan */ 237 for (i = 0; i < width; i++) { 238 GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF); 239 GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF); 240 GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF); 241 GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF); 242 span.array->rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); 243 span.array->rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); 244 span.array->rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); 245 span.array->rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); 246 } 247 248 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { 249 span.end = width; 250 _swrast_pixel_texture(ctx, &span); 251 } 252 253 /* write row to framebuffer */ 254 255 dy = desty + row; 256 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { 257 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, 258 (const GLchan (*)[4])span.array->rgba, NULL ); 259 } 260 else if (zoom) { 261 span.x = destx; 262 span.y = dy; 263 span.end = width; 264 _mesa_write_zoomed_rgba_span(ctx, &span, 265 (CONST GLchan (*)[4])span.array->rgba, 266 desty); 267 } 268 else { 269 span.x = destx; 270 span.y = dy; 271 span.end = width; 272 _mesa_write_rgba_span(ctx, &span); 273 } 274 } 275 276 FREE(convImage); 277} 278 279 280/* 281 * RGBA copypixels 282 */ 283static void 284copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 285 GLint width, GLint height, GLint destx, GLint desty) 286{ 287 SWcontext *swrast = SWRAST_CONTEXT(ctx); 288 GLchan *tmpImage,*p; 289 GLboolean quick_draw; 290 GLint sy, dy, stepy, j; 291 GLboolean changeBuffer; 292 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 293 GLint overlapping; 294 const GLuint transferOps = ctx->_ImageTransferState; 295 struct sw_span span; 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 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 319 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 320 321 if (ctx->Depth.Test) 322 _mesa_span_default_z(ctx, &span); 323 if (ctx->Fog.Enabled) 324 _mesa_span_default_fog(ctx, &span); 325 326 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 327 && !zoom 328 && destx >= 0 329 && destx + width <= (GLint) ctx->DrawBuffer->Width) { 330 quick_draw = GL_TRUE; 331 } 332 else { 333 quick_draw = GL_FALSE; 334 } 335 336 /* If read and draw buffer are different we must do buffer switching */ 337 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 338 || ctx->DrawBuffer != ctx->ReadBuffer; 339 340 if (overlapping) { 341 GLint ssy = sy; 342 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); 343 if (!tmpImage) { 344 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 345 return; 346 } 347 /* setup source */ 348 if (changeBuffer) 349 _swrast_use_read_buffer(ctx); 350 /* read the source image */ 351 p = tmpImage; 352 for (j = 0; j < height; j++, ssy += stepy) { 353 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy, 354 (GLchan (*)[4]) p ); 355 p += width * 4; 356 } 357 p = tmpImage; 358 /* restore dest */ 359 if (changeBuffer) { 360 _swrast_use_draw_buffer(ctx); 361 changeBuffer = GL_FALSE; 362 } 363 } 364 else { 365 tmpImage = NULL; /* silence compiler warnings */ 366 p = NULL; 367 } 368 369 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 370 /* Get source pixels */ 371 if (overlapping) { 372 /* get from buffered image */ 373 MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4); 374 p += width * 4; 375 } 376 else { 377 /* get from framebuffer */ 378 if (changeBuffer) 379 _swrast_use_read_buffer(ctx); 380 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, 381 span.array->rgba ); 382 if (changeBuffer) 383 _swrast_use_draw_buffer(ctx); 384 } 385 386 if (transferOps) { 387 const GLfloat scale = (1.0F / CHAN_MAXF); 388 GLint k; 389 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */ 390 CHECKARRAY(rgbaFloat, return); 391 392 /* convert chan to float */ 393 for (k = 0; k < width; k++) { 394 rgbaFloat[k][RCOMP] = (GLfloat) span.array->rgba[k][RCOMP] * scale; 395 rgbaFloat[k][GCOMP] = (GLfloat) span.array->rgba[k][GCOMP] * scale; 396 rgbaFloat[k][BCOMP] = (GLfloat) span.array->rgba[k][BCOMP] * scale; 397 rgbaFloat[k][ACOMP] = (GLfloat) span.array->rgba[k][ACOMP] * scale; 398 } 399 /* scale & bias */ 400 if (transferOps & IMAGE_SCALE_BIAS_BIT) { 401 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, 402 ctx->Pixel.RedScale, ctx->Pixel.GreenScale, 403 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, 404 ctx->Pixel.RedBias, ctx->Pixel.GreenBias, 405 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); 406 } 407 /* color map lookup */ 408 if (transferOps & IMAGE_MAP_COLOR_BIT) { 409 _mesa_map_rgba(ctx, width, rgbaFloat); 410 } 411 /* GL_COLOR_TABLE lookup */ 412 if (transferOps & IMAGE_COLOR_TABLE_BIT) { 413 _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat); 414 } 415 /* convolution */ 416 if (transferOps & IMAGE_CONVOLUTION_BIT) { 417 _mesa_problem(ctx, "Convolution should not be enabled in copy_rgba_pixels()"); 418 return; 419 } 420 /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */ 421 if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) { 422 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, 423 ctx->Pixel.PostConvolutionScale[RCOMP], 424 ctx->Pixel.PostConvolutionScale[GCOMP], 425 ctx->Pixel.PostConvolutionScale[BCOMP], 426 ctx->Pixel.PostConvolutionScale[ACOMP], 427 ctx->Pixel.PostConvolutionBias[RCOMP], 428 ctx->Pixel.PostConvolutionBias[GCOMP], 429 ctx->Pixel.PostConvolutionBias[BCOMP], 430 ctx->Pixel.PostConvolutionBias[ACOMP]); 431 } 432 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ 433 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { 434 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat); 435 } 436 /* color matrix */ 437 if (transferOps & IMAGE_COLOR_MATRIX_BIT) { 438 _mesa_transform_rgba(ctx, width, rgbaFloat); 439 } 440 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ 441 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { 442 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat); 443 } 444 /* update histogram count */ 445 if (transferOps & IMAGE_HISTOGRAM_BIT) { 446 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); 447 } 448 /* update min/max */ 449 if (transferOps & IMAGE_MIN_MAX_BIT) { 450 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); 451 } 452 /* clamp to [0,1] and convert float back to chan */ 453 for (k = 0; k < width; k++) { 454 GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF); 455 GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF); 456 GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF); 457 GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF); 458 span.array->rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); 459 span.array->rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); 460 span.array->rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); 461 span.array->rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); 462 } 463 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */ 464 } 465 466 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { 467 span.end = width; 468 _swrast_pixel_texture(ctx, &span); 469 } 470 471 if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { 472 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, 473 (const GLchan (*)[4])span.array->rgba, NULL ); 474 } 475 else if (zoom) { 476 span.x = destx; 477 span.y = dy; 478 span.end = width; 479 _mesa_write_zoomed_rgba_span(ctx, &span, 480 (CONST GLchan (*)[4]) span.array->rgba, 481 desty); 482 } 483 else { 484 span.x = destx; 485 span.y = dy; 486 span.end = width; 487 _mesa_write_rgba_span(ctx, &span); 488 } 489 } 490 491 if (overlapping) 492 FREE(tmpImage); 493} 494 495 496static void copy_ci_pixels( GLcontext *ctx, 497 GLint srcx, GLint srcy, GLint width, GLint height, 498 GLint destx, GLint desty ) 499{ 500 GLuint *tmpImage,*p; 501 GLint sy, dy, stepy; 502 GLint j; 503 GLboolean changeBuffer; 504 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 505 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 506 GLint overlapping; 507 struct sw_span span; 508 509 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); 510 511 /* Determine if copy should be bottom-to-top or top-to-bottom */ 512 if (srcy<desty) { 513 /* top-down max-to-min */ 514 sy = srcy + height - 1; 515 dy = desty + height - 1; 516 stepy = -1; 517 } 518 else { 519 /* bottom-up min-to-max */ 520 sy = srcy; 521 dy = desty; 522 stepy = 1; 523 } 524 525 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 526 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 527 528 if (ctx->Depth.Test) 529 _mesa_span_default_z(ctx, &span); 530 if (ctx->Fog.Enabled) 531 _mesa_span_default_fog(ctx, &span); 532 533 /* If read and draw buffer are different we must do buffer switching */ 534 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 535 || ctx->DrawBuffer != ctx->ReadBuffer; 536 537 if (overlapping) { 538 GLint ssy = sy; 539 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); 540 if (!tmpImage) { 541 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 542 return; 543 } 544 /* setup source */ 545 if (changeBuffer) 546 _swrast_use_read_buffer(ctx); 547 /* read the image */ 548 p = tmpImage; 549 for (j = 0; j < height; j++, ssy += stepy) { 550 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p ); 551 p += width; 552 } 553 p = tmpImage; 554 /* restore to draw buffer */ 555 if (changeBuffer) { 556 _swrast_use_draw_buffer(ctx); 557 changeBuffer = GL_FALSE; 558 } 559 } 560 else { 561 tmpImage = NULL; /* silence compiler warning */ 562 p = NULL; 563 } 564 565 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 566 if (overlapping) { 567 MEMCPY(span.array->index, p, width * sizeof(GLuint)); 568 p += width; 569 } 570 else { 571 if (changeBuffer) 572 _swrast_use_read_buffer(ctx); 573 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, 574 span.array->index ); 575 if (changeBuffer) 576 _swrast_use_draw_buffer(ctx); 577 } 578 579 if (shift_or_offset) { 580 _mesa_shift_and_offset_ci( ctx, width, span.array->index ); 581 } 582 if (ctx->Pixel.MapColorFlag) { 583 _mesa_map_ci( ctx, width, span.array->index ); 584 } 585 586 span.x = destx; 587 span.y = dy; 588 span.end = width; 589 if (zoom) 590 _mesa_write_zoomed_index_span(ctx, &span, desty); 591 else 592 _mesa_write_index_span(ctx, &span); 593 } 594 595 if (overlapping) 596 FREE(tmpImage); 597} 598 599 600 601/* 602 * TODO: Optimize!!!! 603 */ 604static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 605 GLint width, GLint height, 606 GLint destx, GLint desty ) 607{ 608 GLfloat depth[MAX_WIDTH]; 609 GLfloat *p, *tmpImage; 610 GLint sy, dy, stepy; 611 GLint i, j; 612 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 613 GLint overlapping; 614 struct sw_span span; 615 616 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); 617 618 if (!ctx->Visual.depthBits) { 619 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 620 return; 621 } 622 623 /* Determine if copy should be bottom-to-top or top-to-bottom */ 624 if (srcy<desty) { 625 /* top-down max-to-min */ 626 sy = srcy + height - 1; 627 dy = desty + height - 1; 628 stepy = -1; 629 } 630 else { 631 /* bottom-up min-to-max */ 632 sy = srcy; 633 dy = desty; 634 stepy = 1; 635 } 636 637 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 638 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 639 640 _mesa_span_default_color(ctx, &span); 641 if (ctx->Fog.Enabled) 642 _mesa_span_default_fog(ctx, &span); 643 644 if (overlapping) { 645 GLint ssy = sy; 646 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); 647 if (!tmpImage) { 648 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 649 return; 650 } 651 p = tmpImage; 652 for (j = 0; j < height; j++, ssy += stepy) { 653 _mesa_read_depth_span_float(ctx, width, srcx, ssy, p); 654 p += width; 655 } 656 p = tmpImage; 657 } 658 else { 659 tmpImage = NULL; /* silence compiler warning */ 660 p = NULL; 661 } 662 663 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 664 if (overlapping) { 665 MEMCPY(depth, p, width * sizeof(GLfloat)); 666 p += width; 667 } 668 else { 669 _mesa_read_depth_span_float(ctx, width, srcx, sy, depth); 670 } 671 672 for (i = 0; i < width; i++) { 673 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 674 span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax); 675 } 676 677 span.x = destx; 678 span.y = dy; 679 span.end = width; 680 if (ctx->Visual.rgbMode) { 681 if (zoom) 682 _mesa_write_zoomed_rgba_span( ctx, &span, 683 (const GLchan (*)[4])span.array->rgba, 684 desty ); 685 else 686 _mesa_write_rgba_span(ctx, &span); 687 } 688 else { 689 if (zoom) 690 _mesa_write_zoomed_index_span( ctx, &span, desty ); 691 else 692 _mesa_write_index_span(ctx, &span); 693 } 694 } 695 696 if (overlapping) 697 FREE(tmpImage); 698} 699 700 701 702static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 703 GLint width, GLint height, 704 GLint destx, GLint desty ) 705{ 706 GLint sy, dy, stepy; 707 GLint j; 708 GLstencil *p, *tmpImage; 709 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 710 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 711 GLint overlapping; 712 713 if (!ctx->Visual.stencilBits) { 714 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 715 return; 716 } 717 718 /* Determine if copy should be bottom-to-top or top-to-bottom */ 719 if (srcy < desty) { 720 /* top-down max-to-min */ 721 sy = srcy + height - 1; 722 dy = desty + height - 1; 723 stepy = -1; 724 } 725 else { 726 /* bottom-up min-to-max */ 727 sy = srcy; 728 dy = desty; 729 stepy = 1; 730 } 731 732 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 733 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 734 735 if (overlapping) { 736 GLint ssy = sy; 737 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil)); 738 if (!tmpImage) { 739 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 740 return; 741 } 742 p = tmpImage; 743 for (j = 0; j < height; j++, ssy += stepy) { 744 _mesa_read_stencil_span( ctx, width, srcx, ssy, p ); 745 p += width; 746 } 747 p = tmpImage; 748 } 749 else { 750 tmpImage = NULL; /* silence compiler warning */ 751 p = NULL; 752 } 753 754 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 755 GLstencil stencil[MAX_WIDTH]; 756 757 if (overlapping) { 758 MEMCPY(stencil, p, width * sizeof(GLstencil)); 759 p += width; 760 } 761 else { 762 _mesa_read_stencil_span( ctx, width, srcx, sy, stencil ); 763 } 764 765 if (shift_or_offset) { 766 _mesa_shift_and_offset_stencil( ctx, width, stencil ); 767 } 768 if (ctx->Pixel.MapStencilFlag) { 769 _mesa_map_stencil( ctx, width, stencil ); 770 } 771 772 if (zoom) { 773 _mesa_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty ); 774 } 775 else { 776 _mesa_write_stencil_span( ctx, width, destx, dy, stencil ); 777 } 778 } 779 780 if (overlapping) 781 FREE(tmpImage); 782} 783 784 785 786 787void 788_swrast_CopyPixels( GLcontext *ctx, 789 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 790 GLint destx, GLint desty, 791 GLenum type ) 792{ 793 SWcontext *swrast = SWRAST_CONTEXT(ctx); 794 RENDER_START(swrast,ctx); 795 796 if (swrast->NewState) 797 _swrast_validate_derived( ctx ); 798 799 if (type == GL_COLOR && ctx->Visual.rgbMode) { 800 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 801 } 802 else if (type == GL_COLOR && !ctx->Visual.rgbMode) { 803 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 804 } 805 else if (type == GL_DEPTH) { 806 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 807 } 808 else if (type == GL_STENCIL) { 809 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 810 } 811 else { 812 _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); 813 } 814 815 RENDER_FINISH(swrast,ctx); 816} 817