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