Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Mesa 3-D graphics library
3
 *
4
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5
 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included
15
 * in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
 
27
/**
28
 * \file image.c
29
 * Image handling.
30
 */
31
 
32
 
33
#include "glheader.h"
34
#include "colormac.h"
35
#include "glformats.h"
36
#include "image.h"
37
#include "imports.h"
38
#include "macros.h"
39
#include "mtypes.h"
40
 
41
 
42
 
43
/**
44
 * Flip the order of the 2 bytes in each word in the given array (src) and
45
 * store the result in another array (dst). For in-place byte-swapping this
46
 * function can be called with the same array for src and dst.
47
 *
48
 * \param dst the array where byte-swapped data will be stored.
49
 * \param src the array with the source data we want to byte-swap.
50
 * \param n number of words.
51
 */
52
void
53
_mesa_swap2_copy( GLushort *dst, GLushort *src, GLuint n )
54
{
55
   GLuint i;
56
   for (i = 0; i < n; i++) {
57
      dst[i] = (src[i] >> 8) | ((src[i] << 8) & 0xff00);
58
   }
59
}
60
 
61
 
62
 
63
/*
64
 * Flip the order of the 4 bytes in each word in the given array (src) and
65
 * store the result in another array (dst). For in-place byte-swapping this
66
 * function can be called with the same array for src and dst.
67
 *
68
 * \param dst the array where byte-swapped data will be stored.
69
 * \param src the array with the source data we want to byte-swap.
70
 * \param n number of words.
71
 */
72
void
73
_mesa_swap4_copy( GLuint *dst, GLuint *src, GLuint n )
74
{
75
   GLuint i, a, b;
76
   for (i = 0; i < n; i++) {
77
      b = src[i];
78
      a =  (b >> 24)
79
	| ((b >> 8) & 0xff00)
80
	| ((b << 8) & 0xff0000)
81
	| ((b << 24) & 0xff000000);
82
      dst[i] = a;
83
   }
84
}
85
 
86
 
87
/**
88
 * Return the byte offset of a specific pixel in an image (1D, 2D or 3D).
89
 *
90
 * Pixel unpacking/packing parameters are observed according to \p packing.
91
 *
92
 * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
93
 * \param packing  the pixelstore attributes
94
 * \param width  the image width
95
 * \param height  the image height
96
 * \param format  the pixel format (must be validated beforehand)
97
 * \param type  the pixel data type (must be validated beforehand)
98
 * \param img  which image in the volume (0 for 1D or 2D images)
99
 * \param row  row of pixel in the image (0 for 1D images)
100
 * \param column column of pixel in the image
101
 *
102
 * \return offset of pixel.
103
 *
104
 * \sa gl_pixelstore_attrib.
105
 */
106
GLintptr
107
_mesa_image_offset( GLuint dimensions,
108
                    const struct gl_pixelstore_attrib *packing,
109
                    GLsizei width, GLsizei height,
110
                    GLenum format, GLenum type,
111
                    GLint img, GLint row, GLint column )
