image.c revision 3998cfa933dcd9134b75d9f0ae2c9cfcd6f2ee45
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * \file image.c 29 * Image handling. 30 */ 31 32 33#include "glheader.h" 34#include "colormac.h" 35#include "glformats.h" 36#include "image.h" 37#include "imports.h" 38#include "macros.h" 39#include "mtypes.h" 40 41 42 43/** 44 * Flip the order of the 2 bytes in each word in the given array. 45 * 46 * \param p array. 47 * \param n number of words. 48 */ 49void 50_mesa_swap2( GLushort *p, GLuint n ) 51{ 52 GLuint i; 53 for (i = 0; i < n; i++) { 54 p[i] = (p[i] >> 8) | ((p[i] << 8) & 0xff00); 55 } 56} 57 58 59 60/* 61 * Flip the order of the 4 bytes in each word in the given array. 62 */ 63void 64_mesa_swap4( GLuint *p, GLuint n ) 65{ 66 GLuint i, a, b; 67 for (i = 0; i < n; i++) { 68 b = p[i]; 69 a = (b >> 24) 70 | ((b >> 8) & 0xff00) 71 | ((b << 8) & 0xff0000) 72 | ((b << 24) & 0xff000000); 73 p[i] = a; 74 } 75} 76 77 78/** 79 * Return the byte offset of a specific pixel in an image (1D, 2D or 3D). 80 * 81 * Pixel unpacking/packing parameters are observed according to \p packing. 82 * 83 * \param dimensions either 1, 2 or 3 to indicate dimensionality of image 84 * \param packing the pixelstore attributes 85 * \param width the image width 86 * \param height the image height 87 * \param format the pixel format (must be validated beforehand) 88 * \param type the pixel data type (must be validated beforehand) 89 * \param img which image in the volume (0 for 1D or 2D images) 90 * \param row row of pixel in the image (0 for 1D images) 91 * \param column column of pixel in the image 92 * 93 * \return offset of pixel. 94 * 95 * \sa gl_pixelstore_attrib. 96 */ 97GLintptr 98_mesa_image_offset( GLuint dimensions, 99 const struct gl_pixelstore_attrib *packing, 100 GLsizei width, GLsizei height, 101 GLenum format, GLenum type, 102 GLint img, GLint row, GLint column ) 103{ 104 GLint alignment; /* 1, 2 or 4 */ 105 GLint pixels_per_row; 106 GLint rows_per_image; 107 GLint skiprows; 108 GLint skippixels; 109 GLint skipimages; /* for 3-D volume images */ 110 GLintptr offset; 111 112 ASSERT(dimensions >= 1 && dimensions <= 3); 113 114 alignment = packing->Alignment; 115 if (packing->RowLength > 0) { 116 pixels_per_row = packing->RowLength; 117 } 118 else { 119 pixels_per_row = width; 120 } 121 if (packing->ImageHeight > 0) { 122 rows_per_image = packing->ImageHeight; 123 } 124 else { 125 rows_per_image = height; 126 } 127 128 skippixels = packing->SkipPixels; 129 /* Note: SKIP_ROWS _is_ used for 1D images */ 130 skiprows = packing->SkipRows; 131 /* Note: SKIP_IMAGES is only used for 3D images */ 132 skipimages = (dimensions == 3) ? packing->SkipImages : 0; 133 134 if (type == GL_BITMAP) { 135 /* BITMAP data */ 136 GLint bytes_per_row; 137 GLint bytes_per_image; 138 /* components per pixel for color or stencil index: */ 139 const GLint comp_per_pixel = 1; 140 141 /* The pixel type and format should have been error checked earlier */ 142 assert(format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX); 143 144 bytes_per_row = alignment 145 * CEILING( comp_per_pixel*pixels_per_row, 8*alignment ); 146 147 bytes_per_image = bytes_per_row * rows_per_image; 148 149 offset = (skipimages + img) * bytes_per_image 150 + (skiprows + row) * bytes_per_row 151 + (skippixels + column) / 8; 152 } 153 else { 154 /* Non-BITMAP data */ 155 GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image; 156 GLint topOfImage; 157 158 bytes_per_pixel = _mesa_bytes_per_pixel( format, type ); 159 160 /* The pixel type and format should have been error checked earlier */ 161 assert(bytes_per_pixel > 0); 162 163 bytes_per_row = pixels_per_row * bytes_per_pixel; 164 remainder = bytes_per_row % alignment; 165 if (remainder > 0) 166 bytes_per_row += (alignment - remainder); 167 168 ASSERT(bytes_per_row % alignment == 0); 169 170 bytes_per_image = bytes_per_row * rows_per_image; 171 172 if (packing->Invert) { 173 /* set pixel_addr to the last row */ 174 topOfImage = bytes_per_row * (height - 1); 175 bytes_per_row = -bytes_per_row; 176 } 177 else { 178 topOfImage = 0; 179 } 180 181 /* compute final pixel address */ 182 offset = (skipimages + img) * bytes_per_image 183 + topOfImage 184 + (skiprows + row) * bytes_per_row 185 + (skippixels + column) * bytes_per_pixel; 186 } 187 188 return offset; 189} 190 191 192/** 193 * Return the address of a specific pixel in an image (1D, 2D or 3D). 194 * 195 * Pixel unpacking/packing parameters are observed according to \p packing. 196 * 197 * \param dimensions either 1, 2 or 3 to indicate dimensionality of image 198 * \param packing the pixelstore attributes 199 * \param image starting address of image data 200 * \param width the image width 201 * \param height the image height 202 * \param format the pixel format (must be validated beforehand) 203 * \param type the pixel data type (must be validated beforehand) 204 * \param img which image in the volume (0 for 1D or 2D images) 205 * \param row row of pixel in the image (0 for 1D images) 206 * \param column column of pixel in the image 207 * 208 * \return address of pixel. 209 * 210 * \sa gl_pixelstore_attrib. 211 */ 212GLvoid * 213_mesa_image_address( GLuint dimensions, 214 const struct gl_pixelstore_attrib *packing, 215 const GLvoid *image, 216 GLsizei width, GLsizei height, 217 GLenum format, GLenum type, 218 GLint img, GLint row, GLint column ) 219{ 220 const GLubyte *addr = (const GLubyte *) image; 221 222 addr += _mesa_image_offset(dimensions, packing, width, height, 223 format, type, img, row, column); 224 225 return (GLvoid *) addr; 226} 227 228 229GLvoid * 230_mesa_image_address1d( const struct gl_pixelstore_attrib *packing, 231 const GLvoid *image, 232 GLsizei width, 233 GLenum format, GLenum type, 234 GLint column ) 235{ 236 return _mesa_image_address(1, packing, image, width, 1, 237 format, type, 0, 0, column); 238} 239 240 241GLvoid * 242_mesa_image_address2d( const struct gl_pixelstore_attrib *packing, 243 const GLvoid *image, 244 GLsizei width, GLsizei height, 245 GLenum format, GLenum type, 246 GLint row, GLint column ) 247{ 248 return _mesa_image_address(2, packing, image, width, height, 249 format, type, 0, row, column); 250} 251 252 253GLvoid * 254_mesa_image_address3d( const struct gl_pixelstore_attrib *packing, 255 const GLvoid *image, 256 GLsizei width, GLsizei height, 257 GLenum format, GLenum type, 258 GLint img, GLint row, GLint column ) 259{ 260 return _mesa_image_address(3, packing, image, width, height, 261 format, type, img, row, column); 262} 263 264 265 266/** 267 * Compute the stride (in bytes) between image rows. 268 * 269 * \param packing the pixelstore attributes 270 * \param width image width. 271 * \param format pixel format. 272 * \param type pixel data type. 273 * 274 * \return the stride in bytes for the given parameters, or -1 if error 275 */ 276GLint 277_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing, 278 GLint width, GLenum format, GLenum type ) 279{ 280 GLint bytesPerRow, remainder; 281 282 ASSERT(packing); 283 284 if (type == GL_BITMAP) { 285 if (packing->RowLength == 0) { 286 bytesPerRow = (width + 7) / 8; 287 } 288 else { 289 bytesPerRow = (packing->RowLength + 7) / 8; 290 } 291 } 292 else { 293 /* Non-BITMAP data */ 294 const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); 295 if (bytesPerPixel <= 0) 296 return -1; /* error */ 297 if (packing->RowLength == 0) { 298 bytesPerRow = bytesPerPixel * width; 299 } 300 else { 301 bytesPerRow = bytesPerPixel * packing->RowLength; 302 } 303 } 304 305 remainder = bytesPerRow % packing->Alignment; 306 if (remainder > 0) { 307 bytesPerRow += (packing->Alignment - remainder); 308 } 309 310 if (packing->Invert) { 311 /* negate the bytes per row (negative row stride) */ 312 bytesPerRow = -bytesPerRow; 313 } 314 315 return bytesPerRow; 316} 317 318 319/* 320 * Compute the stride between images in a 3D texture (in bytes) for the given 321 * pixel packing parameters and image width, format and type. 322 */ 323GLint 324_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing, 325 GLint width, GLint height, 326 GLenum format, GLenum type ) 327{ 328 GLint bytesPerRow, bytesPerImage, remainder; 329 330 ASSERT(packing); 331 332 if (type == GL_BITMAP) { 333 if (packing->RowLength == 0) { 334 bytesPerRow = (width + 7) / 8; 335 } 336 else { 337 bytesPerRow = (packing->RowLength + 7) / 8; 338 } 339 } 340 else { 341 const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type); 342 343 if (bytesPerPixel <= 0) 344 return -1; /* error */ 345 if (packing->RowLength == 0) { 346 bytesPerRow = bytesPerPixel * width; 347 } 348 else { 349 bytesPerRow = bytesPerPixel * packing->RowLength; 350 } 351 } 352 353 remainder = bytesPerRow % packing->Alignment; 354 if (remainder > 0) 355 bytesPerRow += (packing->Alignment - remainder); 356 357 if (packing->ImageHeight == 0) 358 bytesPerImage = bytesPerRow * height; 359 else 360 bytesPerImage = bytesPerRow * packing->ImageHeight; 361 362 return bytesPerImage; 363} 364 365 366 367/** 368 * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel. 369 * This is typically used to convert a bitmap into a GLubyte/pixel texture. 370 * "On" bits will set texels to \p onValue. 371 * "Off" bits will not modify texels. 372 * \param width src bitmap width in pixels 373 * \param height src bitmap height in pixels 374 * \param unpack bitmap unpacking state 375 * \param bitmap the src bitmap data 376 * \param destBuffer start of dest buffer 377 * \param destStride row stride in dest buffer 378 * \param onValue if bit is 1, set destBuffer pixel to this value 379 */ 380void 381_mesa_expand_bitmap(GLsizei width, GLsizei height, 382 const struct gl_pixelstore_attrib *unpack, 383 const GLubyte *bitmap, 384 GLubyte *destBuffer, GLint destStride, 385 GLubyte onValue) 386{ 387 const GLubyte *srcRow = (const GLubyte *) 388 _mesa_image_address2d(unpack, bitmap, width, height, 389 GL_COLOR_INDEX, GL_BITMAP, 0, 0); 390 const GLint srcStride = _mesa_image_row_stride(unpack, width, 391 GL_COLOR_INDEX, GL_BITMAP); 392 GLint row, col; 393 394#define SET_PIXEL(COL, ROW) \ 395 destBuffer[(ROW) * destStride + (COL)] = onValue; 396 397 for (row = 0; row < height; row++) { 398 const GLubyte *src = srcRow; 399 400 if (unpack->LsbFirst) { 401 /* Lsb first */ 402 GLubyte mask = 1U << (unpack->SkipPixels & 0x7); 403 for (col = 0; col < width; col++) { 404 405 if (*src & mask) { 406 SET_PIXEL(col, row); 407 } 408 409 if (mask == 128U) { 410 src++; 411 mask = 1U; 412 } 413 else { 414 mask = mask << 1; 415 } 416 } 417 418 /* get ready for next row */ 419 if (mask != 1) 420 src++; 421 } 422 else { 423 /* Msb first */ 424 GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); 425 for (col = 0; col < width; col++) { 426 427 if (*src & mask) { 428 SET_PIXEL(col, row); 429 } 430 431 if (mask == 1U) { 432 src++; 433 mask = 128U; 434 } 435 else { 436 mask = mask >> 1; 437 } 438 } 439 440 /* get ready for next row */ 441 if (mask != 128) 442 src++; 443 } 444 445 srcRow += srcStride; 446 } /* row */ 447 448#undef SET_PIXEL 449} 450 451 452 453 454/** 455 * Convert an array of RGBA colors from one datatype to another. 456 * NOTE: src may equal dst. In that case, we use a temporary buffer. 457 */ 458void 459_mesa_convert_colors(GLenum srcType, const GLvoid *src, 460 GLenum dstType, GLvoid *dst, 461 GLuint count, const GLubyte mask[]) 462{ 463 GLuint *tempBuffer; 464 const GLboolean useTemp = (src == dst); 465 466 tempBuffer = malloc(count * MAX_PIXEL_BYTES); 467 if (!tempBuffer) 468 return; 469 470 ASSERT(srcType != dstType); 471 472 switch (srcType) { 473 case GL_UNSIGNED_BYTE: 474 if (dstType == GL_UNSIGNED_SHORT) { 475 const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; 476 GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); 477 GLuint i; 478 for (i = 0; i < count; i++) { 479 if (!mask || mask[i]) { 480 dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]); 481 dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]); 482 dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]); 483 dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]); 484 } 485 } 486 if (useTemp) 487 memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); 488 } 489 else { 490 const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src; 491 GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); 492 GLuint i; 493 ASSERT(dstType == GL_FLOAT); 494 for (i = 0; i < count; i++) { 495 if (!mask || mask[i]) { 496 dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]); 497 dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]); 498 dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]); 499 dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]); 500 } 501 } 502 if (useTemp) 503 memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); 504 } 505 break; 506 case GL_UNSIGNED_SHORT: 507 if (dstType == GL_UNSIGNED_BYTE) { 508 const GLushort (*src2)[4] = (const GLushort (*)[4]) src; 509 GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); 510 GLuint i; 511 for (i = 0; i < count; i++) { 512 if (!mask || mask[i]) { 513 dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]); 514 dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]); 515 dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]); 516 dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]); 517 } 518 } 519 if (useTemp) 520 memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); 521 } 522 else { 523 const GLushort (*src2)[4] = (const GLushort (*)[4]) src; 524 GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst); 525 GLuint i; 526 ASSERT(dstType == GL_FLOAT); 527 for (i = 0; i < count; i++) { 528 if (!mask || mask[i]) { 529 dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]); 530 dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]); 531 dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]); 532 dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]); 533 } 534 } 535 if (useTemp) 536 memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat)); 537 } 538 break; 539 case GL_FLOAT: 540 if (dstType == GL_UNSIGNED_BYTE) { 541 const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; 542 GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst); 543 GLuint i; 544 for (i = 0; i < count; i++) { 545 if (!mask || mask[i]) 546 _mesa_unclamped_float_rgba_to_ubyte(dst1[i], src4[i]); 547 } 548 if (useTemp) 549 memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte)); 550 } 551 else { 552 const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src; 553 GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst); 554 GLuint i; 555 ASSERT(dstType == GL_UNSIGNED_SHORT); 556 for (i = 0; i < count; i++) { 557 if (!mask || mask[i]) { 558 UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]); 559 UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]); 560 UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]); 561 UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]); 562 } 563 } 564 if (useTemp) 565 memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort)); 566 } 567 break; 568 default: 569 _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors"); 570 } 571 572 free(tempBuffer); 573} 574 575 576 577 578/** 579 * Perform basic clipping for glDrawPixels. The image's position and size 580 * and the unpack SkipPixels and SkipRows are adjusted so that the image 581 * region is entirely within the window and scissor bounds. 582 * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1). 583 * If Pixel.ZoomY is -1, *destY will be changed to be the first row which 584 * we'll actually write. Beforehand, *destY-1 is the first drawing row. 585 * 586 * \return GL_TRUE if image is ready for drawing or 587 * GL_FALSE if image was completely clipped away (draw nothing) 588 */ 589GLboolean 590_mesa_clip_drawpixels(const struct gl_context *ctx, 591 GLint *destX, GLint *destY, 592 GLsizei *width, GLsizei *height, 593 struct gl_pixelstore_attrib *unpack) 594{ 595 const struct gl_framebuffer *buffer = ctx->DrawBuffer; 596 597 if (unpack->RowLength == 0) { 598 unpack->RowLength = *width; 599 } 600 601 ASSERT(ctx->Pixel.ZoomX == 1.0F); 602 ASSERT(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F); 603 604 /* left clipping */ 605 if (*destX < buffer->_Xmin) { 606 unpack->SkipPixels += (buffer->_Xmin - *destX); 607 *width -= (buffer->_Xmin - *destX); 608 *destX = buffer->_Xmin; 609 } 610 /* right clipping */ 611 if (*destX + *width > buffer->_Xmax) 612 *width -= (*destX + *width - buffer->_Xmax); 613 614 if (*width <= 0) 615 return GL_FALSE; 616 617 if (ctx->Pixel.ZoomY == 1.0F) { 618 /* bottom clipping */ 619 if (*destY < buffer->_Ymin) { 620 unpack->SkipRows += (buffer->_Ymin - *destY); 621 *height -= (buffer->_Ymin - *destY); 622 *destY = buffer->_Ymin; 623 } 624 /* top clipping */ 625 if (*destY + *height > buffer->_Ymax) 626 *height -= (*destY + *height - buffer->_Ymax); 627 } 628 else { /* upside down */ 629 /* top clipping */ 630 if (*destY > buffer->_Ymax) { 631 unpack->SkipRows += (*destY - buffer->_Ymax); 632 *height -= (*destY - buffer->_Ymax); 633 *destY = buffer->_Ymax; 634 } 635 /* bottom clipping */ 636 if (*destY - *height < buffer->_Ymin) 637 *height -= (buffer->_Ymin - (*destY - *height)); 638 /* adjust destY so it's the first row to write to */ 639 (*destY)--; 640 } 641 642 if (*height <= 0) 643 return GL_FALSE; 644 645 return GL_TRUE; 646} 647 648 649/** 650 * Perform clipping for glReadPixels. The image's window position 651 * and size, and the pack skipPixels, skipRows and rowLength are adjusted 652 * so that the image region is entirely within the window bounds. 653 * Note: this is different from _mesa_clip_drawpixels() in that the 654 * scissor box is ignored, and we use the bounds of the current readbuffer 655 * surface. 656 * 657 * \return GL_TRUE if region to read is in bounds 658 * GL_FALSE if region is completely out of bounds (nothing to read) 659 */ 660GLboolean 661_mesa_clip_readpixels(const struct gl_context *ctx, 662 GLint *srcX, GLint *srcY, 663 GLsizei *width, GLsizei *height, 664 struct gl_pixelstore_attrib *pack) 665{ 666 const struct gl_framebuffer *buffer = ctx->ReadBuffer; 667 668 if (pack->RowLength == 0) { 669 pack->RowLength = *width; 670 } 671 672 /* left clipping */ 673 if (*srcX < 0) { 674 pack->SkipPixels += (0 - *srcX); 675 *width -= (0 - *srcX); 676 *srcX = 0; 677 } 678 /* right clipping */ 679 if (*srcX + *width > (GLsizei) buffer->Width) 680 *width -= (*srcX + *width - buffer->Width); 681 682 if (*width <= 0) 683 return GL_FALSE; 684 685 /* bottom clipping */ 686 if (*srcY < 0) { 687 pack->SkipRows += (0 - *srcY); 688 *height -= (0 - *srcY); 689 *srcY = 0; 690 } 691 /* top clipping */ 692 if (*srcY + *height > (GLsizei) buffer->Height) 693 *height -= (*srcY + *height - buffer->Height); 694 695 if (*height <= 0) 696 return GL_FALSE; 697 698 return GL_TRUE; 699} 700 701 702/** 703 * Do clipping for a glCopyTexSubImage call. 704 * The framebuffer source region might extend outside the framebuffer 705 * bounds. Clip the source region against the framebuffer bounds and 706 * adjust the texture/dest position and size accordingly. 707 * 708 * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise. 709 */ 710GLboolean 711_mesa_clip_copytexsubimage(const struct gl_context *ctx, 712 GLint *destX, GLint *destY, 713 GLint *srcX, GLint *srcY, 714 GLsizei *width, GLsizei *height) 715{ 716 const struct gl_framebuffer *fb = ctx->ReadBuffer; 717 const GLint srcX0 = *srcX, srcY0 = *srcY; 718 719 if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height, 720 srcX, srcY, width, height)) { 721 *destX = *destX + *srcX - srcX0; 722 *destY = *destY + *srcY - srcY0; 723 724 return GL_TRUE; 725 } 726 else { 727 return GL_FALSE; 728 } 729} 730 731 732 733/** 734 * Clip the rectangle defined by (x, y, width, height) against the bounds 735 * specified by [xmin, xmax) and [ymin, ymax). 736 * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise. 737 */ 738GLboolean 739_mesa_clip_to_region(GLint xmin, GLint ymin, 740 GLint xmax, GLint ymax, 741 GLint *x, GLint *y, 742 GLsizei *width, GLsizei *height ) 743{ 744 /* left clipping */ 745 if (*x < xmin) { 746 *width -= (xmin - *x); 747 *x = xmin; 748 } 749 750 /* right clipping */ 751 if (*x + *width > xmax) 752 *width -= (*x + *width - xmax); 753 754 if (*width <= 0) 755 return GL_FALSE; 756 757 /* bottom (or top) clipping */ 758 if (*y < ymin) { 759 *height -= (ymin - *y); 760 *y = ymin; 761 } 762 763 /* top (or bottom) clipping */ 764 if (*y + *height > ymax) 765 *height -= (*y + *height - ymax); 766 767 if (*height <= 0) 768 return GL_FALSE; 769 770 return GL_TRUE; 771} 772 773 774/** 775 * Clip dst coords against Xmax (or Ymax). 776 */ 777static inline void 778clip_right_or_top(GLint *srcX0, GLint *srcX1, 779 GLint *dstX0, GLint *dstX1, 780 GLint maxValue) 781{ 782 GLfloat t, bias; 783 784 if (*dstX1 > maxValue) { 785 /* X1 outside right edge */ 786 ASSERT(*dstX0 < maxValue); /* X0 should be inside right edge */ 787 t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); 788 /* chop off [t, 1] part */ 789 ASSERT(t >= 0.0 && t <= 1.0); 790 *dstX1 = maxValue; 791 bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; 792 *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); 793 } 794 else if (*dstX0 > maxValue) { 795 /* X0 outside right edge */ 796 ASSERT(*dstX1 < maxValue); /* X1 should be inside right edge */ 797 t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); 798 /* chop off [t, 1] part */ 799 ASSERT(t >= 0.0 && t <= 1.0); 800 *dstX0 = maxValue; 801 bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F; 802 *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); 803 } 804} 805 806 807/** 808 * Clip dst coords against Xmin (or Ymin). 809 */ 810static inline void 811clip_left_or_bottom(GLint *srcX0, GLint *srcX1, 812 GLint *dstX0, GLint *dstX1, 813 GLint minValue) 814{ 815 GLfloat t, bias; 816 817 if (*dstX0 < minValue) { 818 /* X0 outside left edge */ 819 ASSERT(*dstX1 > minValue); /* X1 should be inside left edge */ 820 t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0); 821 /* chop off [0, t] part */ 822 ASSERT(t >= 0.0 && t <= 1.0); 823 *dstX0 = minValue; 824 bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F; 825 *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias); 826 } 827 else if (*dstX1 < minValue) { 828 /* X1 outside left edge */ 829 ASSERT(*dstX0 > minValue); /* X0 should be inside left edge */ 830 t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1); 831 /* chop off [0, t] part */ 832 ASSERT(t >= 0.0 && t <= 1.0); 833 *dstX1 = minValue; 834 bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F; 835 *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias); 836 } 837} 838 839 840/** 841 * Do clipping of blit src/dest rectangles. 842 * The dest rect is clipped against both the buffer bounds and scissor bounds. 843 * The src rect is just clipped against the buffer bounds. 844 * 845 * When either the src or dest rect is clipped, the other is also clipped 846 * proportionately! 847 * 848 * Note that X0 need not be less than X1 (same for Y) for either the source 849 * and dest rects. That makes the clipping a little trickier. 850 * 851 * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped 852 */ 853GLboolean 854_mesa_clip_blit(struct gl_context *ctx, 855 GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1, 856 GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1) 857{ 858 const GLint srcXmin = 0; 859 const GLint srcXmax = ctx->ReadBuffer->Width; 860 const GLint srcYmin = 0; 861 const GLint srcYmax = ctx->ReadBuffer->Height; 862 863 /* these include scissor bounds */ 864 const GLint dstXmin = ctx->DrawBuffer->_Xmin; 865 const GLint dstXmax = ctx->DrawBuffer->_Xmax; 866 const GLint dstYmin = ctx->DrawBuffer->_Ymin; 867 const GLint dstYmax = ctx->DrawBuffer->_Ymax; 868 869 /* 870 printf("PreClipX: src: %d .. %d dst: %d .. %d\n", 871 *srcX0, *srcX1, *dstX0, *dstX1); 872 printf("PreClipY: src: %d .. %d dst: %d .. %d\n", 873 *srcY0, *srcY1, *dstY0, *dstY1); 874 */ 875 876 /* trivial rejection tests */ 877 if (*dstX0 == *dstX1) 878 return GL_FALSE; /* no width */ 879 if (*dstX0 <= dstXmin && *dstX1 <= dstXmin) 880 return GL_FALSE; /* totally out (left) of bounds */ 881 if (*dstX0 >= dstXmax && *dstX1 >= dstXmax) 882 return GL_FALSE; /* totally out (right) of bounds */ 883 884 if (*dstY0 == *dstY1) 885 return GL_FALSE; 886 if (*dstY0 <= dstYmin && *dstY1 <= dstYmin) 887 return GL_FALSE; 888 if (*dstY0 >= dstYmax && *dstY1 >= dstYmax) 889 return GL_FALSE; 890 891 if (*srcX0 == *srcX1) 892 return GL_FALSE; 893 if (*srcX0 <= srcXmin && *srcX1 <= srcXmin) 894 return GL_FALSE; 895 if (*srcX0 >= srcXmax && *srcX1 >= srcXmax) 896 return GL_FALSE; 897 898 if (*srcY0 == *srcY1) 899 return GL_FALSE; 900 if (*srcY0 <= srcYmin && *srcY1 <= srcYmin) 901 return GL_FALSE; 902 if (*srcY0 >= srcYmax && *srcY1 >= srcYmax) 903 return GL_FALSE; 904 905 /* 906 * dest clip 907 */ 908 clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax); 909 clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax); 910 clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin); 911 clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin); 912 913 /* 914 * src clip (just swap src/dst values from above) 915 */ 916 clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax); 917 clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax); 918 clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin); 919 clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin); 920 921 /* 922 printf("PostClipX: src: %d .. %d dst: %d .. %d\n", 923 *srcX0, *srcX1, *dstX0, *dstX1); 924 printf("PostClipY: src: %d .. %d dst: %d .. %d\n", 925 *srcY0, *srcY1, *dstY0, *dstY1); 926 */ 927 928 ASSERT(*dstX0 >= dstXmin); 929 ASSERT(*dstX0 <= dstXmax); 930 ASSERT(*dstX1 >= dstXmin); 931 ASSERT(*dstX1 <= dstXmax); 932 933 ASSERT(*dstY0 >= dstYmin); 934 ASSERT(*dstY0 <= dstYmax); 935 ASSERT(*dstY1 >= dstYmin); 936 ASSERT(*dstY1 <= dstYmax); 937 938 ASSERT(*srcX0 >= srcXmin); 939 ASSERT(*srcX0 <= srcXmax); 940 ASSERT(*srcX1 >= srcXmin); 941 ASSERT(*srcX1 <= srcXmax); 942 943 ASSERT(*srcY0 >= srcYmin); 944 ASSERT(*srcY0 <= srcYmax); 945 ASSERT(*srcY1 >= srcYmin); 946 ASSERT(*srcY1 <= srcYmax); 947 948 return GL_TRUE; 949} 950