initial check-in
[mesa.git] / src / mesa / main / texutil.c
1 /* $Id: texutil.c,v 1.1 2000/03/24 20:54:21 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
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:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
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.
25 */
26
27
28 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "image.h"
33 #include "mem.h"
34 #include "texutil.h"
35 #include "types.h"
36 #endif
37
38
39 /*
40 * Texture utilities which may be useful to device drivers.
41 */
42
43
44
45
46 /*
47 * Convert texture image data into one a specific internal format.
48 * Input:
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
58 * combination.
59 *
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...
74 *
75 * Notes:
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.
78 *
79 *
80 */
81 GLboolean
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)
88 {
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);
93 ASSERT(dstImage);
94 ASSERT(srcImage);
95 ASSERT(packing);
96
97 switch (dstFormat) {
98 case MESA_I8:
99 case MESA_L8:
100 case MESA_A8:
101 case MESA_C8:
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 */
108 return GL_FALSE;
109 }
110 else {
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;
119 GLint row;
120 for (row = 0; row < dstHeight; row++) {
121 MEMCPY(dst, src, dstWidth * sizeof(GLubyte));
122 dst += dstWidth;
123 src += srcStride;
124 }
125 }
126 else {
127 /* must rescale image */
128 GLubyte *dst = (GLubyte *) dstImage;
129 GLint row;
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);
134 GLint col;
135 for (col = 0; col < dstWidth; col++) {
136 dst[col] = src[col / wScale];
137 }
138 dst += dstWidth;
139 }
140 }
141 }
142 break;
143
144 case MESA_L8_A8:
145 if (srcType != GL_UNSIGNED_BYTE || srcFormat != GL_LUMINANCE_ALPHA) {
146 return GL_FALSE;
147 }
148 else {
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;
156 GLint row, col;
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;
162 }
163 dst += dstWidth;
164 src += srcStride;
165 }
166 }
167 else {
168 /* must rescale */
169 GLushort *dst = dstImage;
170 GLint row, col;
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;
182 }
183 dst += dstWidth;
184 src += srcStride;
185 }
186 }
187 }
188 break;
189
190 case MESA_R5_G6_B5:
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;
199 GLint row;
200 for (row = 0; row < dstHeight; row++) {
201 MEMCPY(dst, src, dstWidth * sizeof(GLushort));
202 src += srcStride;
203 dst += dstWidth;
204 }
205 }
206 else {
207 /* must rescale image */
208 GLushort *dst = dstImage;
209 GLint row;
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);
214 GLint col;
215 for (col = 0; col < dstWidth; col++) {
216 dst[col] = src[col / wScale];
217 }
218 dst += dstWidth;
219 }
220 }
221 }
222 else if (srcFormat == GL_RGB && srcType == GL_UNSIGNED_BYTE) {
223 /* general case */
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;
230 GLint row;
231 for (row = 0; row < dstHeight; row++) {
232 GLint col, col3;
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)
238 | ((g & 0xfc) << 3)
239 | ((b & 0xf8) >> 3);
240 }
241 src += srcStride;
242 dst += dstWidth;
243 }
244 }
245 else {
246 /* must rescale image */
247 GLushort *dst = dstImage;
248 GLint row;
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);
253 GLint col;
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)
260 | ((g & 0xfc) << 3)
261 | ((b & 0xf8) >> 3);
262 }
263 dst += dstWidth;
264 }
265 }
266 }
267 else {
268 /* can't handle this srcFormat/srcType combination */
269 return GL_FALSE;
270 }
271 break;
272
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;
283 GLint row;
284 for (row = 0; row < dstHeight; row++) {
285 MEMCPY(dst, src, dstWidth * sizeof(GLushort));
286 src += srcStride;
287 dst += dstWidth;
288 }
289 }
290 else {
291 /* must rescale image */
292 GLushort *dst = dstImage;
293 GLint row;
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);
298 GLint col;
299 for (col = 0; col < dstWidth; col++) {
300 dst[col] = src[col / wScale];
301 }
302 dst += dstWidth;
303 }
304 }
305 }
306 else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) {
307 /* general case */
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;
314 GLint row;
315 for (row = 0; row < dstHeight; row++) {
316 GLint col, col4;
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)
323 | ((r & 0xf0) << 4)
324 | ((g & 0xf0) )
325 | ((b & 0xf0) >> 4);
326 }
327 src += srcStride;
328 dst += dstWidth;
329 }
330 }
331 else {
332 /* must rescale image */
333 GLushort *dst = dstImage;
334 GLint row;
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);
339 GLint col;
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)
347 | ((r & 0xf0) << 4)
348 | ((g & 0xf0) )
349 | ((b & 0xf0) >> 4);
350 }
351 dst += dstWidth;
352 }
353 }
354 }
355 else {
356 /* can't handle this format/srcType combination */
357 return GL_FALSE;
358 }
359 break;
360
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;
371 GLint row;
372 for (row = 0; row < dstHeight; row++) {
373 MEMCPY(dst, src, dstWidth * sizeof(GLushort));
374 src += srcStride;
375 dst += dstWidth;
376 }
377 }
378 else {
379 /* must rescale image */
380 GLushort *dst = dstImage;
381 GLint row;
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);
386 GLint col;
387 for (col = 0; col < dstWidth; col++) {
388 dst[col] = src[col / wScale];
389 }
390 dst += dstWidth;
391 }
392 }
393 }
394 else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) {
395 /* general case */
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;
402 GLint row;
403 for (row = 0; row < dstHeight; row++) {
404 GLint col, col4;
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)
411 | ((r & 0xf8) << 7)
412 | ((g & 0xf8) << 2)
413 | ((b & 0xf8) >> 3);
414 }
415 src += srcStride;
416 dst += dstWidth;
417 }
418 }
419 else {
420 /* must rescale image */
421 GLushort *dst = dstImage;
422 GLint row;
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);
427 GLint col;
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)
435 | ((r & 0xf8) << 7)
436 | ((g & 0xf8) << 2)
437 | ((b & 0xf8) >> 3);
438 }
439 dst += dstWidth;
440 }
441 }
442 }
443 else {
444 /* can't handle this source format/type combination */
445 return GL_FALSE;
446 }
447 break;
448
449 case MESA_A8_R8_G8_B8:
450 /* 32-bit texels */
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;
459 GLint row;
460 for (row = 0; row < dstHeight; row++) {
461 MEMCPY(dst, src, dstWidth * sizeof(GLuint));
462 src += srcStride;
463 dst += dstWidth;
464 }
465 }
466 else {
467 /* must rescale image */
468 GLuint *dst = dstImage;
469 GLint row;
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);
474 GLint col;
475 for (col = 0; col < dstWidth; col++) {
476 dst[col] = src[col / wScale];
477 }
478 dst += dstWidth;
479 }
480 }
481 }
482 else if (srcFormat == GL_RGBA && srcType == GL_UNSIGNED_BYTE) {
483 /* general case */
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;
490 GLint row;
491 for (row = 0; row < dstHeight; row++) {
492 GLint col, col4;
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;
499 }
500 src += srcStride;
501 dst += dstWidth;
502 }
503 }
504 else {
505 /* must rescale image */
506 GLushort *dst = dstImage;
507 GLint row;
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);
512 GLint col;
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;
520 }
521 dst += dstWidth;
522 }
523 }
524 }
525 else {
526 /* can't handle this source format/type combination */
527 return GL_FALSE;
528 }
529 break;
530
531
532 default:
533 /* unexpected internal format! */
534 return GL_FALSE;
535 }
536 return GL_TRUE;
537 }