112
{
113
   GLint alignment;        /* 1, 2 or 4 */
114
   GLint pixels_per_row;
115
   GLint rows_per_image;
116
   GLint skiprows;
117
   GLint skippixels;
118
   GLint skipimages;       /* for 3-D volume images */
119
   GLintptr offset;
120
 
121
   assert(dimensions >= 1 && dimensions <= 3);
122
 
123
   alignment = packing->Alignment;
124
   if (packing->RowLength > 0) {
125
      pixels_per_row = packing->RowLength;
126
   }
127
   else {
128
      pixels_per_row = width;
129
   }
130
   if (packing->ImageHeight > 0) {
131
      rows_per_image = packing->ImageHeight;
132
   }
133
   else {
134
      rows_per_image = height;
135
   }
136
 
137
   skippixels = packing->SkipPixels;
138
   /* Note: SKIP_ROWS _is_ used for 1D images */
139
   skiprows = packing->SkipRows;
140
   /* Note: SKIP_IMAGES is only used for 3D images */
141
   skipimages = (dimensions == 3) ? packing->SkipImages : 0;
142
 
143
   if (type == GL_BITMAP) {
144
      /* BITMAP data */
145
      GLint bytes_per_row;
146
      GLint bytes_per_image;
147
      /* components per pixel for color or stencil index: */
148
      const GLint comp_per_pixel = 1;
149
 
150
      /* The pixel type and format should have been error checked earlier */
151
      assert(format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX);
152
 
153
      bytes_per_row = alignment
154
                    * DIV_ROUND_UP( comp_per_pixel*pixels_per_row, 8*alignment );
155
 
156
      bytes_per_image = bytes_per_row * rows_per_image;
157
 
158
      offset = (skipimages + img) * bytes_per_image
159
                 + (skiprows + row) * bytes_per_row
160
                 + (skippixels + column) / 8;
161
   }
162
   else {
163
      /* Non-BITMAP data */
164
      GLint bytes_per_pixel, bytes_per_row, remainder, bytes_per_image;
165
      GLint topOfImage;
166
 
167
      bytes_per_pixel = _mesa_bytes_per_pixel( format, type );
168
 
169
      /* The pixel type and format should have been error checked earlier */
170
      assert(bytes_per_pixel > 0);
171
 
172
      bytes_per_row = pixels_per_row * bytes_per_pixel;
173
      remainder = bytes_per_row % alignment;
174
      if (remainder > 0)
175
         bytes_per_row += (alignment - remainder);
176
 
177
      assert(bytes_per_row % alignment == 0);
178
 
179
      bytes_per_image = bytes_per_row * rows_per_image;
180
 
181
      if (packing->Invert) {
182
         /* set pixel_addr to the last row */
183
         topOfImage = bytes_per_row * (height - 1);
184
         bytes_per_row = -bytes_per_row;
185
      }
186
      else {
187
         topOfImage = 0;
188
      }
189
 
190
      /* compute final pixel address */
191
      offset = (skipimages + img) * bytes_per_image
192
                 + topOfImage
193
                 + (skiprows + row) * bytes_per_row
194
                 + (skippixels + column) * bytes_per_pixel;
195
   }
196
 
197
   return offset;
198
}
199
 
200
 
201
/**
202
 * Return the address of a specific pixel in an image (1D, 2D or 3D).
203
 *
204
 * Pixel unpacking/packing parameters are observed according to \p packing.
205
 *
206
 * \param dimensions either 1, 2 or 3 to indicate dimensionality of image
207
 * \param packing  the pixelstore attributes
208
 * \param image  starting address of image data
209
 * \param width  the image width
210
 * \param height  the image height
211
 * \param format  the pixel format (must be validated beforehand)
212
 * \param type  the pixel data type (must be validated beforehand)
213
 * \param img  which image in the volume (0 for 1D or 2D images)
214
 * \param row  row of pixel in the image (0 for 1D images)
215
 * \param column column of pixel in the image
216
 *
217
 * \return address of pixel.
218
 *
219
 * \sa gl_pixelstore_attrib.
220
 */
221
GLvoid *
222
_mesa_image_address( GLuint dimensions,
223
                     const struct gl_pixelstore_attrib *packing,
224
                     const GLvoid *image,
225
                     GLsizei width, GLsizei height,
226
                     GLenum format, GLenum type,
227
                     GLint img, GLint row, GLint column )
228
{
229
   const GLubyte *addr = (const GLubyte *) image;
230
 
231
   addr += _mesa_image_offset(dimensions, packing, width, height,
232
                              format, type, img, row, column);
233
 
234
   return (GLvoid *) addr;
235
}
236
 
237
 
238
GLvoid *
239
_mesa_image_address1d( const struct gl_pixelstore_attrib *packing,
240
                       const GLvoid *image,
241
                       GLsizei width,
242
                       GLenum format, GLenum type,
243
                       GLint column )
244
{
245
   return _mesa_image_address(1, packing, image, width, 1,
246
                              format, type, 0, 0, column);
247
}
248
 
249
 
250
GLvoid *
251
_mesa_image_address2d( const struct gl_pixelstore_attrib *packing,
252
                       const GLvoid *image,
253
                       GLsizei width, GLsizei height,
254
                       GLenum format, GLenum type,
255
                       GLint row, GLint column )
256
{
257
   return _mesa_image_address(2, packing, image, width, height,
258
                              format, type, 0, row, column);
259
}
260
 
261
 
262
GLvoid *
263
_mesa_image_address3d( const struct gl_pixelstore_attrib *packing,
264
                       const GLvoid *image,
265
                       GLsizei width, GLsizei height,
266
                       GLenum format, GLenum type,
267
                       GLint img, GLint row, GLint column )
268
{
269
   return _mesa_image_address(3, packing, image, width, height,
270
                              format, type, img, row, column);
271
}
272
 
273
 
274
 
275
/**
276
 * Compute the stride (in bytes) between image rows.
277
 *
278
 * \param packing the pixelstore attributes
279
 * \param width image width.
280
 * \param format pixel format.
281
 * \param type pixel data type.
282
 *
283
 * \return the stride in bytes for the given parameters, or -1 if error
284
 */
