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