1 /* $Id: mipmap.c,v 1.6 2000/06/05 16:27:41 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-2000 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.
36 * Compute ceiling of integer quotient of A divided by B:
38 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
48 /* To work around optimizer bug in MSVC4.1 */
49 #if defined(__WIN32__) && !defined(OPENSTEP)
50 void dummy(GLuint j
, GLuint k
){
57 GLint GLAPIENTRY
gluScaleImage( GLenum format
,
58 GLsizei widthin
, GLsizei heightin
,
59 GLenum typein
, const void *datain
,
60 GLsizei widthout
, GLsizei heightout
,
61 GLenum typeout
, void *dataout
)
63 GLint components
, i
, j
, k
;
64 GLfloat
*tempin
, *tempout
;
66 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
67 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
68 GLint sizein
, sizeout
;
69 GLint rowstride
, rowlen
;
72 /* Determine number of components per pixel */
75 case GL_STENCIL_INDEX
:
76 case GL_DEPTH_COMPONENT
:
84 case GL_LUMINANCE_ALPHA
:
99 return GLU_INVALID_ENUM
;
102 /* Determine bytes per input datum */
104 case GL_UNSIGNED_BYTE
: sizein
= sizeof(GLubyte
); break;
105 case GL_BYTE
: sizein
= sizeof(GLbyte
); break;
106 case GL_UNSIGNED_SHORT
: sizein
= sizeof(GLushort
); break;
107 case GL_SHORT
: sizein
= sizeof(GLshort
); break;
108 case GL_UNSIGNED_INT
: sizein
= sizeof(GLuint
); break;
109 case GL_INT
: sizein
= sizeof(GLint
); break;
110 case GL_FLOAT
: sizein
= sizeof(GLfloat
); break;
112 /* not implemented yet */
114 return GL_INVALID_ENUM
;
117 /* Determine bytes per output datum */
119 case GL_UNSIGNED_BYTE
: sizeout
= sizeof(GLubyte
); break;
120 case GL_BYTE
: sizeout
= sizeof(GLbyte
); break;
121 case GL_UNSIGNED_SHORT
: sizeout
= sizeof(GLushort
); break;
122 case GL_SHORT
: sizeout
= sizeof(GLshort
); break;
123 case GL_UNSIGNED_INT
: sizeout
= sizeof(GLuint
); break;
124 case GL_INT
: sizeout
= sizeof(GLint
); break;
125 case GL_FLOAT
: sizeout
= sizeof(GLfloat
); break;
127 /* not implemented yet */
129 return GL_INVALID_ENUM
;
132 /* Get glPixelStore state */
133 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
134 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
135 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
136 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
137 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
138 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
139 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
140 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
142 /* Allocate storage for intermediate images */
143 tempin
= (GLfloat
*) malloc( widthin
* heightin
144 * components
* sizeof(GLfloat
) );
146 return GLU_OUT_OF_MEMORY
;
148 tempout
= (GLfloat
*) malloc( widthout
* heightout
149 * components
* sizeof(GLfloat
) );
152 return GLU_OUT_OF_MEMORY
;
157 * Unpack the pixel data and convert to floating point
160 if (unpackrowlength
>0) {
161 rowlen
= unpackrowlength
;
166 if (sizein
>= unpackalignment
) {
167 rowstride
= components
* rowlen
;
170 rowstride
= unpackalignment
/sizein
171 * CEILING( components
* rowlen
* sizein
, unpackalignment
);
175 case GL_UNSIGNED_BYTE
:
177 for (i
=0;i
<heightin
;i
++) {
178 GLubyte
*ubptr
= (GLubyte
*) datain
180 + unpackskiprows
* rowstride
181 + unpackskippixels
* components
;
182 for (j
=0;j
<widthin
*components
;j
++) {
184 tempin
[k
++] = (GLfloat
) *ubptr
++;
190 for (i
=0;i
<heightin
;i
++) {
191 GLbyte
*bptr
= (GLbyte
*) datain
193 + unpackskiprows
* rowstride
194 + unpackskippixels
* components
;
195 for (j
=0;j
<widthin
*components
;j
++) {
197 tempin
[k
++] = (GLfloat
) *bptr
++;
201 case GL_UNSIGNED_SHORT
:
203 for (i
=0;i
<heightin
;i
++) {
204 GLushort
*usptr
= (GLushort
*) datain
206 + unpackskiprows
* rowstride
207 + unpackskippixels
* components
;
208 for (j
=0;j
<widthin
*components
;j
++) {
210 tempin
[k
++] = (GLfloat
) *usptr
++;
216 for (i
=0;i
<heightin
;i
++) {
217 GLshort
*sptr
= (GLshort
*) datain
219 + unpackskiprows
* rowstride
220 + unpackskippixels
* components
;
221 for (j
=0;j
<widthin
*components
;j
++) {
223 tempin
[k
++] = (GLfloat
) *sptr
++;
227 case GL_UNSIGNED_INT
:
229 for (i
=0;i
<heightin
;i
++) {
230 GLuint
*uiptr
= (GLuint
*) datain
232 + unpackskiprows
* rowstride
233 + unpackskippixels
* components
;
234 for (j
=0;j
<widthin
*components
;j
++) {
236 tempin
[k
++] = (GLfloat
) *uiptr
++;
242 for (i
=0;i
<heightin
;i
++) {
243 GLint
*iptr
= (GLint
*) datain
245 + unpackskiprows
* rowstride
246 + unpackskippixels
* components
;
247 for (j
=0;j
<widthin
*components
;j
++) {
249 tempin
[k
++] = (GLfloat
) *iptr
++;
255 for (i
=0;i
<heightin
;i
++) {
256 GLfloat
*fptr
= (GLfloat
*) datain
258 + unpackskiprows
* rowstride
259 + unpackskippixels
* components
;
260 for (j
=0;j
<widthin
*components
;j
++) {
262 tempin
[k
++] = *fptr
++;
267 return GLU_INVALID_ENUM
;
276 sx
= (GLfloat
) (widthin
-1) / (GLfloat
) (widthout
-1);
278 sx
= (GLfloat
) (widthin
-1);
280 sy
= (GLfloat
) (heightin
-1) / (GLfloat
) (heightout
-1);
282 sy
= (GLfloat
) (heightin
-1);
284 /*#define POINT_SAMPLE*/
286 for (i
=0;i
<heightout
;i
++) {
288 for (j
=0;j
<widthout
;j
++) {
291 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
292 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
294 for (k
=0;k
<components
;k
++) {
300 if (sx
<1.0 && sy
<1.0) {
301 /* magnify both width and height: use weighted sample of 4 pixels */
302 GLint i0
, i1
, j0
, j1
;
304 GLfloat
*src00
, *src01
, *src10
, *src11
;
308 for (i
=0;i
<heightout
;i
++) {
311 if (i1
>= heightin
) i1
= heightin
-1;
312 /* i1 = (i+1) * sy - EPSILON;*/
314 for (j
=0;j
<widthout
;j
++) {
317 if (j1
>= widthin
) j1
= widthin
-1;
318 /* j1 = (j+1) * sx - EPSILON; */
321 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
322 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
323 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
324 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
325 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
327 dst
= tempout
+ (i
* widthout
+ j
) * components
;
329 for (k
=0;k
<components
;k
++) {
330 s1
= *src00
++ * (1.0-beta
) + *src01
++ * beta
;
331 s2
= *src10
++ * (1.0-beta
) + *src11
++ * beta
;
332 *dst
++ = s1
* (1.0-alpha
) + s2
* alpha
;
338 /* shrink width and/or height: use an unweighted box filter */
344 for (i
=0;i
<heightout
;i
++) {
347 if (i1
>= heightin
) i1
= heightin
-1;
348 /* i1 = (i+1) * sy - EPSILON; */
349 for (j
=0;j
<widthout
;j
++) {
352 if (j1
>= widthin
) j1
= widthin
-1;
353 /* j1 = (j+1) * sx - EPSILON; */
355 dst
= tempout
+ (i
* widthout
+ j
) * components
;
357 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
358 for (k
=0;k
<components
;k
++) {
360 for (ii
=i0
;ii
<=i1
;ii
++) {
361 for (jj
=j0
;jj
<=j1
;jj
++) {
362 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
365 sum
/= (j1
-j0
+1) * (i1
-i0
+1);
375 * Return output image
378 if (packrowlength
>0) {
379 rowlen
= packrowlength
;
384 if (sizeout
>= packalignment
) {
385 rowstride
= components
* rowlen
;
388 rowstride
= packalignment
/sizeout
389 * CEILING( components
* rowlen
* sizeout
, packalignment
);
393 case GL_UNSIGNED_BYTE
:
395 for (i
=0;i
<heightout
;i
++) {
396 GLubyte
*ubptr
= (GLubyte
*) dataout
398 + packskiprows
* rowstride
399 + packskippixels
* components
;
400 for (j
=0;j
<widthout
*components
;j
++) {
402 *ubptr
++ = (GLubyte
) tempout
[k
++];
408 for (i
=0;i
<heightout
;i
++) {
409 GLbyte
*bptr
= (GLbyte
*) dataout
411 + packskiprows
* rowstride
412 + packskippixels
* components
;
413 for (j
=0;j
<widthout
*components
;j
++) {
415 *bptr
++ = (GLbyte
) tempout
[k
++];
419 case GL_UNSIGNED_SHORT
:
421 for (i
=0;i
<heightout
;i
++) {
422 GLushort
*usptr
= (GLushort
*) dataout
424 + packskiprows
* rowstride
425 + packskippixels
* components
;
426 for (j
=0;j
<widthout
*components
;j
++) {
428 *usptr
++ = (GLushort
) tempout
[k
++];
434 for (i
=0;i
<heightout
;i
++) {
435 GLshort
*sptr
= (GLshort
*) dataout
437 + packskiprows
* rowstride
438 + packskippixels
* components
;
439 for (j
=0;j
<widthout
*components
;j
++) {
441 *sptr
++ = (GLshort
) tempout
[k
++];
445 case GL_UNSIGNED_INT
:
447 for (i
=0;i
<heightout
;i
++) {
448 GLuint
*uiptr
= (GLuint
*) dataout
450 + packskiprows
* rowstride
451 + packskippixels
* components
;
452 for (j
=0;j
<widthout
*components
;j
++) {
454 *uiptr
++ = (GLuint
) tempout
[k
++];
460 for (i
=0;i
<heightout
;i
++) {
461 GLint
*iptr
= (GLint
*) dataout
463 + packskiprows
* rowstride
464 + packskippixels
* components
;
465 for (j
=0;j
<widthout
*components
;j
++) {
467 *iptr
++ = (GLint
) tempout
[k
++];
473 for (i
=0;i
<heightout
;i
++) {
474 GLfloat
*fptr
= (GLfloat
*) dataout
476 + packskiprows
* rowstride
477 + packskippixels
* components
;
478 for (j
=0;j
<widthout
*components
;j
++) {
480 *fptr
++ = tempout
[k
++];
485 return GLU_INVALID_ENUM
;
489 /* free temporary image storage */
499 * Return the largest k such that 2^k <= n.
501 static GLint
ilog2( GLint n
)
506 for (k
=0; n
>>=1; k
++) ;
513 * Find the value nearest to n which is also a power of two.
515 static GLint
round2( GLint n
)
533 * Given an pixel format and datatype, return the number of bytes to
536 static GLint
bytes_per_pixel( GLenum format
, GLenum type
)
542 case GL_STENCIL_INDEX
:
543 case GL_DEPTH_COMPONENT
:
551 case GL_LUMINANCE_ALPHA
:
569 case GL_UNSIGNED_BYTE
: m
= sizeof(GLubyte
); break;
570 case GL_BYTE
: m
= sizeof(GLbyte
); break;
571 case GL_BITMAP
: m
= 1; break;
572 case GL_UNSIGNED_SHORT
: m
= sizeof(GLushort
); break;
573 case GL_SHORT
: m
= sizeof(GLshort
); break;
574 case GL_UNSIGNED_INT
: m
= sizeof(GLuint
); break;
575 case GL_INT
: m
= sizeof(GLint
); break;
576 case GL_FLOAT
: m
= sizeof(GLfloat
); break;
586 * WARNING: This function isn't finished and has never been tested!!!!
588 GLint GLAPIENTRY
gluBuild1DMipmaps( GLenum target
, GLint components
,
589 GLsizei width
, GLenum format
,
590 GLenum type
, const void *data
)
593 GLint levels
, max_levels
;
594 GLint new_width
, max_width
;
598 return GLU_INVALID_VALUE
;
600 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &max_width
);
601 max_levels
= ilog2( max_width
) + 1;
603 /* Compute how many mipmap images to make */
604 levels
= ilog2( width
) + 1;
605 if (levels
>max_levels
) {
609 new_width
= 1 << (levels
-1);
611 texture
= (GLubyte
*) malloc( new_width
* components
);
613 return GLU_OUT_OF_MEMORY
;
616 if (width
!= new_width
) {
617 /* initial rescaling */
619 case GL_UNSIGNED_BYTE
:
621 GLubyte
*ub_data
= (GLubyte
*) data
;
622 for (i
=0;i
<new_width
;i
++) {
623 j
= i
* width
/ new_width
;
624 for (k
=0;k
<components
;k
++) {
625 texture
[i
*components
+k
] = ub_data
[j
*components
+k
];
631 /* Not implemented */
636 /* generate and load mipmap images */
637 for (l
=0;l
<levels
;l
++) {
638 glTexImage1D( GL_TEXTURE_1D
, l
, components
, new_width
, 0,
639 format
, GL_UNSIGNED_BYTE
, texture
);
641 /* Scale image down to 1/2 size */
642 new_width
= new_width
/ 2;
643 for (i
=0;i
<new_width
;i
++) {
644 for (k
=0;k
<components
;k
++) {
645 GLint sample1
, sample2
;
646 sample1
= (GLint
) texture
[i
*2*components
+k
];
647 sample2
= (GLint
) texture
[(i
*2+1)*components
+k
];
648 texture
[i
*components
+k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
660 GLint GLAPIENTRY
gluBuild2DMipmaps( GLenum target
, GLint components
,
661 GLsizei width
, GLsizei height
, GLenum format
,
662 GLenum type
, const void *data
)
665 void *image
, *newimage
;
666 GLint neww
, newh
, level
, bpp
;
670 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
671 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
673 if (width
< 1 || height
< 1)
674 return GLU_INVALID_VALUE
;
676 glGetIntegerv( GL_MAX_TEXTURE_SIZE
, &maxsize
);
682 h
= round2( height
);
687 bpp
= bytes_per_pixel( format
, type
);
689 /* probably a bad format or type enum */
690 return GLU_INVALID_ENUM
;
693 /* Get current glPixelStore values */
694 glGetIntegerv( GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
695 glGetIntegerv( GL_UNPACK_ALIGNMENT
, &unpackalignment
);
696 glGetIntegerv( GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
697 glGetIntegerv( GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
698 glGetIntegerv( GL_PACK_ROW_LENGTH
, &packrowlength
);
699 glGetIntegerv( GL_PACK_ALIGNMENT
, &packalignment
);
700 glGetIntegerv( GL_PACK_SKIP_ROWS
, &packskiprows
);
701 glGetIntegerv( GL_PACK_SKIP_PIXELS
, &packskippixels
);
703 /* set pixel packing */
704 glPixelStorei( GL_PACK_ROW_LENGTH
, 0 );
705 glPixelStorei( GL_PACK_ALIGNMENT
, 1 );
706 glPixelStorei( GL_PACK_SKIP_ROWS
, 0 );
707 glPixelStorei( GL_PACK_SKIP_PIXELS
, 0 );
711 if (w
!=width
|| h
!=height
) {
712 /* must rescale image to get "top" mipmap texture image */
713 image
= malloc( (w
+4) * h
* bpp
);
715 return GLU_OUT_OF_MEMORY
;
717 error
= gluScaleImage( format
, width
, height
, type
, data
,
725 image
= (void *) data
;
731 /* set pixel unpacking */
732 glPixelStorei( GL_UNPACK_ROW_LENGTH
, 0 );
733 glPixelStorei( GL_UNPACK_ALIGNMENT
, 1 );
734 glPixelStorei( GL_UNPACK_SKIP_ROWS
, 0 );
735 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, 0 );
738 glTexImage2D( target
, level
, components
, w
, h
, 0, format
, type
, image
);
740 if (w
==1 && h
==1) break;
742 neww
= (w
<2) ? 1 : w
/2;
743 newh
= (h
<2) ? 1 : h
/2;
744 newimage
= malloc( (neww
+4) * newh
* bpp
);
746 return GLU_OUT_OF_MEMORY
;
749 error
= gluScaleImage( format
, w
, h
, type
, image
,
750 neww
, newh
, type
, newimage
);
770 /* Restore original glPixelStore state */
771 glPixelStorei( GL_UNPACK_ROW_LENGTH
, unpackrowlength
);
772 glPixelStorei( GL_UNPACK_ALIGNMENT
, unpackalignment
);
773 glPixelStorei( GL_UNPACK_SKIP_ROWS
, unpackskiprows
);
774 glPixelStorei( GL_UNPACK_SKIP_PIXELS
, unpackskippixels
);
775 glPixelStorei( GL_PACK_ROW_LENGTH
, packrowlength
);
776 glPixelStorei( GL_PACK_ALIGNMENT
, packalignment
);
777 glPixelStorei( GL_PACK_SKIP_ROWS
, packskiprows
);
778 glPixelStorei( GL_PACK_SKIP_PIXELS
, packskippixels
);