285
GLint
286
_mesa_image_row_stride( const struct gl_pixelstore_attrib *packing,
287
                        GLint width, GLenum format, GLenum type )
288
{
289
   GLint bytesPerRow, remainder;
290
 
291
   assert(packing);
292
 
293
   if (type == GL_BITMAP) {
294
      if (packing->RowLength == 0) {
295
         bytesPerRow = (width + 7) / 8;
296
      }
297
      else {
298
         bytesPerRow = (packing->RowLength + 7) / 8;
299
      }
300
   }
301
   else {
302
      /* Non-BITMAP data */
303
      const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
304
      if (bytesPerPixel <= 0)
305
         return -1;  /* error */
306
      if (packing->RowLength == 0) {
307
         bytesPerRow = bytesPerPixel * width;
308
      }
309
      else {
310
         bytesPerRow = bytesPerPixel * packing->RowLength;
311
      }
312
   }
313
 
314
   remainder = bytesPerRow % packing->Alignment;
315
   if (remainder > 0) {
316
      bytesPerRow += (packing->Alignment - remainder);
317
   }
318
 
319
   if (packing->Invert) {
320
      /* negate the bytes per row (negative row stride) */
321
      bytesPerRow = -bytesPerRow;
322
   }
323
 
324
   return bytesPerRow;
325
}
326
 
327
 
328
/*
329
 * Compute the stride between images in a 3D texture (in bytes) for the given
330
 * pixel packing parameters and image width, format and type.
331
 */
332
GLint
333
_mesa_image_image_stride( const struct gl_pixelstore_attrib *packing,
334
                          GLint width, GLint height,
335
                          GLenum format, GLenum type )
336
{
337
   GLint bytesPerRow, bytesPerImage, remainder;
338
 
339
   assert(packing);
340
 
341
   if (type == GL_BITMAP) {
342
      if (packing->RowLength == 0) {
343
         bytesPerRow = (width + 7) / 8;
344
      }
345
      else {
346
         bytesPerRow = (packing->RowLength + 7) / 8;
347
      }
348
   }
349
   else {
350
      const GLint bytesPerPixel = _mesa_bytes_per_pixel(format, type);
351
 
352
      if (bytesPerPixel <= 0)
353
         return -1;  /* error */
354
      if (packing->RowLength == 0) {
355
         bytesPerRow = bytesPerPixel * width;
356
      }
357
      else {
358
         bytesPerRow = bytesPerPixel * packing->RowLength;
359
      }
360
   }
361
 
362
   remainder = bytesPerRow % packing->Alignment;
363
   if (remainder > 0)
364
      bytesPerRow += (packing->Alignment - remainder);
365
 
366
   if (packing->ImageHeight == 0)
367
      bytesPerImage = bytesPerRow * height;
368
   else
369
      bytesPerImage = bytesPerRow * packing->ImageHeight;
370
 
371
   return bytesPerImage;
372
}
373
 
374
 
375
 
376
/**
377
 * "Expand" a bitmap from 1-bit per pixel to 8-bits per pixel.
378
 * This is typically used to convert a bitmap into a GLubyte/pixel texture.
379
 * "On" bits will set texels to \p onValue.
380
 * "Off" bits will not modify texels.
381
 * \param width  src bitmap width in pixels
382
 * \param height  src bitmap height in pixels
383
 * \param unpack  bitmap unpacking state
384
 * \param bitmap  the src bitmap data
385
 * \param destBuffer  start of dest buffer
386
 * \param destStride  row stride in dest buffer
387
 * \param onValue  if bit is 1, set destBuffer pixel to this value
388
 */
389
void
390
_mesa_expand_bitmap(GLsizei width, GLsizei height,
391
                    const struct gl_pixelstore_attrib *unpack,
392
                    const GLubyte *bitmap,
393
                    GLubyte *destBuffer, GLint destStride,
394
                    GLubyte onValue)
