9f4ffcfea8989eaddcdaa95633e7fed5812596d1
1 /* $Id: mipmap.c,v 1.3 1999/11/09 06:16:59 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.3 1999/11/09 06:16:59 brianp
27 * replace GLint with GLsizei in a gluScaleImage, gluBuild1/2DMipmaps()
29 * Revision 1.2 1999/09/14 00:30:28 brianp
30 * fixed pixel packing/unpacking code in gluBuild2DMipmaps()
32 * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
35 * Revision 1.13 1999/03/05 17:49:06 brianp
36 * added support for GL_EXT_abgr (devernay@istar.fr)
38 * Revision 1.12 1999/01/03 03:23:15 brianp
39 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
41 * Revision 1.11 1998/09/18 02:44:03 brianp
42 * further changes to gluScaleImage() per Randy Frank
44 * Revision 1.10 1998/09/17 03:20:26 brianp
45 * fixed another bug in gluScaleImage() per Sven Panne
47 * Revision 1.9 1998/07/31 03:06:20 brianp
48 * tweaked the gluScaleImage() function per Randy Frank
50 * Revision 1.8 1998/07/08 01:02:53 brianp
51 * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
53 * Revision 1.7 1998/07/01 00:18:02 brianp
54 * if gluBuildxDMipmaps() width or height <= 0 just return 0
56 * Revision 1.6 1998/06/01 01:06:41 brianp
57 * small update for Next/OpenStep from Alexander Mai
59 * Revision 1.5 1997/07/24 01:28:44 brianp
60 * changed precompiled header symbol from PCH to PC_HEADER
62 * Revision 1.4 1997/06/23 00:22:56 brianp
63 * added dummy() call to work around an MSVC 4.1 bug
65 * Revision 1.3 1997/05/28 02:29:38 brianp
66 * added support for precompiled headers (PCH), inserted APIENTRY keyword
68 * Revision 1.2 1997/05/24 13:32:25 brianp
69 * undef EPSILON in case it's already defined
71 * Revision 1.1 1996/09/27 01:19:39 brianp
89 * Compute ceiling of integer quotient of A divided by B:
91 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
101 /* To work around optimizer bug in MSVC4.1 */
102 #if defined(__WIN32__) && !defined(OPENSTEP)
103 void dummy(GLuint j
, GLuint k
){
110 GLint GLAPIENTRY
gluScaleImage( GLenum format
,
111 GLsizei widthin
, GLsizei heightin
,
112 GLenum typein
, const void *datain
,
113 GLsizei widthout
, GLsizei heightout
,
114 GLenum typeout
, void *dataout
)
116 GLint components
, i
, j
, k
;
117 GLfloat
*tempin
, *tempout
;
119 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
120 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
121 GLint sizein
, sizeout
;
122 GLint rowstride
, rowlen
;
125 /* Determine number of components per pixel */
128 case GL_STENCIL_INDEX
:
129 case GL_DEPTH_COMPONENT
:
137 case GL_LUMINANCE_ALPHA
:
150 return GLU_INVALID_ENUM
;
153 /* Determine bytes per input datum */
155 case GL_UNSIGNED_BYTE
: sizein
= sizeof(GLubyte
); break;
156 case GL_BYTE
: sizein
= sizeof(GLbyte
); break;
157 case GL_UNSIGNED_SHORT
: sizein
= sizeof(GLushort
); break;
158 case GL_SHORT
: sizein
= sizeof(GLshort
); break;
159 case GL_UNSIGNED_INT
: sizein
= sizeof(GLuint
); break;
160 case GL_INT
: sizein
= sizeof(GLint
); break;
161 case GL_FLOAT
: sizein
= sizeof(GLfloat
); break;
163 /* not implemented yet */
165 return GL_INVALID_ENUM
;
168 /* Determine bytes per output datum */
170 case GL_UNSIGNED_BYTE
: sizeout
= sizeof(GLubyte
); break;
171 case GL_BYTE
: sizeout
= sizeof(GLbyte
); break;
172 case GL_UNSIGNED_SHORT
: sizeout
= sizeof(GLushort
); break;
173 case GL_SHORT
: sizeout
= sizeof(GLshort
); break;
174 case GL_UNSIGNED_INT
: sizeout
= sizeof(GLuint
); break;
175 case GL_INT
: sizeout
= sizeof(GLint
); break;
176 case GL_FLOAT
: sizeout
= sizeof(GLfloat
); break;
178 /* not implemented yet */
180 return GL_INVALID_ENUM
;
183 /* Get glPixelStore state */
184 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
185 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
186 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
187 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
188 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
189 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
190 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
191 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
193 /* Allocate storage for intermediate images */
194 tempin
= (GLfloat
*) malloc( widthin
* heightin
195 * components
* sizeof(GLfloat
) );
197 return GLU_OUT_OF_MEMORY
;
199 tempout
= (GLfloat
*) malloc( widthout
* heightout
200 * components
* sizeof(GLfloat
) );
203 return GLU_OUT_OF_MEMORY
;
208 * Unpack the pixel data and convert to floating point
211 if (unpackrowlength
>0) {
212 rowlen
= unpackrowlength
;
217 if (sizein
>= unpackalignment
) {
218 rowstride
= components
* rowlen
;
221 rowstride
= unpackalignment
/sizein
222 * CEILING( components
* rowlen
* sizein
, unpackalignment
);
226 case GL_UNSIGNED_BYTE
:
228 for (i
=0;i
<heightin
;i
++) {
229 GLubyte
*ubptr
= (GLubyte
*) datain
231 + unpackskiprows
* rowstride
232 + unpackskippixels
* components
;
233 for (j
=0;j
<widthin
*components
;j
++) {
235 tempin
[k
++] = (GLfloat
) *ubptr
++;
241 for (i
=0;i
<heightin
;i
++) {
242 GLbyte
*bptr
= (GLbyte
*) datain
244 + unpackskiprows
* rowstride
245 + unpackskippixels
* components
;
246 for (j
=0;j
<widthin
*components
;j
++) {
248 tempin
[k
++] = (GLfloat
) *bptr
++;
252 case GL_UNSIGNED_SHORT
:
254 for (i
=0;i
<heightin
;i
++) {
255 GLushort
*usptr
= (GLushort
*) datain
257 + unpackskiprows
* rowstride
258 + unpackskippixels
* components
;
259 for (j
=0;j
<widthin
*components
;j
++) {
261 tempin
[k
++] = (GLfloat
) *usptr
++;
267 for (i
=0;i
<heightin
;i
++) {
268 GLshort
*sptr
= (GLshort
*) datain
270 + unpackskiprows
* rowstride
271 + unpackskippixels
* components
;
272 for (j
=0;j
<widthin
*components
;j
++) {
274 tempin
[k
++] = (GLfloat
) *sptr
++;
278 case GL_UNSIGNED_INT
:
280 for (i
=0;i
<heightin
;i
++) {
281 GLuint
*uiptr
= (GLuint
*) datain
283 + unpackskiprows
* rowstride
284 + unpackskippixels
* components
;
285 for (j
=0;j
<widthin
*components
;j
++) {
287 tempin
[k
++] = (GLfloat
) *uiptr
++;
293 for (i
=0;i
<heightin
;i
++) {
294 GLint
*iptr
= (GLint
*) datain
296 + unpackskiprows
* rowstride
297 + unpackskippixels
* components
;
298 for (j
=0;j
<widthin
*components
;j
++) {
300 tempin
[k
++] = (GLfloat
) *iptr
++;
306 for (i
=0;i
<heightin
;i
++) {
307 GLfloat
*fptr
= (GLfloat
*) datain
309 + unpackskiprows
* rowstride
310 + unpackskippixels
* components
;
311 for (j
=0;j
<widthin
*components
;j
++) {
313 tempin
[k
++] = *fptr
++;
318 return GLU_INVALID_ENUM
;
327 sx
= (GLfloat
) (widthin
-1) / (GLfloat
) (widthout
-1);
329 sx
= (GLfloat
) (widthin
-1);
331 sy
= (GLfloat
) (heightin
-1) / (GLfloat
) (heightout
-1);
333 sy
= (GLfloat
) (heightin
-1);
335 /*#define POINT_SAMPLE*/
337 for (i
=0;i
<heightout
;i
++) {
339 for (j
=0;j
<widthout
;j
++) {
342 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
343 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
345 for (k
=0;k
<components
;k
++) {
351 if (sx
<1.0 && sy
<1.0) {
352 /* magnify both width and height: use weighted sample of 4 pixels */
353 GLint i0
, i1
, j0
, j1
;
355 GLfloat
*src00
, *src01
, *src10
, *src11
;
359 for (i
=0;i
<heightout
;i
++) {
362 if (i1
>= heightin
) i1
= heightin
-1;
363 /* i1 = (i+1) * sy - EPSILON;*/
365 for (j
=0;j
<widthout
;j
++) {
368 if (j1
>= widthin
) j1
= widthin
-1;
369 /* j1 = (j+1) * sx - EPSILON; */
372 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
373 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
374 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
375 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
376 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
378 dst
= tempout
+ (i
* widthout
+ j
) * components
;
380 for (k
=0;k
<components
;k
++) {
381 s1
= *src00
++ * (1.0-beta
) + *src01
++ * beta
;
382 s2
= *src10
++ * (1.0-beta
) + *src11
++ * beta
;
383 *dst
++ = s1
* (1.0-alpha
) + s2
* alpha
;
389 /* shrink width and/or height: use an unweighted box filter */
395 for (i
=0;i
<heightout
;i
++) {
398 if (i1
>= heightin
) i1
= heightin
-1;
399 /* i1 = (i+1) * sy - EPSILON; */
400 for (j
=0;j
<widthout
;j
++) {
403 if (j1
>= widthin
) j1
= widthin
-1;
404 /* j1 = (j+1) * sx - EPSILON; */
406 dst
= tempout
+ (i
* widthout
+ j
) * components
;
408 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
409 for (k
=0;k
<components
;k
++) {
411 for (ii
=i0
;ii
<=i1
;ii
++) {
412 for (jj
=j0
;jj
<=j1
;jj
++) {
413 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
416 sum
/= (j1
-j0
+1) * (i1
-i0
+1);
426 * Return output image
429 if (packrowlength
>0) {
430 rowlen
= packrowlength
;
435 if (sizeout
>= packalignment
) {
436 rowstride
= components
* rowlen
;
439 rowstride
= packalignment
/sizeout
440 * CEILING( components
* rowlen
* sizeout
, packalignment
);
444 case GL_UNSIGNED_BYTE
:
446 for (i
=0;i
<heightout
;i
++) {
447 GLubyte
*ubptr
= (GLubyte
*) dataout
449 + packskiprows
* rowstride
450 + packskippixels
* components
;
451 for (j
=0;j
<widthout
*components
;j
++) {
453 *ubptr
++ = (GLubyte
) tempout
[k
++];
459 for (i
=0;i
<heightout
;i
++) {
460 GLbyte
*bptr
= (GLbyte
*) dataout
462 + packskiprows
* rowstride
463 + packskippixels
* components
;
464 for (j
=0;j
<widthout
*components
;j
++) {
466 *bptr
++ = (GLbyte
) tempout
[k
++];
470 case GL_UNSIGNED_SHORT
:
472 for (i
=0;i
<heightout
;i
++) {
473 GLushort
*usptr
= (GLushort
*) dataout
475 + packskiprows
* rowstride
476 + packskippixels
* components
;
477 for (j
=0;j
<widthout
*components
;j
++) {
479 *usptr
++ = (GLushort
) tempout
[k
++];
485 for (i
=0;i
<heightout
;i
++) {
486 GLshort
*sptr
= (GLshort
*) dataout
488 + packskiprows
* rowstride
489 + packskippixels
* components
;
490 for (j
=0;j
<widthout
*components
;j
++) {
492 *sptr
++ = (GLshort
) tempout
[k
++];
496 case GL_UNSIGNED_INT
:
498 for (i
=0;i
<heightout
;i
++) {
499 GLuint
*uiptr
= (GLuint
*) dataout
501 + packskiprows
* rowstride
502 + packskippixels
* components
;
503 for (j
=0;j
<widthout
*components
;j
++) {
505 *uiptr
++ = (GLuint
) tempout
[k
++];
511 for (i
=0;i
<heightout
;i
++) {
512 GLint
*iptr
= (GLint
*) dataout
514 + packskiprows
* rowstride
515 + packskippixels
* components
;
516 for (j
=0;j
<widthout
*components
;j
++) {
518 *iptr
++ = (GLint
) tempout
[k
++];
524 for (i
=0;i
<heightout
;i
++) {
525 GLfloat
*fptr
= (GLfloat
*) dataout
527 + packskiprows
* rowstride
528 + packskippixels
* components
;
529 for (j
=0;j
<widthout
*components
;j
++) {
531 *fptr
++ = tempout
[k
++];
536 return GLU_INVALID_ENUM
;
540 /* free temporary image storage */
550 * Return the largest k such that 2^k <= n.
552 static GLint
ilog2( GLint n
)
557 for (k
=0; n
>>=1; k
++) ;
564 * Find the value nearest to n which is also a power of two.
566 static GLint
round2( GLint n
)
584 * Given an pixel format and datatype, return the number of bytes to
587 static GLint
bytes_per_pixel( GLenum format
, GLenum type
)
593 case GL_STENCIL_INDEX
:
594 case GL_DEPTH_COMPONENT
:
602 case GL_LUMINANCE_ALPHA
:
619 case GL_UNSIGNED_BYTE
: m
= sizeof(GLubyte
); break;
620 case GL_BYTE
: m
= sizeof(GLbyte
); break;
621 case GL_BITMAP
: m
= 1; break;
622 case GL_UNSIGNED_SHORT
: m
= sizeof(GLushort
); break;
623 case GL_SHORT
: m
= sizeof(GLshort
); break;
624 case GL_UNSIGNED_INT
: m
= sizeof(GLuint
); break;
625 case GL_INT
: m
= sizeof(GLint
); break;
626 case GL_FLOAT
: m
= sizeof(GLfloat
); break;
636 * WARNING: This function isn't finished and has never been tested!!!!
638 GLint GLAPIENTRY
gluBuild1DMipmaps( GLenum target
, GLint components
,
639 GLsizei width
, GLenum format
,
640 GLenum type
, const void *data
)
643 GLint levels
, max_levels
;
644 GLint new_width
, max_width
;
648 return GLU_INVALID_VALUE
;
650 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &max_width
);
651 max_levels
= ilog2( max_width
) + 1;
653 /* Compute how many mipmap images to make */
654 levels
= ilog2( width
) + 1;
655 if (levels
>max_levels
) {
659 new_width
= 1 << (levels
-1);
661 texture
= (GLubyte
*) malloc( new_width
* components
);
663 return GLU_OUT_OF_MEMORY
;
666 if (width
!= new_width
) {
667 /* initial rescaling */
669 case GL_UNSIGNED_BYTE
:
671 GLubyte
*ub_data
= (GLubyte
*) data
;
672 for (i
=0;i
<new_width
;i
++) {
673 j
= i
* width
/ new_width
;
674 for (k
=0;k
<components
;k
++) {
675 texture
[i
*components
+k
] = ub_data
[j
*components
+k
];
681 /* Not implemented */
686 /* generate and load mipmap images */
687 for (l
=0;l
<levels
;l
++) {
688 glTexImage1D( GL_TEXTURE_1D
, l
, components
, new_width
, 0,
689 format
, GL_UNSIGNED_BYTE
, texture
);
691 /* Scale image down to 1/2 size */
692 new_width
= new_width
/ 2;
693 for (i
=0;i
<new_width
;i
++) {
694 for (k
=0;k
<components
;k
++) {
695 GLint sample1
, sample2
;
696 sample1
= (GLint
) texture
[i
*2*components
+k
];
697 sample2
= (GLint
) texture
[(i
*2+1)*components
+k
];
698 texture
[i
*components
+k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
705 /* make sure remaining mipmap levels are removed */
706 for (l
=levels
;l
<max_levels
;l
++) {
707 glTexImage1D( GL_TEXTURE_1D
, l
, components
, 0, 0,
708 format
, GL_UNSIGNED_BYTE
, NULL
);
716 GLint GLAPIENTRY
gluBuild2DMipmaps( GLenum target
, GLint components
,
717 GLsizei width
, GLsizei height
, GLenum format
,
718 GLenum type
, const void *data
)
721 void *image
, *newimage
;
722 GLint neww
, newh
, level
, bpp
;
726 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
727 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
729 if (width
< 1 || height
< 1)
730 return GLU_INVALID_VALUE
;
732 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &maxsize
);
738 h
= round2( height
);
743 bpp
= bytes_per_pixel( format
, type
);
745 /* probably a bad format or type enum */
746 return GLU_INVALID_ENUM
;
749 /* Get current glPixelStore values */
750 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
751 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
752 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
753 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
754 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
755 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
756 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
757 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
759 /* set pixel packing */
760 glPixelStorei( GL_PACK_ROW_LENGTH
, 0 );
761 glPixelStorei( GL_PACK_ALIGNMENT
, 1 );
762 glPixelStorei( GL_PACK_SKIP_ROWS
, 0 );
763 glPixelStorei( GL_PACK_SKIP_PIXELS
, 0 );
767 if (w
!=width
|| h
!=height
) {
768 /* must rescale image to get "top" mipmap texture image */
769 image
= malloc( (w
+4) * h
* bpp
);
771 return GLU_OUT_OF_MEMORY
;
773 error
= gluScaleImage( format
, width
, height
, type
, data
,
781 image
= (void *) data
;
787 /* set pixel unpacking */
788 glPixelStorei( GL_UNPACK_ROW_LENGTH
, 0 );
789 glPixelStorei( GL_UNPACK_ALIGNMENT
, 1 );
790 glPixelStorei( GL_UNPACK_SKIP_ROWS
, 0 );
791 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, 0 );
794 glTexImage2D( target
, level
, components
, w
, h
, 0, format
, type
, image
);
796 if (w
==1 && h
==1) break;
798 neww
= (w
<2) ? 1 : w
/2;
799 newh
= (h
<2) ? 1 : h
/2;
800 newimage
= malloc( (neww
+4) * newh
* bpp
);
802 return GLU_OUT_OF_MEMORY
;
805 error
= gluScaleImage( format
, w
, h
, type
, image
,
806 neww
, newh
, type
, newimage
);
826 /* Restore original glPixelStore state */
827 glPixelStorei( GL_UNPACK_ROW_LENGTH
, unpackrowlength
);
828 glPixelStorei( GL_UNPACK_ALIGNMENT
, unpackalignment
);
829 glPixelStorei( GL_UNPACK_SKIP_ROWS
, unpackskiprows
);
830 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, unpackskippixels
);
831 glPixelStorei( GL_PACK_ROW_LENGTH
, packrowlength
);
832 glPixelStorei( GL_PACK_ALIGNMENT
, packalignment
);
833 glPixelStorei( GL_PACK_SKIP_ROWS
, packskiprows
);
834 glPixelStorei( GL_PACK_SKIP_PIXELS
, packskippixels
);