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