395
{
396
   const GLubyte *srcRow = (const GLubyte *)
397
      _mesa_image_address2d(unpack, bitmap, width, height,
398
                            GL_COLOR_INDEX, GL_BITMAP, 0, 0);
399
   const GLint srcStride = _mesa_image_row_stride(unpack, width,
400
                                                  GL_COLOR_INDEX, GL_BITMAP);
401
   GLint row, col;
402
 
403
#define SET_PIXEL(COL, ROW) \
404
   destBuffer[(ROW) * destStride + (COL)] = onValue;
405
 
406
   for (row = 0; row < height; row++) {
407
      const GLubyte *src = srcRow;
408
 
409
      if (unpack->LsbFirst) {
410
         /* Lsb first */
411
         GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
412
         for (col = 0; col < width; col++) {
413
 
414
            if (*src & mask) {
415
               SET_PIXEL(col, row);
416
            }
417
 
418
            if (mask == 128U) {
419
               src++;
420
               mask = 1U;
421
            }
422
            else {
423
               mask = mask << 1;
424
            }
425
         }
426
 
427
         /* get ready for next row */
428
         if (mask != 1)
429
            src++;
430
      }
431
      else {
432
         /* Msb first */
433
         GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
434
         for (col = 0; col < width; col++) {
435
 
436
            if (*src & mask) {
437
               SET_PIXEL(col, row);
438
            }
439
 
440
            if (mask == 1U) {
441
               src++;
442
               mask = 128U;
443
            }
444
            else {
445
               mask = mask >> 1;
446
            }
447
         }
448
 
449
         /* get ready for next row */
450
         if (mask != 128)
451
            src++;
452
      }
453
 
454
      srcRow += srcStride;
455
   } /* row */
456
 
457
#undef SET_PIXEL
458
}
459
 
460
 
461
 
462
 
463
/**
464
 * Convert an array of RGBA colors from one datatype to another.
465
 * NOTE: src may equal dst.  In that case, we use a temporary buffer.
466
 */
467
void
468
_mesa_convert_colors(GLenum srcType, const GLvoid *src,
469
                     GLenum dstType, GLvoid *dst,
470
                     GLuint count, const GLubyte mask[])
471
{
472
   GLuint *tempBuffer;
473
   const GLboolean useTemp = (src == dst);
474
 
475
   tempBuffer = malloc(count * MAX_PIXEL_BYTES);
476
   if (!tempBuffer)
477
      return;
478
 
479
   assert(srcType != dstType);
480
 
481
   switch (srcType) {
482
   case GL_UNSIGNED_BYTE:
483
      if (dstType == GL_UNSIGNED_SHORT) {
484
         const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
485
         GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
486
         GLuint i;
487
         for (i = 0; i < count; i++) {
488
            if (!mask || mask[i]) {
489
               dst2[i][RCOMP] = UBYTE_TO_USHORT(src1[i][RCOMP]);
490
               dst2[i][GCOMP] = UBYTE_TO_USHORT(src1[i][GCOMP]);
491
               dst2[i][BCOMP] = UBYTE_TO_USHORT(src1[i][BCOMP]);
492
               dst2[i][ACOMP] = UBYTE_TO_USHORT(src1[i][ACOMP]);
493
            }
494
         }
495
         if (useTemp)
496
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
497
      }
498
      else {
499
         const GLubyte (*src1)[4] = (const GLubyte (*)[4]) src;
500
         GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
501
         GLuint i;
502
         assert(dstType == GL_FLOAT);
503
         for (i = 0; i < count; i++) {
504
            if (!mask || mask[i]) {
505
               dst4[i][RCOMP] = UBYTE_TO_FLOAT(src1[i][RCOMP]);
506
               dst4[i][GCOMP] = UBYTE_TO_FLOAT(src1[i][GCOMP]);
507
               dst4[i][BCOMP] = UBYTE_TO_FLOAT(src1[i][BCOMP]);
508
               dst4[i][ACOMP] = UBYTE_TO_FLOAT(src1[i][ACOMP]);
509
            }
510
         }
511
         if (useTemp)
512
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
513
      }
514
      break;
515
   case GL_UNSIGNED_SHORT:
516
      if (dstType == GL_UNSIGNED_BYTE) {
517
         const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
518
         GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
519
         GLuint i;
520
         for (i = 0; i < count; i++) {
521
            if (!mask || mask[i]) {
522
               dst1[i][RCOMP] = USHORT_TO_UBYTE(src2[i][RCOMP]);
523
               dst1[i][GCOMP] = USHORT_TO_UBYTE(src2[i][GCOMP]);
524
               dst1[i][BCOMP] = USHORT_TO_UBYTE(src2[i][BCOMP]);
525
               dst1[i][ACOMP] = USHORT_TO_UBYTE(src2[i][ACOMP]);
526
            }
527
         }
528
         if (useTemp)
529
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
530
      }
531
      else {
532
         const GLushort (*src2)[4] = (const GLushort (*)[4]) src;
533
         GLfloat (*dst4)[4] = (GLfloat (*)[4]) (useTemp ? tempBuffer : dst);
534
         GLuint i;
535
         assert(dstType == GL_FLOAT);
536
         for (i = 0; i < count; i++) {
537
            if (!mask || mask[i]) {
538
               dst4[i][RCOMP] = USHORT_TO_FLOAT(src2[i][RCOMP]);
539
               dst4[i][GCOMP] = USHORT_TO_FLOAT(src2[i][GCOMP]);
540
               dst4[i][BCOMP] = USHORT_TO_FLOAT(src2[i][BCOMP]);
541
               dst4[i][ACOMP] = USHORT_TO_FLOAT(src2[i][ACOMP]);
542
            }
543
         }
544
         if (useTemp)
545
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLfloat));
546
      }
