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