s_copypix.c revision df37d5f2dbf3821f6b3f24771b83ad34584ca383
1/* $Id: s_copypix.c,v 1.4 2000/11/10 18:29:18 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2000 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 "mem.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 */ 52static GLboolean 53regions_overlap(int srcx, int srcy, int dstx, int dsty, int width, int height, 54 float zoomX, float zoomY) 55{ 56 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { 57 return GL_FALSE; 58 } 59 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { 60 return GL_FALSE; 61 } 62 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { 63 return GL_FALSE; 64 } 65 else { 66 return GL_TRUE; 67 } 68} 69 70 71 72/* 73 * RGBA copypixels with convolution. 74 */ 75static void 76copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 77 GLint width, GLint height, GLint destx, GLint desty) 78{ 79 GLdepth zspan[MAX_WIDTH]; 80 GLboolean quick_draw; 81 GLint row; 82 GLboolean changeBuffer; 83 GLchan *saveReadAlpha; 84 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 85 const GLuint transferOps = ctx->_ImageTransferState; 86 GLfloat *dest, *tmpImage, *convImage; 87 88 if (ctx->Depth.Test || ctx->Fog.Enabled) { 89 /* fill in array of z values */ 90 GLdepth z = (GLdepth) 91 (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax); 92 GLint i; 93 for (i = 0; i < width; i++) { 94 zspan[i] = z; 95 } 96 } 97 98 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 99 && !zoom 100 && destx >= 0 101 && destx + width <= ctx->DrawBuffer->Width) { 102 quick_draw = GL_TRUE; 103 } 104 else { 105 quick_draw = GL_FALSE; 106 } 107 108 /* If read and draw buffer are different we must do buffer switching */ 109 saveReadAlpha = ctx->ReadBuffer->Alpha; 110 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 111 || ctx->DrawBuffer != ctx->ReadBuffer; 112 113 114 /* allocate space for GLfloat image */ 115 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 116 if (!tmpImage) { 117 gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 118 return; 119 } 120 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 121 if (!convImage) { 122 FREE(tmpImage); 123 gl_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); 124 return; 125 } 126 127 dest = tmpImage; 128 129 if (changeBuffer) { 130 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 131 ctx->Pixel.DriverReadBuffer ); 132 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) 133 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha; 134 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) 135 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha; 136 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) 137 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha; 138 else 139 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha; 140 } 141 142 /* read source image */ 143 dest = tmpImage; 144 for (row = 0; row < height; row++) { 145 GLchan rgba[MAX_WIDTH][4]; 146 GLint i; 147 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba); 148 /* convert GLchan to GLfloat */ 149 for (i = 0; i < width; i++) { 150 *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF); 151 *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF); 152 *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF); 153 *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF); 154 } 155 } 156 157 /* read from the draw buffer again (in case of blending) */ 158 if (changeBuffer) { 159 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 160 ctx->Color.DriverDrawBuffer ); 161 ctx->ReadBuffer->Alpha = saveReadAlpha; 162 } 163 164 /* do image transfer ops up until convolution */ 165 for (row = 0; row < height; row++) { 166 GLfloat (*rgba)[4] = (GLfloat (*)[4]) tmpImage + row * width * 4; 167 168 /* scale & bias */ 169 if (transferOps & IMAGE_SCALE_BIAS_BIT) { 170 _mesa_scale_and_bias_rgba(ctx, width, rgba); 171 } 172 /* color map lookup */ 173 if (transferOps & IMAGE_MAP_COLOR_BIT) { 174 _mesa_map_rgba(ctx, width, rgba); 175 } 176 /* GL_COLOR_TABLE lookup */ 177 if (transferOps & IMAGE_COLOR_TABLE_BIT) { 178 _mesa_lookup_rgba(&ctx->ColorTable, width, rgba); 179 } 180 } 181 182 /* do convolution */ 183 if (ctx->Pixel.Convolution2DEnabled) { 184 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 185 } 186 else { 187 ASSERT(ctx->Pixel.Separable2DEnabled); 188 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 189 } 190 FREE(tmpImage); 191 192 /* do remaining image transfer ops */ 193 for (row = 0; row < height; row++) { 194 GLfloat (*rgba)[4] = (GLfloat (*)[4]) convImage + row * width * 4; 195 196 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ 197 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { 198 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba); 199 } 200 /* color matrix */ 201 if (transferOps & IMAGE_COLOR_MATRIX_BIT) { 202 _mesa_transform_rgba(ctx, width, rgba); 203 } 204 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ 205 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { 206 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba); 207 } 208 /* update histogram count */ 209 if (transferOps & IMAGE_HISTOGRAM_BIT) { 210 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba); 211 } 212 /* update min/max */ 213 if (transferOps & IMAGE_MIN_MAX_BIT) { 214 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba); 215 } 216 } 217 218 for (row = 0; row < height; row++) { 219 const GLfloat *src = convImage + row * width * 4; 220 GLchan rgba[MAX_WIDTH][4]; 221 GLint i, dy; 222 223 /* clamp to [0,1] and convert float back to chan */ 224 for (i = 0; i < width; i++) { 225 GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF); 226 GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF); 227 GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF); 228 GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF); 229 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); 230 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); 231 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); 232 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); 233 } 234 235 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) { 236 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH]; 237 GLchan primary_rgba[MAX_WIDTH][4]; 238 GLuint unit; 239 /* XXX not sure how multitexture is supposed to work here */ 240 241 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan)); 242 243 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) { 244 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba, 245 s, t, r, q); 246 gl_texture_pixels(ctx, unit, width, s, t, r, NULL, 247 primary_rgba, rgba); 248 } 249 } 250 251 /* write row to framebuffer */ 252 253 dy = desty + row; 254 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) { 255 (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy, 256 (const GLchan (*)[4])rgba, NULL ); 257 } 258 else if (zoom) { 259 gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0, 260 (const GLchan (*)[4])rgba, desty); 261 } 262 else { 263 gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP ); 264 } 265 } 266 267 FREE(convImage); 268} 269 270 271/* 272 * RGBA copypixels 273 */ 274static void 275copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 276 GLint width, GLint height, GLint destx, GLint desty) 277{ 278 GLdepth zspan[MAX_WIDTH]; 279 GLchan rgba[MAX_WIDTH][4]; 280 GLchan *tmpImage,*p; 281 GLboolean quick_draw; 282 GLint sy, dy, stepy; 283 GLint i, j; 284 GLboolean changeBuffer; 285 GLchan *saveReadAlpha; 286 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 287 GLint overlapping; 288 const GLuint transferOps = ctx->_ImageTransferState; 289 290 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 291 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); 292 return; 293 } 294 295 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 296 if (srcy < desty) { 297 /* top-down max-to-min */ 298 sy = srcy + height - 1; 299 dy = desty + height - 1; 300 stepy = -1; 301 } 302 else { 303 /* bottom-up min-to-max */ 304 sy = srcy; 305 dy = desty; 306 stepy = 1; 307 } 308 309 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 310 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 311 312 if (ctx->Depth.Test || ctx->Fog.Enabled) { 313 /* fill in array of z values */ 314 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax); 315 for (i=0;i<width;i++) { 316 zspan[i] = z; 317 } 318 } 319 320 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 321 && !zoom 322 && destx >= 0 323 && destx + width <= ctx->DrawBuffer->Width) { 324 quick_draw = GL_TRUE; 325 } 326 else { 327 quick_draw = GL_FALSE; 328 } 329 330 /* If read and draw buffer are different we must do buffer switching */ 331 saveReadAlpha = ctx->ReadBuffer->Alpha; 332 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 333 || ctx->DrawBuffer != ctx->ReadBuffer; 334 335 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 336 ctx->Pixel.DriverReadBuffer ); 337 338 if (overlapping) { 339 GLint ssy = sy; 340 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); 341 if (!tmpImage) { 342 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 343 return; 344 } 345 p = tmpImage; 346 if (changeBuffer) { 347 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 348 ctx->Pixel.DriverReadBuffer ); 349 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) 350 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha; 351 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) 352 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha; 353 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) 354 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha; 355 else 356 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha; 357 } 358 for (j = 0; j < height; j++, ssy += stepy) { 359 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy, 360 (GLchan (*)[4]) p ); 361 p += (width * sizeof(GLchan) * 4); 362 } 363 p = tmpImage; 364 } 365 else { 366 tmpImage = NULL; /* silence compiler warnings */ 367 p = NULL; 368 } 369 370 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 371 /* Get source pixels */ 372 if (overlapping) { 373 /* get from buffered image */ 374 MEMCPY(rgba, p, width * sizeof(GLchan) * 4); 375 p += (width * sizeof(GLchan) * 4); 376 } 377 else { 378 /* get from framebuffer */ 379 if (changeBuffer) { 380 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 381 ctx->Pixel.DriverReadBuffer ); 382 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) { 383 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha; 384 } 385 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) { 386 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha; 387 } 388 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) { 389 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha; 390 } 391 else { 392 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha; 393 } 394 } 395 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba ); 396 } 397 398 if (changeBuffer) { 399 /* read from the draw buffer again (in case of blending) */ 400 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 401 ctx->Color.DriverDrawBuffer ); 402 ctx->ReadBuffer->Alpha = saveReadAlpha; 403 } 404 405 if (transferOps) { 406 const GLfloat scale = (1.0F / CHAN_MAXF); 407 GLfloat rgbaFloat[MAX_WIDTH][4]; 408 GLuint k; 409 /* convert chan to float */ 410 for (k = 0; k < width; k++) { 411 rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale; 412 rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale; 413 rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale; 414 rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale; 415 } 416 /* scale & bias */ 417 if (transferOps & IMAGE_SCALE_BIAS_BIT) { 418 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat); 419 } 420 /* color map lookup */ 421 if (transferOps & IMAGE_MAP_COLOR_BIT) { 422 _mesa_map_rgba(ctx, width, rgbaFloat); 423 } 424 /* GL_COLOR_TABLE lookup */ 425 if (transferOps & IMAGE_COLOR_TABLE_BIT) { 426 _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat); 427 } 428 /* convolution */ 429 if (transferOps & IMAGE_CONVOLUTION_BIT) { 430 /* XXX to do */ 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 rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); 459 rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); 460 rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); 461 rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); 462 } 463 } 464 465 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) { 466 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH]; 467 GLchan primary_rgba[MAX_WIDTH][4]; 468 GLuint unit; 469 /* XXX not sure how multitexture is supposed to work here */ 470 471 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan)); 472 473 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) { 474 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba, 475 s, t, r, q); 476 gl_texture_pixels(ctx, unit, width, s, t, r, NULL, 477 primary_rgba, rgba); 478 } 479 } 480 481 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) { 482 (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy, 483 (const GLchan (*)[4])rgba, NULL ); 484 } 485 else if (zoom) { 486 gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0, 487 (const GLchan (*)[4])rgba, desty); 488 } 489 else { 490 gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, rgba, GL_BITMAP ); 491 } 492 } 493 494 /* Restore pixel source to be the draw buffer (for blending, etc) */ 495 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 496 ctx->Color.DriverDrawBuffer ); 497 498 if (overlapping) 499 FREE(tmpImage); 500} 501 502 503static void copy_ci_pixels( GLcontext *ctx, 504 GLint srcx, GLint srcy, GLint width, GLint height, 505 GLint destx, GLint desty ) 506{ 507 GLdepth zspan[MAX_WIDTH]; 508 GLuint *tmpImage,*p; 509 GLint sy, dy, stepy; 510 GLint i, j; 511 GLboolean changeBuffer; 512 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 513 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 514 GLint overlapping; 515 516 /* Determine if copy should be bottom-to-top or top-to-bottom */ 517 if (srcy<desty) { 518 /* top-down max-to-min */ 519 sy = srcy + height - 1; 520 dy = desty + height - 1; 521 stepy = -1; 522 } 523 else { 524 /* bottom-up min-to-max */ 525 sy = srcy; 526 dy = desty; 527 stepy = 1; 528 } 529 530 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 531 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 532 533 if (ctx->Depth.Test || ctx->Fog.Enabled) { 534 /* fill in array of z values */ 535 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMax); 536 for (i=0;i<width;i++) { 537 zspan[i] = z; 538 } 539 } 540 541 /* If read and draw buffer are different we must do buffer switching */ 542 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 543 || ctx->DrawBuffer != ctx->ReadBuffer; 544 545 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 546 ctx->Pixel.DriverReadBuffer ); 547 548 if (overlapping) { 549 GLint ssy = sy; 550 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); 551 if (!tmpImage) { 552 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 553 return; 554 } 555 p = tmpImage; 556 if (changeBuffer) { 557 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 558 ctx->Pixel.DriverReadBuffer ); 559 } 560 for (j = 0; j < height; j++, ssy += stepy) { 561 gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p ); 562 p += width; 563 } 564 p = tmpImage; 565 } 566 else { 567 tmpImage = NULL; /* silence compiler warning */ 568 p = NULL; 569 } 570 571 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 572 GLuint indexes[MAX_WIDTH]; 573 if (overlapping) { 574 MEMCPY(indexes, p, width * sizeof(GLuint)); 575 p += width; 576 } 577 else { 578 if (changeBuffer) { 579 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 580 ctx->Pixel.DriverReadBuffer ); 581 } 582 gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes ); 583 } 584 585 if (changeBuffer) { 586 /* set read buffer back to draw buffer (in case of logicops) */ 587 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 588 ctx->Color.DriverDrawBuffer ); 589 } 590 591 if (shift_or_offset) { 592 _mesa_shift_and_offset_ci( ctx, width, indexes ); 593 } 594 if (ctx->Pixel.MapColorFlag) { 595 _mesa_map_ci( ctx, width, indexes ); 596 } 597 598 if (zoom) { 599 gl_write_zoomed_index_span( ctx, width, destx, dy, zspan, 0, indexes, desty ); 600 } 601 else { 602 gl_write_index_span(ctx, width, destx, dy, zspan, 0, indexes, GL_BITMAP); 603 } 604 } 605 606 /* Restore pixel source to be the draw buffer (for blending, etc) */ 607 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 608 ctx->Color.DriverDrawBuffer ); 609 610 if (overlapping) 611 FREE(tmpImage); 612} 613 614 615 616/* 617 * TODO: Optimize!!!! 618 */ 619static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 620 GLint width, GLint height, 621 GLint destx, GLint desty ) 622{ 623 GLfloat depth[MAX_WIDTH]; 624 GLdepth zspan[MAX_WIDTH]; 625 GLfloat *p, *tmpImage; 626 GLuint indexes[MAX_WIDTH]; 627 GLchan rgba[MAX_WIDTH][4]; 628 GLint sy, dy, stepy; 629 GLint i, j; 630 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 631 GLint overlapping; 632 633 if (!ctx->ReadBuffer->DepthBuffer || !ctx->DrawBuffer->DepthBuffer) { 634 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 635 return; 636 } 637 638 /* Determine if copy should be bottom-to-top or top-to-bottom */ 639 if (srcy<desty) { 640 /* top-down max-to-min */ 641 sy = srcy + height - 1; 642 dy = desty + height - 1; 643 stepy = -1; 644 } 645 else { 646 /* bottom-up min-to-max */ 647 sy = srcy; 648 dy = desty; 649 stepy = 1; 650 } 651 652 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 653 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 654 655 /* setup colors or indexes */ 656 if (ctx->Visual.RGBAflag) { 657 GLuint *rgba32 = (GLuint *) rgba; 658 GLuint color = *(GLuint*)( ctx->Current.Color ); 659 for (i = 0; i < width; i++) { 660 rgba32[i] = color; 661 } 662 } 663 else { 664 for (i = 0; i < width; i++) { 665 indexes[i] = ctx->Current.Index; 666 } 667 } 668 669 if (overlapping) { 670 GLint ssy = sy; 671 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); 672 if (!tmpImage) { 673 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 674 return; 675 } 676 p = tmpImage; 677 for (j = 0; j < height; j++, ssy += stepy) { 678 _mesa_read_depth_span_float(ctx, width, srcx, ssy, p); 679 p += width; 680 } 681 p = tmpImage; 682 } 683 else { 684 tmpImage = NULL; /* silence compiler warning */ 685 p = NULL; 686 } 687 688 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 689 if (overlapping) { 690 MEMCPY(depth, p, width * sizeof(GLfloat)); 691 p += width; 692 } 693 else { 694 _mesa_read_depth_span_float(ctx, width, srcx, sy, depth); 695 } 696 697 for (i = 0; i < width; i++) { 698 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 699 zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->Visual.DepthMax); 700 } 701 702 if (ctx->Visual.RGBAflag) { 703 if (zoom) { 704 gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, 0, 705 (const GLchan (*)[4])rgba, desty ); 706 } 707 else { 708 gl_write_rgba_span( ctx, width, destx, dy, zspan, 0, 709 rgba, GL_BITMAP); 710 } 711 } 712 else { 713 if (zoom) { 714 gl_write_zoomed_index_span( ctx, width, destx, dy, 715 zspan, 0, indexes, desty ); 716 } 717 else { 718 gl_write_index_span( ctx, width, destx, dy, 719 zspan, 0, indexes, GL_BITMAP ); 720 } 721 } 722 } 723 724 if (overlapping) 725 FREE(tmpImage); 726} 727 728 729 730static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 731 GLint width, GLint height, 732 GLint destx, GLint desty ) 733{ 734 GLint sy, dy, stepy; 735 GLint j; 736 GLstencil *p, *tmpImage; 737 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 738 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 739 GLint overlapping; 740 741 if (!ctx->DrawBuffer->Stencil || !ctx->ReadBuffer->Stencil) { 742 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 743 return; 744 } 745 746 /* Determine if copy should be bottom-to-top or top-to-bottom */ 747 if (srcy < desty) { 748 /* top-down max-to-min */ 749 sy = srcy + height - 1; 750 dy = desty + height - 1; 751 stepy = -1; 752 } 753 else { 754 /* bottom-up min-to-max */ 755 sy = srcy; 756 dy = desty; 757 stepy = 1; 758 } 759 760 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 761 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 762 763 if (overlapping) { 764 GLint ssy = sy; 765 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil)); 766 if (!tmpImage) { 767 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 768 return; 769 } 770 p = tmpImage; 771 for (j = 0; j < height; j++, ssy += stepy) { 772 _mesa_read_stencil_span( ctx, width, srcx, ssy, p ); 773 p += width; 774 } 775 p = tmpImage; 776 } 777 else { 778 tmpImage = NULL; /* silence compiler warning */ 779 p = NULL; 780 } 781 782 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 783 GLstencil stencil[MAX_WIDTH]; 784 785 if (overlapping) { 786 MEMCPY(stencil, p, width * sizeof(GLstencil)); 787 p += width; 788 } 789 else { 790 _mesa_read_stencil_span( ctx, width, srcx, sy, stencil ); 791 } 792 793 if (shift_or_offset) { 794 _mesa_shift_and_offset_stencil( ctx, width, stencil ); 795 } 796 if (ctx->Pixel.MapStencilFlag) { 797 _mesa_map_stencil( ctx, width, stencil ); 798 } 799 800 if (zoom) { 801 gl_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty ); 802 } 803 else { 804 _mesa_write_stencil_span( ctx, width, destx, dy, stencil ); 805 } 806 } 807 808 if (overlapping) 809 FREE(tmpImage); 810} 811 812 813 814 815void 816_swrast_CopyPixels( GLcontext *ctx, 817 GLint srcx, GLint srcy, GLsizei width, GLsizei height, 818 GLint destx, GLint desty, 819 GLenum type ) 820{ 821 if (SWRAST_CONTEXT(ctx)->NewState) 822 _swrast_validate_derived( ctx ); 823 824 if (type == GL_COLOR && ctx->Visual.RGBAflag) { 825 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); 826 } 827 else if (type == GL_COLOR && !ctx->Visual.RGBAflag) { 828 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 829 } 830 else if (type == GL_DEPTH) { 831 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 832 } 833 else if (type == GL_STENCIL) { 834 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 835 } 836 else { 837 gl_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); 838 } 839} 840