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