547
      break;
548
   case GL_FLOAT:
549
      if (dstType == GL_UNSIGNED_BYTE) {
550
         const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
551
         GLubyte (*dst1)[4] = (GLubyte (*)[4]) (useTemp ? tempBuffer : dst);
552
         GLuint i;
553
         for (i = 0; i < count; i++) {
554
            if (!mask || mask[i])
555
               _mesa_unclamped_float_rgba_to_ubyte(dst1[i], src4[i]);
556
         }
557
         if (useTemp)
558
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLubyte));
559
      }
560
      else {
561
         const GLfloat (*src4)[4] = (const GLfloat (*)[4]) src;
562
         GLushort (*dst2)[4] = (GLushort (*)[4]) (useTemp ? tempBuffer : dst);
563
         GLuint i;
564
         assert(dstType == GL_UNSIGNED_SHORT);
565
         for (i = 0; i < count; i++) {
566
            if (!mask || mask[i]) {
567
               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][RCOMP], src4[i][RCOMP]);
568
               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][GCOMP], src4[i][GCOMP]);
569
               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][BCOMP], src4[i][BCOMP]);
570
               UNCLAMPED_FLOAT_TO_USHORT(dst2[i][ACOMP], src4[i][ACOMP]);
571
            }
572
         }
573
         if (useTemp)
574
            memcpy(dst, tempBuffer, count * 4 * sizeof(GLushort));
575
      }
576
      break;
577
   default:
578
      _mesa_problem(NULL, "Invalid datatype in _mesa_convert_colors");
579
   }
580
 
581
   free(tempBuffer);
582
}
583
 
584
 
585
 
586
 
587
/**
588
 * Perform basic clipping for glDrawPixels.  The image's position and size
589
 * and the unpack SkipPixels and SkipRows are adjusted so that the image
590
 * region is entirely within the window and scissor bounds.
591
 * NOTE: this will only work when glPixelZoom is (1, 1) or (1, -1).
592
 * If Pixel.ZoomY is -1, *destY will be changed to be the first row which
593
 * we'll actually write.  Beforehand, *destY-1 is the first drawing row.
594
 *
595
 * \return  GL_TRUE if image is ready for drawing or
596
 *          GL_FALSE if image was completely clipped away (draw nothing)
597
 */
598
GLboolean
599
_mesa_clip_drawpixels(const struct gl_context *ctx,
600
                      GLint *destX, GLint *destY,
601
                      GLsizei *width, GLsizei *height,
602
                      struct gl_pixelstore_attrib *unpack)
603
{
604
   const struct gl_framebuffer *buffer = ctx->DrawBuffer;
605
 
606
   if (unpack->RowLength == 0) {
607
      unpack->RowLength = *width;
608
   }
609
 
610
   assert(ctx->Pixel.ZoomX == 1.0F);
611
   assert(ctx->Pixel.ZoomY == 1.0F || ctx->Pixel.ZoomY == -1.0F);
612
 
613
   /* left clipping */
614
   if (*destX < buffer->_Xmin) {
615
      unpack->SkipPixels += (buffer->_Xmin - *destX);
616
      *width -= (buffer->_Xmin - *destX);
617
      *destX = buffer->_Xmin;
618
   }
619
   /* right clipping */
620
   if (*destX + *width > buffer->_Xmax)
621
      *width -= (*destX + *width - buffer->_Xmax);
622
 
623
   if (*width <= 0)
624
      return GL_FALSE;
625
 
626
   if (ctx->Pixel.ZoomY == 1.0F) {
627
      /* bottom clipping */
628
      if (*destY < buffer->_Ymin) {
629
         unpack->SkipRows += (buffer->_Ymin - *destY);
630
         *height -= (buffer->_Ymin - *destY);
631
         *destY = buffer->_Ymin;
632
      }
633
      /* top clipping */
634
      if (*destY + *height > buffer->_Ymax)
635
         *height -= (*destY + *height - buffer->_Ymax);
636
   }
637
   else { /* upside down */
638
      /* top clipping */
639
      if (*destY > buffer->_Ymax) {
640
         unpack->SkipRows += (*destY - buffer->_Ymax);
641
         *height -= (*destY - buffer->_Ymax);
642
         *destY = buffer->_Ymax;
643
      }
644
      /* bottom clipping */
645
      if (*destY - *height < buffer->_Ymin)
646
         *height -= (buffer->_Ymin - (*destY - *height));
647
      /* adjust destY so it's the first row to write to */
648
      (*destY)--;
649
   }
650
 
651
   if (*height <= 0)
652
      return GL_FALSE;
653
 
654
   return GL_TRUE;
655
}
656
 
