1 /* $Id: mipmap.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-1999 Brian Paul
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Revision 1.1 1999/08/19 00:55:42 jtg
29 * Revision 1.13 1999/03/05 17:49:06 brianp
30 * added support for GL_EXT_abgr (devernay@istar.fr)
32 * Revision 1.12 1999/01/03 03:23:15 brianp
33 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
35 * Revision 1.11 1998/09/18 02:44:03 brianp
36 * further changes to gluScaleImage() per Randy Frank
38 * Revision 1.10 1998/09/17 03:20:26 brianp
39 * fixed another bug in gluScaleImage() per Sven Panne
41 * Revision 1.9 1998/07/31 03:06:20 brianp
42 * tweaked the gluScaleImage() function per Randy Frank
44 * Revision 1.8 1998/07/08 01:02:53 brianp
45 * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
47 * Revision 1.7 1998/07/01 00:18:02 brianp
48 * if gluBuildxDMipmaps() width or height <= 0 just return 0
50 * Revision 1.6 1998/06/01 01:06:41 brianp
51 * small update for Next/OpenStep from Alexander Mai
53 * Revision 1.5 1997/07/24 01:28:44 brianp
54 * changed precompiled header symbol from PCH to PC_HEADER
56 * Revision 1.4 1997/06/23 00:22:56 brianp
57 * added dummy() call to work around an MSVC 4.1 bug
59 * Revision 1.3 1997/05/28 02:29:38 brianp
60 * added support for precompiled headers (PCH), inserted APIENTRY keyword
62 * Revision 1.2 1997/05/24 13:32:25 brianp
63 * undef EPSILON in case it's already defined
65 * Revision 1.1 1996/09/27 01:19:39 brianp
83 * Compute ceiling of integer quotient of A divided by B:
85 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
95 /* To work around optimizer bug in MSVC4.1 */
96 #if defined(__WIN32__) && !defined(OPENSTEP)
97 void dummy(GLuint j
, GLuint k
){
104 GLint GLAPIENTRY
gluScaleImage( GLenum format
,
105 GLint widthin
, GLint heightin
,
106 GLenum typein
, const void *datain
,
107 GLint widthout
, GLint heightout
,
108 GLenum typeout
, void *dataout
)
110 GLint components
, i
, j
, k
;
111 GLfloat
*tempin
, *tempout
;
113 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
114 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
115 GLint sizein
, sizeout
;
116 GLint rowstride
, rowlen
;
119 /* Determine number of components per pixel */
122 case GL_STENCIL_INDEX
:
123 case GL_DEPTH_COMPONENT
:
131 case GL_LUMINANCE_ALPHA
:
144 return GLU_INVALID_ENUM
;
147 /* Determine bytes per input datum */
149 case GL_UNSIGNED_BYTE
: sizein
= sizeof(GLubyte
); break;
150 case GL_BYTE
: sizein
= sizeof(GLbyte
); break;
151 case GL_UNSIGNED_SHORT
: sizein
= sizeof(GLushort
); break;
152 case GL_SHORT
: sizein
= sizeof(GLshort
); break;
153 case GL_UNSIGNED_INT
: sizein
= sizeof(GLuint
); break;
154 case GL_INT
: sizein
= sizeof(GLint
); break;
155 case GL_FLOAT
: sizein
= sizeof(GLfloat
); break;
157 /* not implemented yet */
159 return GL_INVALID_ENUM
;
162 /* Determine bytes per output datum */
164 case GL_UNSIGNED_BYTE
: sizeout
= sizeof(GLubyte
); break;
165 case GL_BYTE
: sizeout
= sizeof(GLbyte
); break;
166 case GL_UNSIGNED_SHORT
: sizeout
= sizeof(GLushort
); break;
167 case GL_SHORT
: sizeout
= sizeof(GLshort
); break;
168 case GL_UNSIGNED_INT
: sizeout
= sizeof(GLuint
); break;
169 case GL_INT
: sizeout
= sizeof(GLint
); break;
170 case GL_FLOAT
: sizeout
= sizeof(GLfloat
); break;
172 /* not implemented yet */
174 return GL_INVALID_ENUM
;
177 /* Get glPixelStore state */
178 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
179 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
180 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
181 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
182 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
183 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
184 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
185 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
187 /* Allocate storage for intermediate images */
188 tempin
= (GLfloat
*) malloc( widthin
* heightin
189 * components
* sizeof(GLfloat
) );
191 return GLU_OUT_OF_MEMORY
;
193 tempout
= (GLfloat
*) malloc( widthout
* heightout
194 * components
* sizeof(GLfloat
) );
197 return GLU_OUT_OF_MEMORY
;
202 * Unpack the pixel data and convert to floating point
205 if (unpackrowlength
>0) {
206 rowlen
= unpackrowlength
;
211 if (sizein
>= unpackalignment
) {
212 rowstride
= components
* rowlen
;
215 rowstride
= unpackalignment
/sizein
216 * CEILING( components
* rowlen
* sizein
, unpackalignment
);
220 case GL_UNSIGNED_BYTE
:
222 for (i
=0;i
<heightin
;i
++) {
223 GLubyte
*ubptr
= (GLubyte
*) datain
225 + unpackskiprows
* rowstride
226 + unpackskippixels
* components
;
227 for (j
=0;j
<widthin
*components
;j
++) {
229 tempin
[k
++] = (GLfloat
) *ubptr
++;
235 for (i
=0;i
<heightin
;i
++) {
236 GLbyte
*bptr
= (GLbyte
*) datain
238 + unpackskiprows
* rowstride
239 + unpackskippixels
* components
;
240 for (j
=0;j
<widthin
*components
;j
++) {
242 tempin
[k
++] = (GLfloat
) *bptr
++;
246 case GL_UNSIGNED_SHORT
:
248 for (i
=0;i
<heightin
;i
++) {
249 GLushort
*usptr
= (GLushort
*) datain
251 + unpackskiprows
* rowstride
252 + unpackskippixels
* components
;
253 for (j
=0;j
<widthin
*components
;j
++) {
255 tempin
[k
++] = (GLfloat
) *usptr
++;
261 for (i
=0;i
<heightin
;i
++) {
262 GLshort
*sptr
= (GLshort
*) datain
264 + unpackskiprows
* rowstride
265 + unpackskippixels
* components
;
266 for (j
=0;j
<widthin
*components
;j
++) {
268 tempin
[k
++] = (GLfloat
) *sptr
++;
272 case GL_UNSIGNED_INT
:
274 for (i
=0;i
<heightin
;i
++) {
275 GLuint
*uiptr
= (GLuint
*) datain
277 + unpackskiprows
* rowstride
278 + unpackskippixels
* components
;
279 for (j
=0;j
<widthin
*components
;j
++) {
281 tempin
[k
++] = (GLfloat
) *uiptr
++;
287 for (i
=0;i
<heightin
;i
++) {
288 GLint
*iptr
= (GLint
*) datain
290 + unpackskiprows
* rowstride
291 + unpackskippixels
* components
;
292 for (j
=0;j
<widthin
*components
;j
++) {
294 tempin
[k
++] = (GLfloat
) *iptr
++;
300 for (i
=0;i
<heightin
;i
++) {
301 GLfloat
*fptr
= (GLfloat
*) datain
303 + unpackskiprows
* rowstride
304 + unpackskippixels
* components
;
305 for (j
=0;j
<widthin
*components
;j
++) {
307 tempin
[k
++] = *fptr
++;
312 return GLU_INVALID_ENUM
;
321 sx
= (GLfloat
) (widthin
-1) / (GLfloat
) (widthout
-1);
323 sx
= (GLfloat
) (widthin
-1);
325 sy
= (GLfloat
) (heightin
-1) / (GLfloat
) (heightout
-1);
327 sy
= (GLfloat
) (heightin
-1);
329 /*#define POINT_SAMPLE*/
331 for (i
=0;i
<heightout
;i
++) {
333 for (j
=0;j
<widthout
;j
++) {
336 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
337 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
339 for (k
=0;k
<components
;k
++) {
345 if (sx
<1.0 && sy
<1.0) {
346 /* magnify both width and height: use weighted sample of 4 pixels */
347 GLint i0
, i1
, j0
, j1
;
349 GLfloat
*src00
, *src01
, *src10
, *src11
;
353 for (i
=0;i
<heightout
;i
++) {
356 if (i1
>= heightin
) i1
= heightin
-1;
357 /* i1 = (i+1) * sy - EPSILON;*/
359 for (j
=0;j
<widthout
;j
++) {
362 if (j1
>= widthin
) j1
= widthin
-1;
363 /* j1 = (j+1) * sx - EPSILON; */
366 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
367 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
368 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
369 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
370 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
372 dst
= tempout
+ (i
* widthout
+ j
) * components
;
374 for (k
=0;k
<components
;k
++) {
375 s1
= *src00
++ * (1.0-beta
) + *src01
++ * beta
;
376 s2
= *src10
++ * (1.0-beta
) + *src11
++ * beta
;
377 *dst
++ = s1
* (1.0-alpha
) + s2
* alpha
;
383 /* shrink width and/or height: use an unweighted box filter */
389 for (i
=0;i
<heightout
;i
++) {
392 if (i1
>= heightin
) i1
= heightin
-1;
393 /* i1 = (i+1) * sy - EPSILON; */
394 for (j
=0;j
<widthout
;j
++) {
397 if (j1
>= widthin
) j1
= widthin
-1;
398 /* j1 = (j+1) * sx - EPSILON; */
400 dst
= tempout
+ (i
* widthout
+ j
) * components
;
402 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
403 for (k
=0;k
<components
;k
++) {
405 for (ii
=i0
;ii
<=i1
;ii
++) {
406 for (jj
=j0
;jj
<=j1
;jj
++) {
407 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
410 sum
/= (j1
-j0
+1) * (i1
-i0
+1);
420 * Return output image
423 if (packrowlength
>0) {
424 rowlen
= packrowlength
;
429 if (sizeout
>= packalignment
) {
430 rowstride
= components
* rowlen
;
433 rowstride
= packalignment
/sizeout
434 * CEILING( components
* rowlen
* sizeout
, packalignment
);
438 case GL_UNSIGNED_BYTE
:
440 for (i
=0;i
<heightout
;i
++) {
441 GLubyte
*ubptr
= (GLubyte
*) dataout
443 + packskiprows
* rowstride
444 + packskippixels
* components
;
445 for (j
=0;j
<widthout
*components
;j
++) {
447 *ubptr
++ = (GLubyte
) tempout
[k
++];
453 for (i
=0;i
<heightout
;i
++) {
454 GLbyte
*bptr
= (GLbyte
*) dataout
456 + packskiprows
* rowstride
457 + packskippixels
* components
;
458 for (j
=0;j
<widthout
*components
;j
++) {
460 *bptr
++ = (GLbyte
) tempout
[k
++];
464 case GL_UNSIGNED_SHORT
:
466 for (i
=0;i
<heightout
;i
++) {
467 GLushort
*usptr
= (GLushort
*) dataout
469 + packskiprows
* rowstride
470 + packskippixels
* components
;
471 for (j
=0;j
<widthout
*components
;j
++) {
473 *usptr
++ = (GLushort
) tempout
[k
++];
479 for (i
=0;i
<heightout
;i
++) {
480 GLshort
*sptr
= (GLshort
*) dataout
482 + packskiprows
* rowstride
483 + packskippixels
* components
;
484 for (j
=0;j
<widthout
*components
;j
++) {
486 *sptr
++ = (GLshort
) tempout
[k
++];
490 case GL_UNSIGNED_INT
:
492 for (i
=0;i
<heightout
;i
++) {
493 GLuint
*uiptr
= (GLuint
*) dataout
495 + packskiprows
* rowstride
496 + packskippixels
* components
;
497 for (j
=0;j
<widthout
*components
;j
++) {
499 *uiptr
++ = (GLuint
) tempout
[k
++];
505 for (i
=0;i
<heightout
;i
++) {
506 GLint
*iptr
= (GLint
*) dataout
508 + packskiprows
* rowstride
509 + packskippixels
* components
;
510 for (j
=0;j
<widthout
*components
;j
++) {
512 *iptr
++ = (GLint
) tempout
[k
++];
518 for (i
=0;i
<heightout
;i
++) {
519 GLfloat
*fptr
= (GLfloat
*) dataout
521 + packskiprows
* rowstride
522 + packskippixels
* components
;
523 for (j
=0;j
<widthout
*components
;j
++) {
525 *fptr
++ = tempout
[k
++];
530 return GLU_INVALID_ENUM
;
534 /* free temporary image storage */
544 * Return the largest k such that 2^k <= n.
546 static GLint
ilog2( GLint n
)
551 for (k
=0; n
>>=1; k
++) ;
558 * Find the value nearest to n which is also a power of two.
560 static GLint
round2( GLint n
)
578 * Given an pixel format and datatype, return the number of bytes to
581 static GLint
bytes_per_pixel( GLenum format
, GLenum type
)
587 case GL_STENCIL_INDEX
:
588 case GL_DEPTH_COMPONENT
:
596 case GL_LUMINANCE_ALPHA
:
613 case GL_UNSIGNED_BYTE
: m
= sizeof(GLubyte
); break;
614 case GL_BYTE
: m
= sizeof(GLbyte
); break;
615 case GL_BITMAP
: m
= 1; break;
616 case GL_UNSIGNED_SHORT
: m
= sizeof(GLushort
); break;
617 case GL_SHORT
: m
= sizeof(GLshort
); break;
618 case GL_UNSIGNED_INT
: m
= sizeof(GLuint
); break;
619 case GL_INT
: m
= sizeof(GLint
); break;
620 case GL_FLOAT
: m
= sizeof(GLfloat
); break;
630 * WARNING: This function isn't finished and has never been tested!!!!
632 GLint GLAPIENTRY
gluBuild1DMipmaps( GLenum target
, GLint components
,
633 GLint width
, GLenum format
,
634 GLenum type
, const void *data
)
637 GLint levels
, max_levels
;
638 GLint new_width
, max_width
;
642 return GLU_INVALID_VALUE
;
644 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &max_width
);
645 max_levels
= ilog2( max_width
) + 1;
647 /* Compute how many mipmap images to make */
648 levels
= ilog2( width
) + 1;
649 if (levels
>max_levels
) {
653 new_width
= 1 << (levels
-1);
655 texture
= (GLubyte
*) malloc( new_width
* components
);
657 return GLU_OUT_OF_MEMORY
;
660 if (width
!= new_width
) {
661 /* initial rescaling */
663 case GL_UNSIGNED_BYTE
:
665 GLubyte
*ub_data
= (GLubyte
*) data
;
666 for (i
=0;i
<new_width
;i
++) {
667 j
= i
* width
/ new_width
;
668 for (k
=0;k
<components
;k
++) {
669 texture
[i
*components
+k
] = ub_data
[j
*components
+k
];
675 /* Not implemented */
680 /* generate and load mipmap images */
681 for (l
=0;l
<levels
;l
++) {
682 glTexImage1D( GL_TEXTURE_1D
, l
, components
, new_width
, 0,
683 format
, GL_UNSIGNED_BYTE
, texture
);
685 /* Scale image down to 1/2 size */
686 new_width
= new_width
/ 2;
687 for (i
=0;i
<new_width
;i
++) {
688 for (k
=0;k
<components
;k
++) {
689 GLint sample1
, sample2
;
690 sample1
= (GLint
) texture
[i
*2*components
+k
];
691 sample2
= (GLint
) texture
[(i
*2+1)*components
+k
];
692 texture
[i
*components
+k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
699 /* make sure remaining mipmap levels are removed */
700 for (l
=levels
;l
<max_levels
;l
++) {
701 glTexImage1D( GL_TEXTURE_1D
, l
, components
, 0, 0,
702 format
, GL_UNSIGNED_BYTE
, NULL
);
710 GLint GLAPIENTRY
gluBuild2DMipmaps( GLenum target
, GLint components
,
711 GLint width
, GLint height
, GLenum format
,
712 GLenum type
, const void *data
)
715 void *image
, *newimage
;
716 GLint neww
, newh
, level
, bpp
;
719 if (width
< 1 || height
< 1)
720 return GLU_INVALID_VALUE
;
722 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &maxsize
);
728 h
= round2( height
);
733 bpp
= bytes_per_pixel( format
, type
);
735 /* probably a bad format or type enum */
736 return GLU_INVALID_ENUM
;
739 if (w
!=width
|| h
!=height
) {
740 /* must rescale image to get "top" mipmap texture image */
741 image
= malloc( (w
+4) * h
* bpp
);
743 return GLU_OUT_OF_MEMORY
;
745 error
= gluScaleImage( format
, width
, height
, type
, data
,
752 image
= (void *) data
;
757 glTexImage2D( target
, level
, components
, w
, h
, 0, format
, type
, image
);
759 if (w
==1 && h
==1) break;
761 neww
= (w
<2) ? 1 : w
/2;
762 newh
= (h
<2) ? 1 : h
/2;
763 newimage
= malloc( (neww
+4) * newh
* bpp
);
765 return GLU_OUT_OF_MEMORY
;
768 error
= gluScaleImage( format
, w
, h
, type
, image
,
769 neww
, newh
, type
, newimage
);