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