s_copypix.c revision 9927f1978da8530416f699d084dda099720e43e6
1/* $Id: s_copypix.c,v 1.27 2002/01/10 16:54:29 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 GLchan primary_rgba[MAX_WIDTH][4]; 271 GLuint unit; 272 DEFMARRAY(GLfloat, texcoord, MAX_WIDTH, 4); /* mac 32k limitation */ 273 CHECKARRAY(texcoord, return); /* mac 32k limitation */ 274 275 /* XXX not sure how multitexture is supposed to work here */ 276 277 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan)); 278 279 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 280 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba, 281 texcoord); 282 _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL, 283 (CONST GLchan (*)[4]) primary_rgba, 284 rgba); 285 } 286 UNDEFARRAY(texcoord); /* mac 32k limitation */ 287 } 288 289 /* write row to framebuffer */ 290 291 dy = desty + row; 292 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) { 293 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, 294 (const GLchan (*)[4])rgba, NULL ); 295 } 296 else if (zoom) { 297 _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan, 298 (const GLchan (*)[4])rgba, desty); 299 } 300 else { 301 _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba, 302 NULL, GL_BITMAP ); 303 } 304 } 305 306 FREE(convImage); 307} 308 309 310/* 311 * RGBA copypixels 312 */ 313static void 314copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, 315 GLint width, GLint height, GLint destx, GLint desty) 316{ 317 SWcontext *swrast = SWRAST_CONTEXT(ctx); 318 GLdepth zspan[MAX_WIDTH]; 319 GLfloat fogSpan[MAX_WIDTH]; 320 GLchan rgba[MAX_WIDTH][4]; 321 GLchan *tmpImage,*p; 322 GLboolean quick_draw; 323 GLint sy, dy, stepy; 324 GLint i, j; 325 GLboolean changeBuffer; 326 GLchan *saveReadAlpha; 327 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 328 GLint overlapping; 329 const GLuint transferOps = ctx->_ImageTransferState; 330 331 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 332 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); 333 return; 334 } 335 336 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 337 if (srcy < desty) { 338 /* top-down max-to-min */ 339 sy = srcy + height - 1; 340 dy = desty + height - 1; 341 stepy = -1; 342 } 343 else { 344 /* bottom-up min-to-max */ 345 sy = srcy; 346 dy = desty; 347 stepy = 1; 348 } 349 350 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 351 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 352 353 if (ctx->Depth.Test || ctx->Fog.Enabled) { 354 /* fill in array of z values */ 355 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax); 356 GLfloat fog; 357 358 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) 359 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord); 360 else 361 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance); 362 363 for (i=0;i<width;i++) { 364 zspan[i] = z; 365 fogSpan[i] = fog; 366 } 367 } 368 369 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 370 && !zoom 371 && destx >= 0 372 && destx + width <= ctx->DrawBuffer->Width) { 373 quick_draw = GL_TRUE; 374 } 375 else { 376 quick_draw = GL_FALSE; 377 } 378 379 /* If read and draw buffer are different we must do buffer switching */ 380 saveReadAlpha = ctx->ReadBuffer->Alpha; 381 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 382 || ctx->DrawBuffer != ctx->ReadBuffer; 383 384 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 385 ctx->Pixel.DriverReadBuffer ); 386 387 if (overlapping) { 388 GLint ssy = sy; 389 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); 390 if (!tmpImage) { 391 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 392 return; 393 } 394 p = tmpImage; 395 if (changeBuffer) { 396 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 397 ctx->Pixel.DriverReadBuffer ); 398 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) 399 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha; 400 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) 401 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha; 402 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) 403 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha; 404 else 405 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha; 406 } 407 for (j = 0; j < height; j++, ssy += stepy) { 408 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy, 409 (GLchan (*)[4]) p ); 410 p += (width * sizeof(GLchan) * 4); 411 } 412 p = tmpImage; 413 } 414 else { 415 tmpImage = NULL; /* silence compiler warnings */ 416 p = NULL; 417 } 418 419 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 420 /* Get source pixels */ 421 if (overlapping) { 422 /* get from buffered image */ 423 MEMCPY(rgba, p, width * sizeof(GLchan) * 4); 424 p += (width * sizeof(GLchan) * 4); 425 } 426 else { 427 /* get from framebuffer */ 428 if (changeBuffer) { 429 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 430 ctx->Pixel.DriverReadBuffer ); 431 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) { 432 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha; 433 } 434 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) { 435 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha; 436 } 437 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) { 438 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha; 439 } 440 else { 441 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha; 442 } 443 } 444 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba ); 445 } 446 447 if (changeBuffer) { 448 /* read from the draw buffer again (in case of blending) */ 449 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 450 ctx->Color.DriverDrawBuffer ); 451 ctx->ReadBuffer->Alpha = saveReadAlpha; 452 } 453 454 if (transferOps) { 455 const GLfloat scale = (1.0F / CHAN_MAXF); 456 GLint k; 457 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */ 458 CHECKARRAY(rgbaFloat, return); 459 460 /* convert chan to float */ 461 for (k = 0; k < width; k++) { 462 rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale; 463 rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale; 464 rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale; 465 rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale; 466 } 467 /* scale & bias */ 468 if (transferOps & IMAGE_SCALE_BIAS_BIT) { 469 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, 470 ctx->Pixel.RedScale, ctx->Pixel.GreenScale, 471 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, 472 ctx->Pixel.RedBias, ctx->Pixel.GreenBias, 473 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); 474 } 475 /* color map lookup */ 476 if (transferOps & IMAGE_MAP_COLOR_BIT) { 477 _mesa_map_rgba(ctx, width, rgbaFloat); 478 } 479 /* GL_COLOR_TABLE lookup */ 480 if (transferOps & IMAGE_COLOR_TABLE_BIT) { 481 _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat); 482 } 483 /* convolution */ 484 if (transferOps & IMAGE_CONVOLUTION_BIT) { 485 /* XXX to do */ 486 } 487 /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */ 488 if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) { 489 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, 490 ctx->Pixel.PostConvolutionScale[RCOMP], 491 ctx->Pixel.PostConvolutionScale[GCOMP], 492 ctx->Pixel.PostConvolutionScale[BCOMP], 493 ctx->Pixel.PostConvolutionScale[ACOMP], 494 ctx->Pixel.PostConvolutionBias[RCOMP], 495 ctx->Pixel.PostConvolutionBias[GCOMP], 496 ctx->Pixel.PostConvolutionBias[BCOMP], 497 ctx->Pixel.PostConvolutionBias[ACOMP]); 498 } 499 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ 500 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { 501 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat); 502 } 503 /* color matrix */ 504 if (transferOps & IMAGE_COLOR_MATRIX_BIT) { 505 _mesa_transform_rgba(ctx, width, rgbaFloat); 506 } 507 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ 508 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { 509 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat); 510 } 511 /* update histogram count */ 512 if (transferOps & IMAGE_HISTOGRAM_BIT) { 513 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); 514 } 515 /* update min/max */ 516 if (transferOps & IMAGE_MIN_MAX_BIT) { 517 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); 518 } 519 /* clamp to [0,1] and convert float back to chan */ 520 for (k = 0; k < width; k++) { 521 GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF); 522 GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF); 523 GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF); 524 GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF); 525 rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); 526 rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); 527 rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); 528 rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); 529 } 530 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */ 531 } 532 533 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) { 534 GLuint unit; 535 GLchan primary_rgba[MAX_WIDTH][4]; 536 DEFMARRAY(GLfloat, texcoord, MAX_WIDTH, 4); /* mac 32k limitation */ 537 CHECKARRAY(texcoord, return); /* mac 32k limitation */ 538 539 /* XXX not sure how multitexture is supposed to work here */ 540 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan)); 541 542 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 543 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba, 544 texcoord); 545 _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL, 546 (CONST GLchan (*)[4]) primary_rgba, 547 rgba); 548 } 549 550 UNDEFARRAY(texcoord); /* mac 32k limitation */ 551 } 552 553 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) { 554 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, 555 (const GLchan (*)[4])rgba, NULL ); 556 } 557 else if (zoom) { 558 _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan, 559 (const GLchan (*)[4])rgba, desty); 560 } 561 else { 562 _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba, 563 NULL, GL_BITMAP ); 564 } 565 } 566 567 /* Restore pixel source to be the draw buffer (for blending, etc) */ 568 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 569 ctx->Color.DriverDrawBuffer ); 570 571 if (overlapping) 572 FREE(tmpImage); 573} 574 575 576static void copy_ci_pixels( GLcontext *ctx, 577 GLint srcx, GLint srcy, GLint width, GLint height, 578 GLint destx, GLint desty ) 579{ 580 SWcontext *swrast = SWRAST_CONTEXT(ctx); 581 GLdepth zspan[MAX_WIDTH]; 582 GLfloat fogSpan[MAX_WIDTH]; 583 GLuint *tmpImage,*p; 584 GLint sy, dy, stepy; 585 GLint i, j; 586 GLboolean changeBuffer; 587 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 588 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; 589 GLint overlapping; 590 591 /* Determine if copy should be bottom-to-top or top-to-bottom */ 592 if (srcy<desty) { 593 /* top-down max-to-min */ 594 sy = srcy + height - 1; 595 dy = desty + height - 1; 596 stepy = -1; 597 } 598 else { 599 /* bottom-up min-to-max */ 600 sy = srcy; 601 dy = desty; 602 stepy = 1; 603 } 604 605 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 606 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 607 608 if (ctx->Depth.Test || ctx->Fog.Enabled) { 609 /* fill in array of z values */ 610 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax); 611 GLfloat fog; 612 613 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) 614 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord); 615 else 616 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance); 617 618 for (i=0;i<width;i++) { 619 zspan[i] = z; 620 fogSpan[i] = fog; 621 } 622 } 623 624 /* If read and draw buffer are different we must do buffer switching */ 625 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer 626 || ctx->DrawBuffer != ctx->ReadBuffer; 627 628 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 629 ctx->Pixel.DriverReadBuffer ); 630 631 if (overlapping) { 632 GLint ssy = sy; 633 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); 634 if (!tmpImage) { 635 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); 636 return; 637 } 638 p = tmpImage; 639 if (changeBuffer) { 640 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 641 ctx->Pixel.DriverReadBuffer ); 642 } 643 for (j = 0; j < height; j++, ssy += stepy) { 644 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p ); 645 p += width; 646 } 647 p = tmpImage; 648 } 649 else { 650 tmpImage = NULL; /* silence compiler warning */ 651 p = NULL; 652 } 653 654 for (j = 0; j < height; j++, sy += stepy, dy += stepy) { 655 GLuint indexes[MAX_WIDTH]; 656 if (overlapping) { 657 MEMCPY(indexes, p, width * sizeof(GLuint)); 658 p += width; 659 } 660 else { 661 if (changeBuffer) { 662 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer, 663 ctx->Pixel.DriverReadBuffer ); 664 } 665 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes ); 666 } 667 668 if (changeBuffer) { 669 /* set read buffer back to draw buffer (in case of logicops) */ 670 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 671 ctx->Color.DriverDrawBuffer ); 672 } 673 674 if (shift_or_offset) { 675 _mesa_shift_and_offset_ci( ctx, width, indexes ); 676 } 677 if (ctx->Pixel.MapColorFlag) { 678 _mesa_map_ci( ctx, width, indexes ); 679 } 680 681 if (zoom) { 682 _mesa_write_zoomed_index_span(ctx, width, destx, dy, zspan, fogSpan, 683 indexes, desty ); 684 } 685 else { 686 _old_write_index_span(ctx, width, destx, dy, zspan, fogSpan, indexes, 687 NULL, GL_BITMAP); 688 } 689 } 690 691 /* Restore pixel source to be the draw buffer (for blending, etc) */ 692 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer, 693 ctx->Color.DriverDrawBuffer ); 694 695 if (overlapping) 696 FREE(tmpImage); 697} 698 699 700 701/* 702 * TODO: Optimize!!!! 703 */ 704static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, 705 GLint width, GLint height, 706 GLint destx, GLint desty ) 707{ 708 GLfloat depth[MAX_WIDTH]; 709 GLdepth zspan[MAX_WIDTH]; 710 GLfloat fogSpan[MAX_WIDTH]; 711 GLfloat *p, *tmpImage; 712 GLuint indexes[MAX_WIDTH]; 713 GLint sy, dy, stepy; 714 GLint i, j; 715 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; 716 GLint overlapping; 717 DEFMARRAY(GLchan, rgba, MAX_WIDTH, 4); /* mac 32k limitation */ 718 CHECKARRAY(rgba, return); /* mac 32k limitation */ 719 720 if (!ctx->Visual.depthBits) { 721 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 722 UNDEFARRAY(rgba); /* mac 32k limitation */ 723 return; 724 } 725 726 /* Determine if copy should be bottom-to-top or top-to-bottom */ 727 if (srcy<desty) { 728 /* top-down max-to-min */ 729 sy = srcy + height - 1; 730 dy = desty + height - 1; 731 stepy = -1; 732 } 733 else { 734 /* bottom-up min-to-max */ 735 sy = srcy; 736 dy = desty; 737 stepy = 1; 738 } 739 740 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, 741 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); 742 743 /* setup colors or indexes */ 744 if (ctx->Visual.rgbMode) { 745 GLchan r, g, b, a; 746 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]); 747 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]); 748 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]); 749 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]); 750 for (i = 0; i < width; i++) { 751 rgba[i][RCOMP] = r; 752 rgba[i][GCOMP] = g; 753 rgba[i][BCOMP] = b; 754 rgba[i][ACOMP] = a; 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 _old_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 _old_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