image.c revision 3998cfa933dcd9134b75d9f0ae2c9cfcd6f2ee45
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 */
49void
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 */
63void
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 */
97GLintptr
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 */
212GLvoid *
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
229GLvoid *
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
241GLvoid *
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
253GLvoid *
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 */
276GLint
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 */
323GLint
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 */
380void
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 */
458void
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 */
589GLboolean
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 */
660GLboolean
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 */
710GLboolean
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 */
738GLboolean
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 */
777static inline void
778clip_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 */
810static inline void
811clip_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 */
853GLboolean
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}
950