1 /* $Id: mipmap.c,v 1.2 2003/08/22 20:11:43 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)
51 dummy(GLuint j
, GLuint k
)
60 gluScaleImage(GLenum format
,
61 GLsizei widthin
, GLsizei heightin
,
62 GLenum typein
, const void *datain
,
63 GLsizei widthout
, GLsizei heightout
,
64 GLenum typeout
, void *dataout
)
66 GLint components
, i
, j
, k
;
67 GLfloat
*tempin
, *tempout
, f
;
69 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
70 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
71 GLint sizein
, sizeout
;
72 GLint rowstride
, rowlen
;
75 /* Determine number of components per pixel */
78 case GL_STENCIL_INDEX
:
79 case GL_DEPTH_COMPONENT
:
87 case GL_LUMINANCE_ALPHA
:
102 return GLU_INVALID_ENUM
;
105 /* Determine bytes per input datum */
107 case GL_UNSIGNED_BYTE
:
108 sizein
= sizeof(GLubyte
);
111 sizein
= sizeof(GLbyte
);
113 case GL_UNSIGNED_SHORT
:
114 sizein
= sizeof(GLushort
);
117 sizein
= sizeof(GLshort
);
119 case GL_UNSIGNED_INT
:
120 sizein
= sizeof(GLuint
);
123 sizein
= sizeof(GLint
);
126 sizein
= sizeof(GLfloat
);
129 /* not implemented yet */
131 return GL_INVALID_ENUM
;
134 /* Determine bytes per output datum */
136 case GL_UNSIGNED_BYTE
:
137 sizeout
= sizeof(GLubyte
);
140 sizeout
= sizeof(GLbyte
);
142 case GL_UNSIGNED_SHORT
:
143 sizeout
= sizeof(GLushort
);
146 sizeout
= sizeof(GLshort
);
148 case GL_UNSIGNED_INT
:
149 sizeout
= sizeof(GLuint
);
152 sizeout
= sizeof(GLint
);
155 sizeout
= sizeof(GLfloat
);
158 /* not implemented yet */
160 return GL_INVALID_ENUM
;
163 /* Get glPixelStore state */
164 glGetFloatv(GL_UNPACK_ROW_LENGTH
, &f
); unpackrowlength
= (int)f
;
165 glGetFloatv(GL_UNPACK_ALIGNMENT
, &f
); unpackalignment
= (int)f
;
166 glGetFloatv(GL_UNPACK_SKIP_ROWS
, &f
); unpackskiprows
= (int)f
;
167 glGetFloatv(GL_UNPACK_SKIP_PIXELS
, &f
); unpackskippixels
= (int)f
;
168 glGetFloatv(GL_PACK_ROW_LENGTH
, &f
); packrowlength
= (int)f
;
169 glGetFloatv(GL_PACK_ALIGNMENT
, &f
); packalignment
= (int)f
;
170 glGetFloatv(GL_PACK_SKIP_ROWS
, &f
); packskiprows
= (int)f
;
171 glGetFloatv(GL_PACK_SKIP_PIXELS
, &f
); packskippixels
= (int)f
;
173 /* Allocate storage for intermediate images */
174 tempin
= (GLfloat
*) malloc(widthin
* heightin
175 * components
* sizeof(GLfloat
));
177 return GLU_OUT_OF_MEMORY
;
179 tempout
= (GLfloat
*) malloc(widthout
* heightout
180 * components
* sizeof(GLfloat
));
183 return GLU_OUT_OF_MEMORY
;
188 * Unpack the pixel data and convert to floating point
191 if (unpackrowlength
> 0) {
192 rowlen
= unpackrowlength
;
197 if (sizein
>= unpackalignment
) {
198 rowstride
= components
* rowlen
;
201 rowstride
= unpackalignment
/ sizein
202 * CEILING(components
* rowlen
* sizein
, unpackalignment
);
206 case GL_UNSIGNED_BYTE
:
208 for (i
= 0; i
< heightin
; i
++) {
209 GLubyte
*ubptr
= (GLubyte
*) datain
211 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
212 for (j
= 0; j
< widthin
* components
; j
++) {
214 tempin
[k
++] = (GLfloat
) * ubptr
++;
220 for (i
= 0; i
< heightin
; i
++) {
221 GLbyte
*bptr
= (GLbyte
*) datain
223 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
224 for (j
= 0; j
< widthin
* components
; j
++) {
226 tempin
[k
++] = (GLfloat
) * bptr
++;
230 case GL_UNSIGNED_SHORT
:
232 for (i
= 0; i
< heightin
; i
++) {
233 GLushort
*usptr
= (GLushort
*) datain
235 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
236 for (j
= 0; j
< widthin
* components
; j
++) {
238 tempin
[k
++] = (GLfloat
) * usptr
++;
244 for (i
= 0; i
< heightin
; i
++) {
245 GLshort
*sptr
= (GLshort
*) datain
247 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
248 for (j
= 0; j
< widthin
* components
; j
++) {
250 tempin
[k
++] = (GLfloat
) * sptr
++;
254 case GL_UNSIGNED_INT
:
256 for (i
= 0; i
< heightin
; i
++) {
257 GLuint
*uiptr
= (GLuint
*) datain
259 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
260 for (j
= 0; j
< widthin
* components
; j
++) {
262 tempin
[k
++] = (GLfloat
) * uiptr
++;
268 for (i
= 0; i
< heightin
; i
++) {
269 GLint
*iptr
= (GLint
*) datain
271 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
272 for (j
= 0; j
< widthin
* components
; j
++) {
274 tempin
[k
++] = (GLfloat
) * iptr
++;
280 for (i
= 0; i
< heightin
; i
++) {
281 GLfloat
*fptr
= (GLfloat
*) datain
283 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
284 for (j
= 0; j
< widthin
* components
; j
++) {
286 tempin
[k
++] = *fptr
++;
291 return GLU_INVALID_ENUM
;
300 sx
= (GLfloat
) (widthin
- 1) / (GLfloat
) (widthout
- 1);
302 sx
= (GLfloat
) (widthin
- 1);
304 sy
= (GLfloat
) (heightin
- 1) / (GLfloat
) (heightout
- 1);
306 sy
= (GLfloat
) (heightin
- 1);
308 /*#define POINT_SAMPLE*/
310 for (i
= 0; i
< heightout
; i
++) {
312 for (j
= 0; j
< widthout
; j
++) {
315 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
316 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
318 for (k
= 0; k
< components
; k
++) {
324 if (sx
< 1.0 && sy
< 1.0) {
325 /* magnify both width and height: use weighted sample of 4 pixels */
326 GLint i0
, i1
, j0
, j1
;
328 GLfloat
*src00
, *src01
, *src10
, *src11
;
332 for (i
= 0; i
< heightout
; i
++) {
337 /* i1 = (i+1) * sy - EPSILON;*/
339 for (j
= 0; j
< widthout
; j
++) {
344 /* j1 = (j+1) * sx - EPSILON; */
347 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
348 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
349 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
350 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
351 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
353 dst
= tempout
+ (i
* widthout
+ j
) * components
;
355 for (k
= 0; k
< components
; k
++) {
356 s1
= *src00
++ * (1.0 - beta
) + *src01
++ * beta
;
357 s2
= *src10
++ * (1.0 - beta
) + *src11
++ * beta
;
358 *dst
++ = s1
* (1.0 - alpha
) + s2
* alpha
;
364 /* shrink width and/or height: use an unweighted box filter */
370 for (i
= 0; i
< heightout
; i
++) {
375 /* i1 = (i+1) * sy - EPSILON; */
376 for (j
= 0; j
< widthout
; j
++) {
381 /* j1 = (j+1) * sx - EPSILON; */
383 dst
= tempout
+ (i
* widthout
+ j
) * components
;
385 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
386 for (k
= 0; k
< components
; k
++) {
388 for (ii
= i0
; ii
<= i1
; ii
++) {
389 for (jj
= j0
; jj
<= j1
; jj
++) {
390 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
393 sum
/= (j1
- j0
+ 1) * (i1
- i0
+ 1);
403 * Return output image
406 if (packrowlength
> 0) {
407 rowlen
= packrowlength
;
412 if (sizeout
>= packalignment
) {
413 rowstride
= components
* rowlen
;
416 rowstride
= packalignment
/ sizeout
417 * CEILING(components
* rowlen
* sizeout
, packalignment
);
421 case GL_UNSIGNED_BYTE
:
423 for (i
= 0; i
< heightout
; i
++) {
424 GLubyte
*ubptr
= (GLubyte
*) dataout
426 + packskiprows
* rowstride
+ packskippixels
* components
;
427 for (j
= 0; j
< widthout
* components
; j
++) {
429 *ubptr
++ = (GLubyte
) tempout
[k
++];
435 for (i
= 0; i
< heightout
; i
++) {
436 GLbyte
*bptr
= (GLbyte
*) dataout
438 + packskiprows
* rowstride
+ packskippixels
* components
;
439 for (j
= 0; j
< widthout
* components
; j
++) {
441 *bptr
++ = (GLbyte
) tempout
[k
++];
445 case GL_UNSIGNED_SHORT
:
447 for (i
= 0; i
< heightout
; i
++) {
448 GLushort
*usptr
= (GLushort
*) dataout
450 + packskiprows
* rowstride
+ packskippixels
* components
;
451 for (j
= 0; j
< widthout
* components
; j
++) {
453 *usptr
++ = (GLushort
) tempout
[k
++];
459 for (i
= 0; i
< heightout
; i
++) {
460 GLshort
*sptr
= (GLshort
*) dataout
462 + packskiprows
* rowstride
+ packskippixels
* components
;
463 for (j
= 0; j
< widthout
* components
; j
++) {
465 *sptr
++ = (GLshort
) tempout
[k
++];
469 case GL_UNSIGNED_INT
:
471 for (i
= 0; i
< heightout
; i
++) {
472 GLuint
*uiptr
= (GLuint
*) dataout
474 + packskiprows
* rowstride
+ packskippixels
* components
;
475 for (j
= 0; j
< widthout
* components
; j
++) {
477 *uiptr
++ = (GLuint
) tempout
[k
++];
483 for (i
= 0; i
< heightout
; i
++) {
484 GLint
*iptr
= (GLint
*) dataout
486 + packskiprows
* rowstride
+ packskippixels
* components
;
487 for (j
= 0; j
< widthout
* components
; j
++) {
489 *iptr
++ = (GLint
) tempout
[k
++];
495 for (i
= 0; i
< heightout
; i
++) {
496 GLfloat
*fptr
= (GLfloat
*) dataout
498 + packskiprows
* rowstride
+ packskippixels
* components
;
499 for (j
= 0; j
< widthout
* components
; j
++) {
501 *fptr
++ = tempout
[k
++];
506 return GLU_INVALID_ENUM
;
510 /* free temporary image storage */
520 * Return the largest k such that 2^k <= n.
529 for (k
= 0; n
>>= 1; k
++);
536 * Find the value nearest to n which is also a power of two.
543 for (m
= 1; m
< n
; m
*= 2);
546 if (m
- n
<= n
- m
/ 2) {
556 * Given an pixel format and data type, return the number of bytes to
560 bytes_per_pixel(GLenum format
, GLenum type
)
566 case GL_STENCIL_INDEX
:
567 case GL_DEPTH_COMPONENT
:
575 case GL_LUMINANCE_ALPHA
:
594 case GL_UNSIGNED_BYTE
:
603 case GL_UNSIGNED_SHORT
:
604 m
= sizeof(GLushort
);
609 case GL_UNSIGNED_INT
:
628 * WARNING: This function isn't finished and has never been tested!!!!
631 gluBuild1DMipmaps(GLenum target
, GLint components
,
632 GLsizei width
, GLenum format
, GLenum type
, const void *data
)
640 gluBuild2DMipmaps(GLenum target
, GLint components
,
641 GLsizei width
, GLsizei height
, GLenum format
,
642 GLenum type
, const void *data
)
646 void *image
, *newimage
;
647 GLint neww
, newh
, level
, bpp
;
651 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
652 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
655 if (width
< 1 || height
< 1)
656 return GLU_INVALID_VALUE
;
658 glGetFloatv(GL_MAX_TEXTURE_SIZE
, &f
); maxsize
= (int)f
;
669 bpp
= bytes_per_pixel(format
, type
);
671 /* probably a bad format or type enum */
672 return GLU_INVALID_ENUM
;
675 /* Get current glPixelStore values */
676 glGetFloatv(GL_UNPACK_ROW_LENGTH
, &f
); unpackrowlength
= (int)f
;
677 glGetFloatv(GL_UNPACK_ALIGNMENT
, &f
); unpackalignment
= (int)f
;
678 glGetFloatv(GL_UNPACK_SKIP_ROWS
, &f
); unpackskiprows
= (int)f
;
679 glGetFloatv(GL_UNPACK_SKIP_PIXELS
, &f
); unpackskippixels
= (int)f
;
680 glGetFloatv(GL_PACK_ROW_LENGTH
, &f
); packrowlength
= (int)f
;
681 glGetFloatv(GL_PACK_ALIGNMENT
, &f
); packalignment
= (int)f
;
682 glGetFloatv(GL_PACK_SKIP_ROWS
, &f
); packskiprows
= (int)f
;
683 glGetFloatv(GL_PACK_SKIP_PIXELS
, &f
); packskippixels
= (int)f
;
685 /* set pixel packing */
686 glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
687 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
688 glPixelStorei(GL_PACK_SKIP_ROWS
, 0);
689 glPixelStorei(GL_PACK_SKIP_PIXELS
, 0);
693 if (w
!= width
|| h
!= height
) {
694 /* must rescale image to get "top" mipmap texture image */
695 image
= malloc((w
+ 4) * h
* bpp
);
697 return GLU_OUT_OF_MEMORY
;
699 error
= gluScaleImage(format
, width
, height
, type
, data
,
707 image
= (void *) data
;
713 /* set pixel unpacking */
714 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
715 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
716 glPixelStorei(GL_UNPACK_SKIP_ROWS
, 0);
717 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, 0);
720 glTexImage2D(target
, level
, components
, w
, h
, 0, format
, type
, image
);
722 if (w
== 1 && h
== 1)
725 neww
= (w
< 2) ? 1 : w
/ 2;
726 newh
= (h
< 2) ? 1 : h
/ 2;
727 newimage
= malloc((neww
+ 4) * newh
* bpp
);
729 return GLU_OUT_OF_MEMORY
;
732 error
= gluScaleImage(format
, w
, h
, type
, image
,
733 neww
, newh
, type
, newimage
);
753 /* Restore original glPixelStore state */
754 glPixelStorei(GL_UNPACK_ROW_LENGTH
, unpackrowlength
);
755 glPixelStorei(GL_UNPACK_ALIGNMENT
, unpackalignment
);
756 glPixelStorei(GL_UNPACK_SKIP_ROWS
, unpackskiprows
);
757 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, unpackskippixels
);
758 glPixelStorei(GL_PACK_ROW_LENGTH
, packrowlength
);
759 glPixelStorei(GL_PACK_ALIGNMENT
, packalignment
);
760 glPixelStorei(GL_PACK_SKIP_ROWS
, packskiprows
);
761 glPixelStorei(GL_PACK_SKIP_PIXELS
, packskippixels
);