63246f3958ec8d74684761294574931e7e480cdc
1 /* $Id: mipmap.c,v 1.2 1999/09/14 00:30:28 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.2 1999/09/14 00:30:28 brianp
27 * fixed pixel packing/unpacking code in gluBuild2DMipmaps()
29 * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
32 * Revision 1.13 1999/03/05 17:49:06 brianp
33 * added support for GL_EXT_abgr (devernay@istar.fr)
35 * Revision 1.12 1999/01/03 03:23:15 brianp
36 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
38 * Revision 1.11 1998/09/18 02:44:03 brianp
39 * further changes to gluScaleImage() per Randy Frank
41 * Revision 1.10 1998/09/17 03:20:26 brianp
42 * fixed another bug in gluScaleImage() per Sven Panne
44 * Revision 1.9 1998/07/31 03:06:20 brianp
45 * tweaked the gluScaleImage() function per Randy Frank
47 * Revision 1.8 1998/07/08 01:02:53 brianp
48 * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
50 * Revision 1.7 1998/07/01 00:18:02 brianp
51 * if gluBuildxDMipmaps() width or height <= 0 just return 0
53 * Revision 1.6 1998/06/01 01:06:41 brianp
54 * small update for Next/OpenStep from Alexander Mai
56 * Revision 1.5 1997/07/24 01:28:44 brianp
57 * changed precompiled header symbol from PCH to PC_HEADER
59 * Revision 1.4 1997/06/23 00:22:56 brianp
60 * added dummy() call to work around an MSVC 4.1 bug
62 * Revision 1.3 1997/05/28 02:29:38 brianp
63 * added support for precompiled headers (PCH), inserted APIENTRY keyword
65 * Revision 1.2 1997/05/24 13:32:25 brianp
66 * undef EPSILON in case it's already defined
68 * Revision 1.1 1996/09/27 01:19:39 brianp
86 * Compute ceiling of integer quotient of A divided by B:
88 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
98 /* To work around optimizer bug in MSVC4.1 */
99 #if defined(__WIN32__) && !defined(OPENSTEP)
100 void dummy(GLuint j
, GLuint k
){
107 GLint GLAPIENTRY
gluScaleImage( GLenum format
,
108 GLint widthin
, GLint heightin
,
109 GLenum typein
, const void *datain
,
110 GLint widthout
, GLint heightout
,
111 GLenum typeout
, void *dataout
)
113 GLint components
, i
, j
, k
;
114 GLfloat
*tempin
, *tempout
;
116 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
117 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
118 GLint sizein
, sizeout
;
119 GLint rowstride
, rowlen
;
122 /* Determine number of components per pixel */
125 case GL_STENCIL_INDEX
:
126 case GL_DEPTH_COMPONENT
:
134 case GL_LUMINANCE_ALPHA
:
147 return GLU_INVALID_ENUM
;
150 /* Determine bytes per input datum */
152 case GL_UNSIGNED_BYTE
: sizein
= sizeof(GLubyte
); break;
153 case GL_BYTE
: sizein
= sizeof(GLbyte
); break;
154 case GL_UNSIGNED_SHORT
: sizein
= sizeof(GLushort
); break;
155 case GL_SHORT
: sizein
= sizeof(GLshort
); break;
156 case GL_UNSIGNED_INT
: sizein
= sizeof(GLuint
); break;
157 case GL_INT
: sizein
= sizeof(GLint
); break;
158 case GL_FLOAT
: sizein
= sizeof(GLfloat
); break;
160 /* not implemented yet */
162 return GL_INVALID_ENUM
;
165 /* Determine bytes per output datum */
167 case GL_UNSIGNED_BYTE
: sizeout
= sizeof(GLubyte
); break;
168 case GL_BYTE
: sizeout
= sizeof(GLbyte
); break;
169 case GL_UNSIGNED_SHORT
: sizeout
= sizeof(GLushort
); break;
170 case GL_SHORT
: sizeout
= sizeof(GLshort
); break;
171 case GL_UNSIGNED_INT
: sizeout
= sizeof(GLuint
); break;
172 case GL_INT
: sizeout
= sizeof(GLint
); break;
173 case GL_FLOAT
: sizeout
= sizeof(GLfloat
); break;
175 /* not implemented yet */
177 return GL_INVALID_ENUM
;
180 /* Get glPixelStore state */
181 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
182 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
183 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
184 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
185 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
186 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
187 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
188 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
190 /* Allocate storage for intermediate images */
191 tempin
= (GLfloat
*) malloc( widthin
* heightin
192 * components
* sizeof(GLfloat
) );
194 return GLU_OUT_OF_MEMORY
;
196 tempout
= (GLfloat
*) malloc( widthout
* heightout
197 * components
* sizeof(GLfloat
) );
200 return GLU_OUT_OF_MEMORY
;
205 * Unpack the pixel data and convert to floating point
208 if (unpackrowlength
>0) {
209 rowlen
= unpackrowlength
;
214 if (sizein
>= unpackalignment
) {
215 rowstride
= components
* rowlen
;
218 rowstride
= unpackalignment
/sizein
219 * CEILING( components
* rowlen
* sizein
, unpackalignment
);
223 case GL_UNSIGNED_BYTE
:
225 for (i
=0;i
<heightin
;i
++) {
226 GLubyte
*ubptr
= (GLubyte
*) datain
228 + unpackskiprows
* rowstride
229 + unpackskippixels
* components
;
230 for (j
=0;j
<widthin
*components
;j
++) {
232 tempin
[k
++] = (GLfloat
) *ubptr
++;
238 for (i
=0;i
<heightin
;i
++) {
239 GLbyte
*bptr
= (GLbyte
*) datain
241 + unpackskiprows
* rowstride
242 + unpackskippixels
* components
;
243 for (j
=0;j
<widthin
*components
;j
++) {
245 tempin
[k
++] = (GLfloat
) *bptr
++;
249 case GL_UNSIGNED_SHORT
:
251 for (i
=0;i
<heightin
;i
++) {
252 GLushort
*usptr
= (GLushort
*) datain
254 + unpackskiprows
* rowstride
255 + unpackskippixels
* components
;
256 for (j
=0;j
<widthin
*components
;j
++) {
258 tempin
[k
++] = (GLfloat
) *usptr
++;
264 for (i
=0;i
<heightin
;i
++) {
265 GLshort
*sptr
= (GLshort
*) datain
267 + unpackskiprows
* rowstride
268 + unpackskippixels
* components
;
269 for (j
=0;j
<widthin
*components
;j
++) {
271 tempin
[k
++] = (GLfloat
) *sptr
++;
275 case GL_UNSIGNED_INT
:
277 for (i
=0;i
<heightin
;i
++) {
278 GLuint
*uiptr
= (GLuint
*) datain
280 + unpackskiprows
* rowstride
281 + unpackskippixels
* components
;
282 for (j
=0;j
<widthin
*components
;j
++) {
284 tempin
[k
++] = (GLfloat
) *uiptr
++;
290 for (i
=0;i
<heightin
;i
++) {
291 GLint
*iptr
= (GLint
*) datain
293 + unpackskiprows
* rowstride
294 + unpackskippixels
* components
;
295 for (j
=0;j
<widthin
*components
;j
++) {
297 tempin
[k
++] = (GLfloat
) *iptr
++;
303 for (i
=0;i
<heightin
;i
++) {
304 GLfloat
*fptr
= (GLfloat
*) datain
306 + unpackskiprows
* rowstride
307 + unpackskippixels
* components
;
308 for (j
=0;j
<widthin
*components
;j
++) {
310 tempin
[k
++] = *fptr
++;
315 return GLU_INVALID_ENUM
;
324 sx
= (GLfloat
) (widthin
-1) / (GLfloat
) (widthout
-1);
326 sx
= (GLfloat
) (widthin
-1);
328 sy
= (GLfloat
) (heightin
-1) / (GLfloat
) (heightout
-1);
330 sy
= (GLfloat
) (heightin
-1);
332 /*#define POINT_SAMPLE*/
334 for (i
=0;i
<heightout
;i
++) {
336 for (j
=0;j
<widthout
;j
++) {
339 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
340 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
342 for (k
=0;k
<components
;k
++) {
348 if (sx
<1.0 && sy
<1.0) {
349 /* magnify both width and height: use weighted sample of 4 pixels */
350 GLint i0
, i1
, j0
, j1
;
352 GLfloat
*src00
, *src01
, *src10
, *src11
;
356 for (i
=0;i
<heightout
;i
++) {
359 if (i1
>= heightin
) i1
= heightin
-1;
360 /* i1 = (i+1) * sy - EPSILON;*/
362 for (j
=0;j
<widthout
;j
++) {
365 if (j1
>= widthin
) j1
= widthin
-1;
366 /* j1 = (j+1) * sx - EPSILON; */
369 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
370 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
371 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
372 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
373 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
375 dst
= tempout
+ (i
* widthout
+ j
) * components
;
377 for (k
=0;k
<components
;k
++) {
378 s1
= *src00
++ * (1.0-beta
) + *src01
++ * beta
;
379 s2
= *src10
++ * (1.0-beta
) + *src11
++ * beta
;
380 *dst
++ = s1
* (1.0-alpha
) + s2
* alpha
;
386 /* shrink width and/or height: use an unweighted box filter */
392 for (i
=0;i
<heightout
;i
++) {
395 if (i1
>= heightin
) i1
= heightin
-1;
396 /* i1 = (i+1) * sy - EPSILON; */
397 for (j
=0;j
<widthout
;j
++) {
400 if (j1
>= widthin
) j1
= widthin
-1;
401 /* j1 = (j+1) * sx - EPSILON; */
403 dst
= tempout
+ (i
* widthout
+ j
) * components
;
405 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
406 for (k
=0;k
<components
;k
++) {
408 for (ii
=i0
;ii
<=i1
;ii
++) {
409 for (jj
=j0
;jj
<=j1
;jj
++) {
410 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
413 sum
/= (j1
-j0
+1) * (i1
-i0
+1);
423 * Return output image
426 if (packrowlength
>0) {
427 rowlen
= packrowlength
;
432 if (sizeout
>= packalignment
) {
433 rowstride
= components
* rowlen
;
436 rowstride
= packalignment
/sizeout
437 * CEILING( components
* rowlen
* sizeout
, packalignment
);
441 case GL_UNSIGNED_BYTE
:
443 for (i
=0;i
<heightout
;i
++) {
444 GLubyte
*ubptr
= (GLubyte
*) dataout
446 + packskiprows
* rowstride
447 + packskippixels
* components
;
448 for (j
=0;j
<widthout
*components
;j
++) {
450 *ubptr
++ = (GLubyte
) tempout
[k
++];
456 for (i
=0;i
<heightout
;i
++) {
457 GLbyte
*bptr
= (GLbyte
*) dataout
459 + packskiprows
* rowstride
460 + packskippixels
* components
;
461 for (j
=0;j
<widthout
*components
;j
++) {
463 *bptr
++ = (GLbyte
) tempout
[k
++];
467 case GL_UNSIGNED_SHORT
:
469 for (i
=0;i
<heightout
;i
++) {
470 GLushort
*usptr
= (GLushort
*) dataout
472 + packskiprows
* rowstride
473 + packskippixels
* components
;
474 for (j
=0;j
<widthout
*components
;j
++) {
476 *usptr
++ = (GLushort
) tempout
[k
++];
482 for (i
=0;i
<heightout
;i
++) {
483 GLshort
*sptr
= (GLshort
*) dataout
485 + packskiprows
* rowstride
486 + packskippixels
* components
;
487 for (j
=0;j
<widthout
*components
;j
++) {
489 *sptr
++ = (GLshort
) tempout
[k
++];
493 case GL_UNSIGNED_INT
:
495 for (i
=0;i
<heightout
;i
++) {
496 GLuint
*uiptr
= (GLuint
*) dataout
498 + packskiprows
* rowstride
499 + packskippixels
* components
;
500 for (j
=0;j
<widthout
*components
;j
++) {
502 *uiptr
++ = (GLuint
) tempout
[k
++];
508 for (i
=0;i
<heightout
;i
++) {
509 GLint
*iptr
= (GLint
*) dataout
511 + packskiprows
* rowstride
512 + packskippixels
* components
;
513 for (j
=0;j
<widthout
*components
;j
++) {
515 *iptr
++ = (GLint
) tempout
[k
++];
521 for (i
=0;i
<heightout
;i
++) {
522 GLfloat
*fptr
= (GLfloat
*) dataout
524 + packskiprows
* rowstride
525 + packskippixels
* components
;
526 for (j
=0;j
<widthout
*components
;j
++) {
528 *fptr
++ = tempout
[k
++];
533 return GLU_INVALID_ENUM
;
537 /* free temporary image storage */
547 * Return the largest k such that 2^k <= n.
549 static GLint
ilog2( GLint n
)
554 for (k
=0; n
>>=1; k
++) ;
561 * Find the value nearest to n which is also a power of two.
563 static GLint
round2( GLint n
)
581 * Given an pixel format and datatype, return the number of bytes to
584 static GLint
bytes_per_pixel( GLenum format
, GLenum type
)
590 case GL_STENCIL_INDEX
:
591 case GL_DEPTH_COMPONENT
:
599 case GL_LUMINANCE_ALPHA
:
616 case GL_UNSIGNED_BYTE
: m
= sizeof(GLubyte
); break;
617 case GL_BYTE
: m
= sizeof(GLbyte
); break;
618 case GL_BITMAP
: m
= 1; break;
619 case GL_UNSIGNED_SHORT
: m
= sizeof(GLushort
); break;
620 case GL_SHORT
: m
= sizeof(GLshort
); break;
621 case GL_UNSIGNED_INT
: m
= sizeof(GLuint
); break;
622 case GL_INT
: m
= sizeof(GLint
); break;
623 case GL_FLOAT
: m
= sizeof(GLfloat
); break;
633 * WARNING: This function isn't finished and has never been tested!!!!
635 GLint GLAPIENTRY
gluBuild1DMipmaps( GLenum target
, GLint components
,
636 GLint width
, GLenum format
,
637 GLenum type
, const void *data
)
640 GLint levels
, max_levels
;
641 GLint new_width
, max_width
;
645 return GLU_INVALID_VALUE
;
647 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &max_width
);
648 max_levels
= ilog2( max_width
) + 1;
650 /* Compute how many mipmap images to make */
651 levels
= ilog2( width
) + 1;
652 if (levels
>max_levels
) {
656 new_width
= 1 << (levels
-1);
658 texture
= (GLubyte
*) malloc( new_width
* components
);
660 return GLU_OUT_OF_MEMORY
;
663 if (width
!= new_width
) {
664 /* initial rescaling */
666 case GL_UNSIGNED_BYTE
:
668 GLubyte
*ub_data
= (GLubyte
*) data
;
669 for (i
=0;i
<new_width
;i
++) {
670 j
= i
* width
/ new_width
;
671 for (k
=0;k
<components
;k
++) {
672 texture
[i
*components
+k
] = ub_data
[j
*components
+k
];
678 /* Not implemented */
683 /* generate and load mipmap images */
684 for (l
=0;l
<levels
;l
++) {
685 glTexImage1D( GL_TEXTURE_1D
, l
, components
, new_width
, 0,
686 format
, GL_UNSIGNED_BYTE
, texture
);
688 /* Scale image down to 1/2 size */
689 new_width
= new_width
/ 2;
690 for (i
=0;i
<new_width
;i
++) {
691 for (k
=0;k
<components
;k
++) {
692 GLint sample1
, sample2
;
693 sample1
= (GLint
) texture
[i
*2*components
+k
];
694 sample2
= (GLint
) texture
[(i
*2+1)*components
+k
];
695 texture
[i
*components
+k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
702 /* make sure remaining mipmap levels are removed */
703 for (l
=levels
;l
<max_levels
;l
++) {
704 glTexImage1D( GL_TEXTURE_1D
, l
, components
, 0, 0,
705 format
, GL_UNSIGNED_BYTE
, NULL
);
713 GLint GLAPIENTRY
gluBuild2DMipmaps( GLenum target
, GLint components
,
714 GLint width
, GLint 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
);