1 /* $Id: texutil.c,v 1.1 2000/03/24 20:54:21 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 * Texture utilities which may be useful to device drivers.
47 * Convert texture image data into one a specific internal format.
49 * dstFormat - the destination internal format
50 * dstWidth, dstHeight - the destination image size
51 * destImage - pointer to destination image buffer
52 * srcWidth, srcHeight - size of texture image
53 * srcFormat, srcType - format and datatype of source image
54 * srcImage - pointer to user's texture image
55 * packing - describes how user's texture image is packed.
56 * Return: pointer to resulting image data or NULL if error or out of memory
57 * or NULL if we can't process the given image format/type/internalFormat
60 * Supported type conversions:
61 * srcFormat srcType dstFormat
62 * GL_INTENSITY GL_UNSIGNED_BYTE MESA_I8
63 * GL_LUMINANCE GL_UNSIGNED_BYTE MESA_L8
64 * GL_ALPHA GL_UNSIGNED_BYTE MESA_A8
65 * GL_COLOR_INDEX GL_UNSIGNED_BYTE MESA_C8
66 * GL_LUMINANCE_ALPHA GL_UNSIGNED_BYTE MESA_L8_A8
67 * GL_RGB GL_UNSIGNED_BYTE MESA_R5_G6_B5
68 * GL_RGB GL_UNSIGNED_SHORT_5_6_5 MESA_R5_G6_B5
69 * GL_RGBA GL_UNSIGNED_BYTE MESA_A4_R4_G4_B4
70 * GL_BGRA GL_UNSIGNED_SHORT_4_4_4_4_REV MESA_A4_R4_G4_B4
71 * GL_BGRA GL_UNSIGHED_SHORT_1_5_5_5_REV MESA_A1_R5_G5_B5
72 * GL_BGRA GL_UNSIGNED_INT_8_8_8_8_REV MESA_A8_R8_G8_B8
73 * more to be added for new drivers...
76 * Some hardware only supports texture images of specific aspect ratios.
77 * This code will do power-of-two image up-scaling if that's needed.
82 _mesa_convert_teximage(MesaIntTexFormat dstFormat
,
83 GLint dstWidth
, GLint dstHeight
, GLvoid
*dstImage
,
84 GLsizei srcWidth
, GLsizei srcHeight
,
85 GLenum srcFormat
, GLenum srcType
,
86 const GLvoid
*srcImage
,
87 const struct gl_pixelstore_attrib
*packing
)
89 const GLint wScale
= dstWidth
/ srcWidth
; /* must be power of two */
90 const GLint hScale
= dstHeight
/ srcHeight
; /* must be power of two */
91 ASSERT(dstWidth
>= srcWidth
);
92 ASSERT(dstHeight
>= srcHeight
);
102 if (srcType
!= GL_UNSIGNED_BYTE
||
103 ((srcFormat
!= GL_INTENSITY
) &&
104 (srcFormat
!= GL_LUMINANCE
) &&
105 (srcFormat
!= GL_ALPHA
) &&
106 (srcFormat
!= GL_COLOR_INDEX
))) {
107 /* bad internal format / srcFormat combination */
111 /* store as 8-bit texels */
112 if (wScale
== 1 && hScale
== 1) {
113 /* no scaling needed - fast case */
114 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
115 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
116 const GLint srcStride
= _mesa_image_row_stride(packing
,
117 srcWidth
, srcFormat
, srcType
);
118 GLubyte
*dst
= (GLubyte
*) dstImage
;
120 for (row
= 0; row
< dstHeight
; row
++) {
121 MEMCPY(dst
, src
, dstWidth
* sizeof(GLubyte
));
127 /* must rescale image */
128 GLubyte
*dst
= (GLubyte
*) dstImage
;
130 for (row
= 0; row
< dstHeight
; row
++) {
131 GLint srcRow
= row
/ hScale
;
132 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
133 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
135 for (col
= 0; col
< dstWidth
; col
++) {
136 dst
[col
] = src
[col
/ wScale
];
145 if (srcType
!= GL_UNSIGNED_BYTE
|| srcFormat
!= GL_LUMINANCE_ALPHA
) {
149 /* store as 16-bit texels */
150 if (wScale
== 1 && hScale
== 1) {
151 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
152 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
153 const GLint srcStride
= _mesa_image_row_stride(packing
,
154 srcWidth
, srcFormat
, srcType
);
155 GLushort
*dst
= dstImage
;
157 for (row
= 0; row
< dstHeight
; row
++) {
158 for (col
= 0; col
< dstWidth
; col
++) {
159 GLubyte alpha
= src
[col
* 2 + 0];
160 GLubyte luminance
= src
[col
* 2 + 1];
161 dst
[col
] = ((GLushort
) luminance
<< 8) | alpha
;
169 GLushort
*dst
= dstImage
;
171 for (row
= 0; row
< dstHeight
; row
++) {
172 GLint srcRow
= row
/ hScale
;
173 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
174 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
175 const GLint srcStride
= _mesa_image_row_stride(packing
,
176 srcWidth
, srcFormat
, srcType
);
177 for (col
= 0; col
< dstWidth
; col
++) {
178 GLint srcCol
= col
/ wScale
;
179 GLubyte alpha
= src
[srcCol
* 2 + 0];
180 GLubyte luminance
= src
[srcCol
* 2 + 1];
181 dst
[col
] = ((GLushort
) luminance
<< 8) | alpha
;
191 if (srcFormat
== GL_RGB
&& srcType
== GL_UNSIGNED_SHORT_5_6_5
) {
192 /* special, optimized case */
193 if (wScale
== 1 && hScale
== 1) {
194 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
195 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
196 const GLint srcStride
= _mesa_image_row_stride(packing
,
197 srcWidth
, srcFormat
, srcType
);
198 GLushort
*dst
= dstImage
;
200 for (row
= 0; row
< dstHeight
; row
++) {
201 MEMCPY(dst
, src
, dstWidth
* sizeof(GLushort
));
207 /* must rescale image */
208 GLushort
*dst
= dstImage
;
210 for (row
= 0; row
< dstHeight
; row
++) {
211 GLint srcRow
= row
/ hScale
;
212 const GLushort
*src
= _mesa_image_address(packing
, srcImage
,
213 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
215 for (col
= 0; col
< dstWidth
; col
++) {
216 dst
[col
] = src
[col
/ wScale
];
222 else if (srcFormat
== GL_RGB
&& srcType
== GL_UNSIGNED_BYTE
) {
224 if (wScale
== 1 && hScale
== 1) {
225 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
226 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
227 const GLint srcStride
= _mesa_image_row_stride(packing
,
228 srcWidth
, srcFormat
, srcType
);
229 GLushort
*dst
= dstImage
;
231 for (row
= 0; row
< dstHeight
; row
++) {
233 for (col
= col3
= 0; col
< dstWidth
; col
++, col3
+= 3) {
234 GLubyte r
= src
[col3
+ 0];
235 GLubyte g
= src
[col3
+ 1];
236 GLubyte b
= src
[col3
+ 2];
237 dst
[col
] = ((r
& 0xf8) << 8)
246 /* must rescale image */
247 GLushort
*dst
= dstImage
;
249 for (row
= 0; row
< dstHeight
; row
++) {
250 GLint srcRow
= row
/ hScale
;
251 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
252 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
254 for (col
= 0; col
< dstWidth
; col
++) {
255 GLint col3
= (col
/ wScale
) * 3;
256 GLubyte r
= src
[col3
+ 0];
257 GLubyte g
= src
[col3
+ 1];
258 GLubyte b
= src
[col3
+ 2];
259 dst
[col
] = ((r
& 0xf8) << 8)
268 /* can't handle this srcFormat/srcType combination */
273 case MESA_A4_R4_G4_B4
:
274 /* store as 16-bit texels (GR_TEXFMT_ARGB_4444) */
275 if (srcFormat
== GL_BGRA
&& srcType
== GL_UNSIGNED_SHORT_4_4_4_4_REV
){
276 /* special, optimized case */
277 if (wScale
== 1 && hScale
== 1) {
278 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
279 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
280 const GLint srcStride
= _mesa_image_row_stride(packing
,
281 srcWidth
, srcFormat
, srcType
);
282 GLushort
*dst
= dstImage
;
284 for (row
= 0; row
< dstHeight
; row
++) {
285 MEMCPY(dst
, src
, dstWidth
* sizeof(GLushort
));
291 /* must rescale image */
292 GLushort
*dst
= dstImage
;
294 for (row
= 0; row
< dstHeight
; row
++) {
295 GLint srcRow
= row
/ hScale
;
296 const GLushort
*src
= _mesa_image_address(packing
, srcImage
,
297 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
299 for (col
= 0; col
< dstWidth
; col
++) {
300 dst
[col
] = src
[col
/ wScale
];
306 else if (srcFormat
== GL_RGBA
&& srcType
== GL_UNSIGNED_BYTE
) {
308 if (wScale
== 1 && hScale
== 1) {
309 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
310 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
311 const GLint srcStride
= _mesa_image_row_stride(packing
,
312 srcWidth
, srcFormat
, srcType
);
313 GLushort
*dst
= dstImage
;
315 for (row
= 0; row
< dstHeight
; row
++) {
317 for (col
= col4
= 0; col
< dstWidth
; col
++, col4
+= 4) {
318 GLubyte r
= src
[col4
+ 0];
319 GLubyte g
= src
[col4
+ 1];
320 GLubyte b
= src
[col4
+ 2];
321 GLubyte a
= src
[col4
+ 3];
322 dst
[col
] = ((a
& 0xf0) << 8)
332 /* must rescale image */
333 GLushort
*dst
= dstImage
;
335 for (row
= 0; row
< dstHeight
; row
++) {
336 GLint srcRow
= row
/ hScale
;
337 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
338 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
340 for (col
= 0; col
< dstWidth
; col
++) {
341 GLint col4
= (col
/ wScale
) * 4;
342 GLubyte r
= src
[col4
+ 0];
343 GLubyte g
= src
[col4
+ 1];
344 GLubyte b
= src
[col4
+ 2];
345 GLubyte a
= src
[col4
+ 3];
346 dst
[col
] = ((a
& 0xf0) << 8)
356 /* can't handle this format/srcType combination */
361 case MESA_A1_R5_G5_B5
:
362 /* store as 16-bit texels (GR_TEXFMT_ARGB_1555) */
363 if (srcFormat
== GL_RGBA
&& srcType
== GL_UNSIGNED_SHORT_1_5_5_5_REV
){
364 /* special, optimized case */
365 if (wScale
== 1 && hScale
== 1) {
366 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
367 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
368 const GLint srcStride
= _mesa_image_row_stride(packing
,
369 srcWidth
, srcFormat
, srcType
);
370 GLushort
*dst
= dstImage
;
372 for (row
= 0; row
< dstHeight
; row
++) {
373 MEMCPY(dst
, src
, dstWidth
* sizeof(GLushort
));
379 /* must rescale image */
380 GLushort
*dst
= dstImage
;
382 for (row
= 0; row
< dstHeight
; row
++) {
383 GLint srcRow
= row
/ hScale
;
384 const GLushort
*src
= _mesa_image_address(packing
, srcImage
,
385 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
387 for (col
= 0; col
< dstWidth
; col
++) {
388 dst
[col
] = src
[col
/ wScale
];
394 else if (srcFormat
== GL_RGBA
&& srcType
== GL_UNSIGNED_BYTE
) {
396 if (wScale
== 1 && hScale
== 1) {
397 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
398 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
399 const GLint srcStride
= _mesa_image_row_stride(packing
,
400 srcWidth
, srcFormat
, srcType
);
401 GLushort
*dst
= dstImage
;
403 for (row
= 0; row
< dstHeight
; row
++) {
405 for (col
= col4
= 0; col
< dstWidth
; col
++, col4
+= 4) {
406 GLubyte r
= src
[col4
+ 0];
407 GLubyte g
= src
[col4
+ 1];
408 GLubyte b
= src
[col4
+ 2];
409 GLubyte a
= src
[col4
+ 3];
410 dst
[col
] = ((a
& 0x80) << 8)
420 /* must rescale image */
421 GLushort
*dst
= dstImage
;
423 for (row
= 0; row
< dstHeight
; row
++) {
424 GLint srcRow
= row
/ hScale
;
425 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
426 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
428 for (col
= 0; col
< dstWidth
; col
++) {
429 GLint col4
= (col
/ wScale
) * 4;
430 GLubyte r
= src
[col4
+ 0];
431 GLubyte g
= src
[col4
+ 1];
432 GLubyte b
= src
[col4
+ 2];
433 GLubyte a
= src
[col4
+ 3];
434 dst
[col
] = ((a
& 0x80) << 8)
444 /* can't handle this source format/type combination */
449 case MESA_A8_R8_G8_B8
:
451 if (srcFormat
== GL_BGRA
&& srcType
== GL_UNSIGNED_INT_8_8_8_8_REV
){
452 /* special, optimized case */
453 if (wScale
== 1 && hScale
== 1) {
454 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
455 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
456 const GLint srcStride
= _mesa_image_row_stride(packing
,
457 srcWidth
, srcFormat
, srcType
);
458 GLuint
*dst
= dstImage
;
460 for (row
= 0; row
< dstHeight
; row
++) {
461 MEMCPY(dst
, src
, dstWidth
* sizeof(GLuint
));
467 /* must rescale image */
468 GLuint
*dst
= dstImage
;
470 for (row
= 0; row
< dstHeight
; row
++) {
471 GLint srcRow
= row
/ hScale
;
472 const GLuint
*src
= _mesa_image_address(packing
, srcImage
,
473 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
475 for (col
= 0; col
< dstWidth
; col
++) {
476 dst
[col
] = src
[col
/ wScale
];
482 else if (srcFormat
== GL_RGBA
&& srcType
== GL_UNSIGNED_BYTE
) {
484 if (wScale
== 1 && hScale
== 1) {
485 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
486 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, 0, 0);
487 const GLint srcStride
= _mesa_image_row_stride(packing
,
488 srcWidth
, srcFormat
, srcType
);
489 GLuint
*dst
= dstImage
;
491 for (row
= 0; row
< dstHeight
; row
++) {
493 for (col
= col4
= 0; col
< dstWidth
; col
++, col4
+= 4) {
494 GLubyte r
= src
[col4
+ 0];
495 GLubyte g
= src
[col4
+ 1];
496 GLubyte b
= src
[col4
+ 2];
497 GLubyte a
= src
[col4
+ 3];
498 dst
[col
] = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
505 /* must rescale image */
506 GLushort
*dst
= dstImage
;
508 for (row
= 0; row
< dstHeight
; row
++) {
509 GLint srcRow
= row
/ hScale
;
510 const GLubyte
*src
= _mesa_image_address(packing
, srcImage
,
511 srcWidth
, srcHeight
, srcFormat
, srcType
, 0, srcRow
, 0);
513 for (col
= 0; col
< dstWidth
; col
++) {
514 GLint col4
= (col
/ wScale
) * 4;
515 GLubyte r
= src
[col4
+ 0];
516 GLubyte g
= src
[col4
+ 1];
517 GLubyte b
= src
[col4
+ 2];
518 GLubyte a
= src
[col4
+ 3];
519 dst
[col
] = (a
<< 24) | (r
<< 16) | (g
<< 8) | b
;
526 /* can't handle this source format/type combination */
533 /* unexpected internal format! */