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