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