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
_mesa_swap2(GLushort * p,GLuint n)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
_mesa_swap4(GLuint * p,GLuint n)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
_mesa_image_offset(GLuint dimensions,const struct gl_pixelstore_attrib * packing,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint img,GLint row,GLint column)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 *
_mesa_image_address(GLuint dimensions,const struct gl_pixelstore_attrib * packing,const GLvoid * image,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint img,GLint row,GLint column)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 *
_mesa_image_address1d(const struct gl_pixelstore_attrib * packing,const GLvoid * image,GLsizei width,GLenum format,GLenum type,GLint column)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 *
_mesa_image_address2d(const struct gl_pixelstore_attrib * packing,const GLvoid * image,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint row,GLint column)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 *
_mesa_image_address3d(const struct gl_pixelstore_attrib * packing,const GLvoid * image,GLsizei width,GLsizei height,GLenum format,GLenum type,GLint img,GLint row,GLint column)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
_mesa_image_row_stride(const struct gl_pixelstore_attrib * packing,GLint width,GLenum format,GLenum type)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
_mesa_image_image_stride(const struct gl_pixelstore_attrib * packing,GLint width,GLint height,GLenum format,GLenum type)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
_mesa_expand_bitmap(GLsizei width,GLsizei height,const struct gl_pixelstore_attrib * unpack,const GLubyte * bitmap,GLubyte * destBuffer,GLint destStride,GLubyte onValue)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
_mesa_convert_colors(GLenum srcType,const GLvoid * src,GLenum dstType,GLvoid * dst,GLuint count,const GLubyte mask[])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
_mesa_clip_drawpixels(const struct gl_context * ctx,GLint * destX,GLint * destY,GLsizei * width,GLsizei * height,struct gl_pixelstore_attrib * unpack)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
_mesa_clip_readpixels(const struct gl_context * ctx,GLint * srcX,GLint * srcY,GLsizei * width,GLsizei * height,struct gl_pixelstore_attrib * pack)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
_mesa_clip_copytexsubimage(const struct gl_context * ctx,GLint * destX,GLint * destY,GLint * srcX,GLint * srcY,GLsizei * width,GLsizei * height)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
_mesa_clip_to_region(GLint xmin,GLint ymin,GLint xmax,GLint ymax,GLint * x,GLint * y,GLsizei * width,GLsizei * height)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
clip_right_or_top(GLint * srcX0,GLint * srcX1,GLint * dstX0,GLint * dstX1,GLint maxValue)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
clip_left_or_bottom(GLint * srcX0,GLint * srcX1,GLint * dstX0,GLint * dstX1,GLint minValue)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
_mesa_clip_blit(struct gl_context * ctx,GLint * srcX0,GLint * srcY0,GLint * srcX1,GLint * srcY1,GLint * dstX0,GLint * dstY0,GLint * dstX1,GLint * dstY1)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