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 | }=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>>=>>>=>>>=>>>=>>=>>=>>=>>=>>=>>>=>>>>>>>>>><>>><>>=>=>=>><>><>>><>> |