657
 
658
/**
659
 * Perform clipping for glReadPixels.  The image's window position
660
 * and size, and the pack skipPixels, skipRows and rowLength are adjusted
661
 * so that the image region is entirely within the window bounds.
662
 * Note: this is different from _mesa_clip_drawpixels() in that the
663
 * scissor box is ignored, and we use the bounds of the current readbuffer
664
 * surface.
665
 *
666
 * \return  GL_TRUE if region to read is in bounds
667
 *          GL_FALSE if region is completely out of bounds (nothing to read)
668
 */
669
GLboolean
670
_mesa_clip_readpixels(const struct gl_context *ctx,
671
                      GLint *srcX, GLint *srcY,
672
                      GLsizei *width, GLsizei *height,
673
                      struct gl_pixelstore_attrib *pack)
674
{
675
   const struct gl_framebuffer *buffer = ctx->ReadBuffer;
676
 
677
   if (pack->RowLength == 0) {
678
      pack->RowLength = *width;
679
   }
680
 
681
   /* left clipping */
682
   if (*srcX < 0) {
683
      pack->SkipPixels += (0 - *srcX);
684
      *width -= (0 - *srcX);
685
      *srcX = 0;
686
   }
687
   /* right clipping */
688
   if (*srcX + *width > (GLsizei) buffer->Width)
689
      *width -= (*srcX + *width - buffer->Width);
690
 
691
   if (*width <= 0)
692
      return GL_FALSE;
693
 
694
   /* bottom clipping */
695
   if (*srcY < 0) {
696
      pack->SkipRows += (0 - *srcY);
697
      *height -= (0 - *srcY);
698
      *srcY = 0;
699
   }
700
   /* top clipping */
701
   if (*srcY + *height > (GLsizei) buffer->Height)
702
      *height -= (*srcY + *height - buffer->Height);
703
 
704
   if (*height <= 0)
705
      return GL_FALSE;
706
 
707
   return GL_TRUE;
708
}
709
 
710
 
711
/**
712
 * Do clipping for a glCopyTexSubImage call.
713
 * The framebuffer source region might extend outside the framebuffer
714
 * bounds.  Clip the source region against the framebuffer bounds and
715
 * adjust the texture/dest position and size accordingly.
716
 *
717
 * \return GL_FALSE if region is totally clipped, GL_TRUE otherwise.
718
 */
719
GLboolean
720
_mesa_clip_copytexsubimage(const struct gl_context *ctx,
721
                           GLint *destX, GLint *destY,
722
                           GLint *srcX, GLint *srcY,
723
                           GLsizei *width, GLsizei *height)
724
{
725
   const struct gl_framebuffer *fb = ctx->ReadBuffer;
726
   const GLint srcX0 = *srcX, srcY0 = *srcY;
727
 
728
   if (_mesa_clip_to_region(0, 0, fb->Width, fb->Height,
729
                            srcX, srcY, width, height)) {
730
      *destX = *destX + *srcX - srcX0;
731
      *destY = *destY + *srcY - srcY0;
732
 
733
      return GL_TRUE;
734
   }
735
   else {
736
      return GL_FALSE;
737
   }
738
}
739
 
740
 
741
 
742
/**
743
 * Clip the rectangle defined by (x, y, width, height) against the bounds
744
 * specified by [xmin, xmax) and [ymin, ymax).
745
 * \return GL_FALSE if rect is totally clipped, GL_TRUE otherwise.
746
 */
747
GLboolean
748
_mesa_clip_to_region(GLint xmin, GLint ymin,
749
                     GLint xmax, GLint ymax,
750
                     GLint *x, GLint *y,
751
                     GLsizei *width, GLsizei *height )
