500b0b1d0314d52d75b8a8b7cb37e79f343d34bc
1 /* $Id: mipmap.c,v 1.4 1999/12/12 17:24:18 brianp 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.4 1999/12/12 17:24:18 brianp
27 * removed unneeded code in gluBuild1DMipmaps()
29 * Revision 1.3 1999/11/09 06:16:59 brianp
30 * replace GLint with GLsizei in a gluScaleImage, gluBuild1/2DMipmaps()
32 * Revision 1.2 1999/09/14 00:30:28 brianp
33 * fixed pixel packing/unpacking code in gluBuild2DMipmaps()
35 * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
38 * Revision 1.13 1999/03/05 17:49:06 brianp
39 * added support for GL_EXT_abgr (devernay@istar.fr)
41 * Revision 1.12 1999/01/03 03:23:15 brianp
42 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
44 * Revision 1.11 1998/09/18 02:44:03 brianp
45 * further changes to gluScaleImage() per Randy Frank
47 * Revision 1.10 1998/09/17 03:20:26 brianp
48 * fixed another bug in gluScaleImage() per Sven Panne
50 * Revision 1.9 1998/07/31 03:06:20 brianp
51 * tweaked the gluScaleImage() function per Randy Frank
53 * Revision 1.8 1998/07/08 01:02:53 brianp
54 * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
56 * Revision 1.7 1998/07/01 00:18:02 brianp
57 * if gluBuildxDMipmaps() width or height <= 0 just return 0
59 * Revision 1.6 1998/06/01 01:06:41 brianp
60 * small update for Next/OpenStep from Alexander Mai
62 * Revision 1.5 1997/07/24 01:28:44 brianp
63 * changed precompiled header symbol from PCH to PC_HEADER
65 * Revision 1.4 1997/06/23 00:22:56 brianp
66 * added dummy() call to work around an MSVC 4.1 bug
68 * Revision 1.3 1997/05/28 02:29:38 brianp
69 * added support for precompiled headers (PCH), inserted APIENTRY keyword
71 * Revision 1.2 1997/05/24 13:32:25 brianp
72 * undef EPSILON in case it's already defined
74 * Revision 1.1 1996/09/27 01:19:39 brianp
92 * Compute ceiling of integer quotient of A divided by B:
94 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
101 #define EPSILON 0.001
104 /* To work around optimizer bug in MSVC4.1 */
105 #if defined(__WIN32__) && !defined(OPENSTEP)
106 void dummy(GLuint j
, GLuint k
){
113 GLint GLAPIENTRY
gluScaleImage( GLenum format
,
114 GLsizei widthin
, GLsizei heightin
,
115 GLenum typein
, const void *datain
,
116 GLsizei widthout
, GLsizei heightout
,
117 GLenum typeout
, void *dataout
)
119 GLint components
, i
, j
, k
;
120 GLfloat
*tempin
, *tempout
;
122 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
123 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
124 GLint sizein
, sizeout
;
125 GLint rowstride
, rowlen
;
128 /* Determine number of components per pixel */
131 case GL_STENCIL_INDEX
:
132 case GL_DEPTH_COMPONENT
:
140 case GL_LUMINANCE_ALPHA
:
153 return GLU_INVALID_ENUM
;
156 /* Determine bytes per input datum */
158 case GL_UNSIGNED_BYTE
: sizein
= sizeof(GLubyte
); break;
159 case GL_BYTE
: sizein
= sizeof(GLbyte
); break;
160 case GL_UNSIGNED_SHORT
: sizein
= sizeof(GLushort
); break;
161 case GL_SHORT
: sizein
= sizeof(GLshort
); break;
162 case GL_UNSIGNED_INT
: sizein
= sizeof(GLuint
); break;
163 case GL_INT
: sizein
= sizeof(GLint
); break;
164 case GL_FLOAT
: sizein
= sizeof(GLfloat
); break;
166 /* not implemented yet */
168 return GL_INVALID_ENUM
;
171 /* Determine bytes per output datum */
173 case GL_UNSIGNED_BYTE
: sizeout
= sizeof(GLubyte
); break;
174 case GL_BYTE
: sizeout
= sizeof(GLbyte
); break;
175 case GL_UNSIGNED_SHORT
: sizeout
= sizeof(GLushort
); break;
176 case GL_SHORT
: sizeout
= sizeof(GLshort
); break;
177 case GL_UNSIGNED_INT
: sizeout
= sizeof(GLuint
); break;
178 case GL_INT
: sizeout
= sizeof(GLint
); break;
179 case GL_FLOAT
: sizeout
= sizeof(GLfloat
); break;
181 /* not implemented yet */
183 return GL_INVALID_ENUM
;
186 /* Get glPixelStore state */
187 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
188 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
189 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
190 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
191 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
192 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
193 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
194 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
196 /* Allocate storage for intermediate images */
197 tempin
= (GLfloat
*) malloc( widthin
* heightin
198 * components
* sizeof(GLfloat
) );
200 return GLU_OUT_OF_MEMORY
;
202 tempout
= (GLfloat
*) malloc( widthout
* heightout
203 * components
* sizeof(GLfloat
) );
206 return GLU_OUT_OF_MEMORY
;
211 * Unpack the pixel data and convert to floating point
214 if (unpackrowlength
>0) {
215 rowlen
= unpackrowlength
;
220 if (sizein
>= unpackalignment
) {
221 rowstride
= components
* rowlen
;
224 rowstride
= unpackalignment
/sizein
225 * CEILING( components
* rowlen
* sizein
, unpackalignment
);
229 case GL_UNSIGNED_BYTE
:
231 for (i
=0;i
<heightin
;i
++) {
232 GLubyte
*ubptr
= (GLubyte
*) datain
234 + unpackskiprows
* rowstride
235 + unpackskippixels
* components
;
236 for (j
=0;j
<widthin
*components
;j
++) {
238 tempin
[k
++] = (GLfloat
) *ubptr
++;
244 for (i
=0;i
<heightin
;i
++) {
245 GLbyte
*bptr
= (GLbyte
*) datain
247 + unpackskiprows
* rowstride
248 + unpackskippixels
* components
;
249 for (j
=0;j
<widthin
*components
;j
++) {
251 tempin
[k
++] = (GLfloat
) *bptr
++;
255 case GL_UNSIGNED_SHORT
:
257 for (i
=0;i
<heightin
;i
++) {
258 GLushort
*usptr
= (GLushort
*) datain
260 + unpackskiprows
* rowstride
261 + unpackskippixels
* components
;
262 for (j
=0;j
<widthin
*components
;j
++) {
264 tempin
[k
++] = (GLfloat
) *usptr
++;
270 for (i
=0;i
<heightin
;i
++) {
271 GLshort
*sptr
= (GLshort
*) datain
273 + unpackskiprows
* rowstride
274 + unpackskippixels
* components
;
275 for (j
=0;j
<widthin
*components
;j
++) {
277 tempin
[k
++] = (GLfloat
) *sptr
++;
281 case GL_UNSIGNED_INT
:
283 for (i
=0;i
<heightin
;i
++) {
284 GLuint
*uiptr
= (GLuint
*) datain
286 + unpackskiprows
* rowstride
287 + unpackskippixels
* components
;
288 for (j
=0;j
<widthin
*components
;j
++) {
290 tempin
[k
++] = (GLfloat
) *uiptr
++;
296 for (i
=0;i
<heightin
;i
++) {
297 GLint
*iptr
= (GLint
*) datain
299 + unpackskiprows
* rowstride
300 + unpackskippixels
* components
;
301 for (j
=0;j
<widthin
*components
;j
++) {
303 tempin
[k
++] = (GLfloat
) *iptr
++;
309 for (i
=0;i
<heightin
;i
++) {
310 GLfloat
*fptr
= (GLfloat
*) datain
312 + unpackskiprows
* rowstride
313 + unpackskippixels
* components
;
314 for (j
=0;j
<widthin
*components
;j
++) {
316 tempin
[k
++] = *fptr
++;
321 return GLU_INVALID_ENUM
;
330 sx
= (GLfloat
) (widthin
-1) / (GLfloat
) (widthout
-1);
332 sx
= (GLfloat
) (widthin
-1);
334 sy
= (GLfloat
) (heightin
-1) / (GLfloat
) (heightout
-1);
336 sy
= (GLfloat
) (heightin
-1);
338 /*#define POINT_SAMPLE*/
340 for (i
=0;i
<heightout
;i
++) {
342 for (j
=0;j
<widthout
;j
++) {
345 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
346 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
348 for (k
=0;k
<components
;k
++) {
354 if (sx
<1.0 && sy
<1.0) {
355 /* magnify both width and height: use weighted sample of 4 pixels */
356 GLint i0
, i1
, j0
, j1
;
358 GLfloat
*src00
, *src01
, *src10
, *src11
;
362 for (i
=0;i
<heightout
;i
++) {
365 if (i1
>= heightin
) i1
= heightin
-1;
366 /* i1 = (i+1) * sy - EPSILON;*/
368 for (j
=0;j
<widthout
;j
++) {
371 if (j1
>= widthin
) j1
= widthin
-1;
372 /* j1 = (j+1) * sx - EPSILON; */
375 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
376 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
377 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
378 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
379 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
381 dst
= tempout
+ (i
* widthout
+ j
) * components
;
383 for (k
=0;k
<components
;k
++) {
384 s1
= *src00
++ * (1.0-beta
) + *src01
++ * beta
;
385 s2
= *src10
++ * (1.0-beta
) + *src11
++ * beta
;
386 *dst
++ = s1
* (1.0-alpha
) + s2
* alpha
;
392 /* shrink width and/or height: use an unweighted box filter */
398 for (i
=0;i
<heightout
;i
++) {
401 if (i1
>= heightin
) i1
= heightin
-1;
402 /* i1 = (i+1) * sy - EPSILON; */
403 for (j
=0;j
<widthout
;j
++) {
406 if (j1
>= widthin
) j1
= widthin
-1;
407 /* j1 = (j+1) * sx - EPSILON; */
409 dst
= tempout
+ (i
* widthout
+ j
) * components
;
411 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
412 for (k
=0;k
<components
;k
++) {
414 for (ii
=i0
;ii
<=i1
;ii
++) {
415 for (jj
=j0
;jj
<=j1
;jj
++) {
416 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
419 sum
/= (j1
-j0
+1) * (i1
-i0
+1);
429 * Return output image
432 if (packrowlength
>0) {
433 rowlen
= packrowlength
;
438 if (sizeout
>= packalignment
) {
439 rowstride
= components
* rowlen
;
442 rowstride
= packalignment
/sizeout
443 * CEILING( components
* rowlen
* sizeout
, packalignment
);
447 case GL_UNSIGNED_BYTE
:
449 for (i
=0;i
<heightout
;i
++) {
450 GLubyte
*ubptr
= (GLubyte
*) dataout
452 + packskiprows
* rowstride
453 + packskippixels
* components
;
454 for (j
=0;j
<widthout
*components
;j
++) {
456 *ubptr
++ = (GLubyte
) tempout
[k
++];
462 for (i
=0;i
<heightout
;i
++) {
463 GLbyte
*bptr
= (GLbyte
*) dataout
465 + packskiprows
* rowstride
466 + packskippixels
* components
;
467 for (j
=0;j
<widthout
*components
;j
++) {
469 *bptr
++ = (GLbyte
) tempout
[k
++];
473 case GL_UNSIGNED_SHORT
:
475 for (i
=0;i
<heightout
;i
++) {
476 GLushort
*usptr
= (GLushort
*) dataout
478 + packskiprows
* rowstride
479 + packskippixels
* components
;
480 for (j
=0;j
<widthout
*components
;j
++) {
482 *usptr
++ = (GLushort
) tempout
[k
++];
488 for (i
=0;i
<heightout
;i
++) {
489 GLshort
*sptr
= (GLshort
*) dataout
491 + packskiprows
* rowstride
492 + packskippixels
* components
;
493 for (j
=0;j
<widthout
*components
;j
++) {
495 *sptr
++ = (GLshort
) tempout
[k
++];
499 case GL_UNSIGNED_INT
:
501 for (i
=0;i
<heightout
;i
++) {
502 GLuint
*uiptr
= (GLuint
*) dataout
504 + packskiprows
* rowstride
505 + packskippixels
* components
;
506 for (j
=0;j
<widthout
*components
;j
++) {
508 *uiptr
++ = (GLuint
) tempout
[k
++];
514 for (i
=0;i
<heightout
;i
++) {
515 GLint
*iptr
= (GLint
*) dataout
517 + packskiprows
* rowstride
518 + packskippixels
* components
;
519 for (j
=0;j
<widthout
*components
;j
++) {
521 *iptr
++ = (GLint
) tempout
[k
++];
527 for (i
=0;i
<heightout
;i
++) {
528 GLfloat
*fptr
= (GLfloat
*) dataout
530 + packskiprows
* rowstride
531 + packskippixels
* components
;
532 for (j
=0;j
<widthout
*components
;j
++) {
534 *fptr
++ = tempout
[k
++];
539 return GLU_INVALID_ENUM
;
543 /* free temporary image storage */
553 * Return the largest k such that 2^k <= n.
555 static GLint
ilog2( GLint n
)
560 for (k
=0; n
>>=1; k
++) ;
567 * Find the value nearest to n which is also a power of two.
569 static GLint
round2( GLint n
)
587 * Given an pixel format and datatype, return the number of bytes to
590 static GLint
bytes_per_pixel( GLenum format
, GLenum type
)
596 case GL_STENCIL_INDEX
:
597 case GL_DEPTH_COMPONENT
:
605 case GL_LUMINANCE_ALPHA
:
622 case GL_UNSIGNED_BYTE
: m
= sizeof(GLubyte
); break;
623 case GL_BYTE
: m
= sizeof(GLbyte
); break;
624 case GL_BITMAP
: m
= 1; break;
625 case GL_UNSIGNED_SHORT
: m
= sizeof(GLushort
); break;
626 case GL_SHORT
: m
= sizeof(GLshort
); break;
627 case GL_UNSIGNED_INT
: m
= sizeof(GLuint
); break;
628 case GL_INT
: m
= sizeof(GLint
); break;
629 case GL_FLOAT
: m
= sizeof(GLfloat
); break;
639 * WARNING: This function isn't finished and has never been tested!!!!
641 GLint GLAPIENTRY
gluBuild1DMipmaps( GLenum target
, GLint components
,
642 GLsizei width
, GLenum format
,
643 GLenum type
, const void *data
)
646 GLint levels
, max_levels
;
647 GLint new_width
, max_width
;
651 return GLU_INVALID_VALUE
;
653 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &max_width
);
654 max_levels
= ilog2( max_width
) + 1;
656 /* Compute how many mipmap images to make */
657 levels
= ilog2( width
) + 1;
658 if (levels
>max_levels
) {
662 new_width
= 1 << (levels
-1);
664 texture
= (GLubyte
*) malloc( new_width
* components
);
666 return GLU_OUT_OF_MEMORY
;
669 if (width
!= new_width
) {
670 /* initial rescaling */
672 case GL_UNSIGNED_BYTE
:
674 GLubyte
*ub_data
= (GLubyte
*) data
;
675 for (i
=0;i
<new_width
;i
++) {
676 j
= i
* width
/ new_width
;
677 for (k
=0;k
<components
;k
++) {
678 texture
[i
*components
+k
] = ub_data
[j
*components
+k
];
684 /* Not implemented */
689 /* generate and load mipmap images */
690 for (l
=0;l
<levels
;l
++) {
691 glTexImage1D( GL_TEXTURE_1D
, l
, components
, new_width
, 0,
692 format
, GL_UNSIGNED_BYTE
, texture
);
694 /* Scale image down to 1/2 size */
695 new_width
= new_width
/ 2;
696 for (i
=0;i
<new_width
;i
++) {
697 for (k
=0;k
<components
;k
++) {
698 GLint sample1
, sample2
;
699 sample1
= (GLint
) texture
[i
*2*components
+k
];
700 sample2
= (GLint
) texture
[(i
*2+1)*components
+k
];
701 texture
[i
*components
+k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
713 GLint GLAPIENTRY
gluBuild2DMipmaps( GLenum target
, GLint components
,
714 GLsizei width
, GLsizei height
, GLenum format
,
715 GLenum type
, const void *data
)
718 void *image
, *newimage
;
719 GLint neww
, newh
, level
, bpp
;
723 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
724 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
726 if (width
< 1 || height
< 1)
727 return GLU_INVALID_VALUE
;
729 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &maxsize
);
735 h
= round2( height
);
740 bpp
= bytes_per_pixel( format
, type
);
742 /* probably a bad format or type enum */
743 return GLU_INVALID_ENUM
;
746 /* Get current glPixelStore values */
747 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
748 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
749 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
750 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
751 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
752 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
753 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
754 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
756 /* set pixel packing */
757 glPixelStorei( GL_PACK_ROW_LENGTH
, 0 );
758 glPixelStorei( GL_PACK_ALIGNMENT
, 1 );
759 glPixelStorei( GL_PACK_SKIP_ROWS
, 0 );
760 glPixelStorei( GL_PACK_SKIP_PIXELS
, 0 );
764 if (w
!=width
|| h
!=height
) {
765 /* must rescale image to get "top" mipmap texture image */
766 image
= malloc( (w
+4) * h
* bpp
);
768 return GLU_OUT_OF_MEMORY
;
770 error
= gluScaleImage( format
, width
, height
, type
, data
,
778 image
= (void *) data
;
784 /* set pixel unpacking */
785 glPixelStorei( GL_UNPACK_ROW_LENGTH
, 0 );
786 glPixelStorei( GL_UNPACK_ALIGNMENT
, 1 );
787 glPixelStorei( GL_UNPACK_SKIP_ROWS
, 0 );
788 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, 0 );
791 glTexImage2D( target
, level
, components
, w
, h
, 0, format
, type
, image
);
793 if (w
==1 && h
==1) break;
795 neww
= (w
<2) ? 1 : w
/2;
796 newh
= (h
<2) ? 1 : h
/2;
797 newimage
= malloc( (neww
+4) * newh
* bpp
);
799 return GLU_OUT_OF_MEMORY
;
802 error
= gluScaleImage( format
, w
, h
, type
, image
,
803 neww
, newh
, type
, newimage
);
823 /* Restore original glPixelStore state */
824 glPixelStorei( GL_UNPACK_ROW_LENGTH
, unpackrowlength
);
825 glPixelStorei( GL_UNPACK_ALIGNMENT
, unpackalignment
);
826 glPixelStorei( GL_UNPACK_SKIP_ROWS
, unpackskiprows
);
827 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, unpackskippixels
);
828 glPixelStorei( GL_PACK_ROW_LENGTH
, packrowlength
);
829 glPixelStorei( GL_PACK_ALIGNMENT
, packalignment
);
830 glPixelStorei( GL_PACK_SKIP_ROWS
, packskiprows
);
831 glPixelStorei( GL_PACK_SKIP_PIXELS
, packskippixels
);