DD: Refactor BlitFramebuffer.
[mesa.git] / src / mesa / main / image.c
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 */
52 void
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 */
72 void
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 */
106 GLintptr
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 */
221 GLvoid *
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
238 GLvoid *
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
250 GLvoid *
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
262 GLvoid *
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 */
285 GLint
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 */
332 GLint
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 */
389 void
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 */
467 void
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 */
598 GLboolean
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 */
669 GLboolean
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 */
719 GLboolean
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 */
747 GLboolean
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 */
786 static inline void
787 clip_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 */
819 static inline void
820 clip_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 */
862 GLboolean
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 }