752
{
753
   /* left clipping */
754
   if (*x < xmin) {
755
      *width -= (xmin - *x);
756
      *x = xmin;
757
   }
758
 
759
   /* right clipping */
760
   if (*x + *width > xmax)
761
      *width -= (*x + *width - xmax);
762
 
763
   if (*width <= 0)
764
      return GL_FALSE;
765
 
766
   /* bottom (or top) clipping */
767
   if (*y < ymin) {
768
      *height -= (ymin - *y);
769
      *y = ymin;
770
   }
771
 
772
   /* top (or bottom) clipping */
773
   if (*y + *height > ymax)
774
      *height -= (*y + *height - ymax);
775
 
776
   if (*height <= 0)
777
      return GL_FALSE;
778
 
779
   return GL_TRUE;
780
}
781
 
782
 
783
/**
784
 * Clip dst coords against Xmax (or Ymax).
785
 */
786
static inline void
787
clip_right_or_top(GLint *srcX0, GLint *srcX1,
788
                  GLint *dstX0, GLint *dstX1,
789
                  GLint maxValue)
790
{
791
   GLfloat t, bias;
792
 
793
   if (*dstX1 > maxValue) {
794
      /* X1 outside right edge */
795
      assert(*dstX0 < maxValue); /* X0 should be inside right edge */
796
      t = (GLfloat) (maxValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
797
      /* chop off [t, 1] part */
798
      assert(t >= 0.0 && t <= 1.0);
799
      *dstX1 = maxValue;
800
      bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
801
      *srcX1 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
802
   }
803
   else if (*dstX0 > maxValue) {
804
      /* X0 outside right edge */
805
      assert(*dstX1 < maxValue); /* X1 should be inside right edge */
806
      t = (GLfloat) (maxValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
807
      /* chop off [t, 1] part */
808
      assert(t >= 0.0 && t <= 1.0);
809
      *dstX0 = maxValue;
810
      bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
811
      *srcX0 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
812
   }
813
}
814
 
815
 
816
/**
817
 * Clip dst coords against Xmin (or Ymin).
818
 */
819
static inline void
820
clip_left_or_bottom(GLint *srcX0, GLint *srcX1,
821
                    GLint *dstX0, GLint *dstX1,
822
                    GLint minValue)
823
{
824
   GLfloat t, bias;
825
 
826
   if (*dstX0 < minValue) {
827
      /* X0 outside left edge */
828
      assert(*dstX1 > minValue); /* X1 should be inside left edge */
829
      t = (GLfloat) (minValue - *dstX0) / (GLfloat) (*dstX1 - *dstX0);
830
      /* chop off [0, t] part */
831
      assert(t >= 0.0 && t <= 1.0);
832
      *dstX0 = minValue;
833
      bias = (*srcX0 < *srcX1) ? 0.5F : -0.5F;
834
      *srcX0 = *srcX0 + (GLint) (t * (*srcX1 - *srcX0) + bias);
835
   }
836
   else if (*dstX1 < minValue) {
837
      /* X1 outside left edge */
838
      assert(*dstX0 > minValue); /* X0 should be inside left edge */
839
      t = (GLfloat) (minValue - *dstX1) / (GLfloat) (*dstX0 - *dstX1);
840
      /* chop off [0, t] part */
841
      assert(t >= 0.0 && t <= 1.0);
842
      *dstX1 = minValue;
843
      bias = (*srcX0 < *srcX1) ? -0.5F : 0.5F;
844
      *srcX1 = *srcX1 + (GLint) (t * (*srcX0 - *srcX1) + bias);
845
   }
846
}
847
 
848
 
849
/**
850
 * Do clipping of blit src/dest rectangles.
851
 * The dest rect is clipped against both the buffer bounds and scissor bounds.
852
 * The src rect is just clipped against the buffer bounds.
853
 *
854
 * When either the src or dest rect is clipped, the other is also clipped
855
 * proportionately!
856
 *
857
 * Note that X0 need not be less than X1 (same for Y) for either the source
858
 * and dest rects.  That makes the clipping a little trickier.
859
 *
860
 * \return GL_TRUE if anything is left to draw, GL_FALSE if totally clipped
861
 */
862
GLboolean
863
_mesa_clip_blit(struct gl_context *ctx,
864
                const struct gl_framebuffer *readFb,
865
                const struct gl_framebuffer *drawFb,
866
                GLint *srcX0, GLint *srcY0, GLint *srcX1, GLint *srcY1,
867
                GLint *dstX0, GLint *dstY0, GLint *dstX1, GLint *dstY1)
868
{
869
   const GLint srcXmin = 0;
870
   const GLint srcXmax = readFb->Width;
871
   const GLint srcYmin = 0;
872
   const GLint srcYmax = readFb->Height;
873
 
874
   /* these include scissor bounds */
875
   const GLint dstXmin = drawFb->_Xmin;
876
   const GLint dstXmax = drawFb->_Xmax;
877
   const GLint dstYmin = drawFb->_Ymin;
878
   const GLint dstYmax = drawFb->_Ymax;
879
 
880
   /*
881
   printf("PreClipX:  src: %d .. %d  dst: %d .. %d\n",
882
          *srcX0, *srcX1, *dstX0, *dstX1);
883
   printf("PreClipY:  src: %d .. %d  dst: %d .. %d\n",
884
          *srcY0, *srcY1, *dstY0, *dstY1);
885
   */
886
 
887
   /* trivial rejection tests */
888
   if (*dstX0 == *dstX1)
889
      return GL_FALSE; /* no width */
890
   if (*dstX0 <= dstXmin && *dstX1 <= dstXmin)
891
      return GL_FALSE; /* totally out (left) of bounds */
892
   if (*dstX0 >= dstXmax && *dstX1 >= dstXmax)
893
      return GL_FALSE; /* totally out (right) of bounds */
894
 
895
   if (*dstY0 == *dstY1)
896
      return GL_FALSE;
897
   if (*dstY0 <= dstYmin && *dstY1 <= dstYmin)
898
      return GL_FALSE;
899
   if (*dstY0 >= dstYmax && *dstY1 >= dstYmax)
900
      return GL_FALSE;
901
 
902
   if (*srcX0 == *srcX1)
903
      return GL_FALSE;
904
   if (*srcX0 <= srcXmin && *srcX1 <= srcXmin)
905
      return GL_FALSE;
906
   if (*srcX0 >= srcXmax && *srcX1 >= srcXmax)
907
      return GL_FALSE;
908
 
909
   if (*srcY0 == *srcY1)
910
      return GL_FALSE;
911
   if (*srcY0 <= srcYmin && *srcY1 <= srcYmin)
912
      return GL_FALSE;
913
   if (*srcY0 >= srcYmax && *srcY1 >= srcYmax)
914
      return GL_FALSE;
915
 
916
   /*
917
    * dest clip
918
    */
919
   clip_right_or_top(srcX0, srcX1, dstX0, dstX1, dstXmax);
920
   clip_right_or_top(srcY0, srcY1, dstY0, dstY1, dstYmax);
921
   clip_left_or_bottom(srcX0, srcX1, dstX0, dstX1, dstXmin);
922
   clip_left_or_bottom(srcY0, srcY1, dstY0, dstY1, dstYmin);
923
 
924
   /*
925
    * src clip (just swap src/dst values from above)
926
    */
927
   clip_right_or_top(dstX0, dstX1, srcX0, srcX1, srcXmax);
928
   clip_right_or_top(dstY0, dstY1, srcY0, srcY1, srcYmax);
929
   clip_left_or_bottom(dstX0, dstX1, srcX0, srcX1, srcXmin);
930
   clip_left_or_bottom(dstY0, dstY1, srcY0, srcY1, srcYmin);
931
 
932
   /*
933
   printf("PostClipX: src: %d .. %d  dst: %d .. %d\n",
934
          *srcX0, *srcX1, *dstX0, *dstX1);
935
   printf("PostClipY: src: %d .. %d  dst: %d .. %d\n",
936
          *srcY0, *srcY1, *dstY0, *dstY1);
937
   */
938
 
939
   assert(*dstX0 >= dstXmin);
940
   assert(*dstX0 <= dstXmax);
941
   assert(*dstX1 >= dstXmin);
942
   assert(*dstX1 <= dstXmax);
943
 
944
   assert(*dstY0 >= dstYmin);
945
   assert(*dstY0 <= dstYmax);
946
   assert(*dstY1 >= dstYmin);
947
   assert(*dstY1 <= dstYmax);
948
 
949
   assert(*srcX0 >= srcXmin);
950
   assert(*srcX0 <= srcXmax);
951
   assert(*srcX1 >= srcXmin);
952
   assert(*srcX1 <= srcXmax);
953
 
954
   assert(*srcY0 >= srcYmin);
955
   assert(*srcY0 <= srcYmax);
956
   assert(*srcY1 >= srcYmin);
957
   assert(*srcY1 <= srcYmax);
958
 
959
   return GL_TRUE;
960
}