main: Nameless texture creation and deletion. Does not affect normal creation and...
[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.
45 *
46 * \param p array.
47 * \param n number of words.
48 */
49 void
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 */
63 void
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 */
97 GLintptr
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 */
212 GLvoid *
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
229 GLvoid *
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
241 GLvoid *
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
253 GLvoid *
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 */
276 GLint
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 */
323 GLint
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 */
380 void
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 */
458 void
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 */
589 GLboolean
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 */
660 GLboolean
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 */
710 GLboolean
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 */
738 GLboolean
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 */
777 static inline void
778 clip_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 */
810 static inline void
811 clip_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 */
853 GLboolean
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 }