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