1 /* $Id: mipmap.c,v 1.7 2000/07/11 14:11:04 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
;
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 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
165 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpackalignment
);
166 glGetIntegerv(GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
167 glGetIntegerv(GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
168 glGetIntegerv(GL_PACK_ROW_LENGTH
, &packrowlength
);
169 glGetIntegerv(GL_PACK_ALIGNMENT
, &packalignment
);
170 glGetIntegerv(GL_PACK_SKIP_ROWS
, &packskiprows
);
171 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &packskippixels
);
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 datatype, 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
:
593 case GL_UNSIGNED_BYTE
:
602 case GL_UNSIGNED_SHORT
:
603 m
= sizeof(GLushort
);
608 case GL_UNSIGNED_INT
:
627 * WARNING: This function isn't finished and has never been tested!!!!
630 gluBuild1DMipmaps(GLenum target
, GLint components
,
631 GLsizei width
, GLenum format
, GLenum type
, const void *data
)
634 GLint levels
, max_levels
;
635 GLint new_width
, max_width
;
639 return GLU_INVALID_VALUE
;
641 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &max_width
);
642 max_levels
= ilog2(max_width
) + 1;
644 /* Compute how many mipmap images to make */
645 levels
= ilog2(width
) + 1;
646 if (levels
> max_levels
) {
650 new_width
= 1 << (levels
- 1);
652 texture
= (GLubyte
*) malloc(new_width
* components
);
654 return GLU_OUT_OF_MEMORY
;
657 if (width
!= new_width
) {
658 /* initial rescaling */
660 case GL_UNSIGNED_BYTE
:
662 GLubyte
*ub_data
= (GLubyte
*) data
;
663 for (i
= 0; i
< new_width
; i
++) {
664 j
= i
* width
/ new_width
;
665 for (k
= 0; k
< components
; k
++) {
666 texture
[i
* components
+ k
] = ub_data
[j
* components
+ k
];
672 /* Not implemented */
677 /* generate and load mipmap images */
678 for (l
= 0; l
< levels
; l
++) {
679 glTexImage1D(GL_TEXTURE_1D
, l
, components
, new_width
, 0,
680 format
, GL_UNSIGNED_BYTE
, texture
);
682 /* Scale image down to 1/2 size */
683 new_width
= new_width
/ 2;
684 for (i
= 0; i
< new_width
; i
++) {
685 for (k
= 0; k
< components
; k
++) {
686 GLint sample1
, sample2
;
687 sample1
= (GLint
) texture
[i
* 2 * components
+ k
];
688 sample2
= (GLint
) texture
[(i
* 2 + 1) * components
+ k
];
689 texture
[i
* components
+ k
] = (GLubyte
) ((sample1
+ sample2
) / 2);
702 gluBuild2DMipmaps(GLenum target
, GLint components
,
703 GLsizei width
, GLsizei height
, GLenum format
,
704 GLenum type
, const void *data
)
707 void *image
, *newimage
;
708 GLint neww
, newh
, level
, bpp
;
712 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
713 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
715 if (width
< 1 || height
< 1)
716 return GLU_INVALID_VALUE
;
718 glGetIntegerv(GL_MAX_TEXTURE_SIZE
, &maxsize
);
729 bpp
= bytes_per_pixel(format
, type
);
731 /* probably a bad format or type enum */
732 return GLU_INVALID_ENUM
;
735 /* Get current glPixelStore values */
736 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
737 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpackalignment
);
738 glGetIntegerv(GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
739 glGetIntegerv(GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
740 glGetIntegerv(GL_PACK_ROW_LENGTH
, &packrowlength
);
741 glGetIntegerv(GL_PACK_ALIGNMENT
, &packalignment
);
742 glGetIntegerv(GL_PACK_SKIP_ROWS
, &packskiprows
);
743 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &packskippixels
);
745 /* set pixel packing */
746 glPixelStorei(GL_PACK_ROW_LENGTH
, 0);
747 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
748 glPixelStorei(GL_PACK_SKIP_ROWS
, 0);
749 glPixelStorei(GL_PACK_SKIP_PIXELS
, 0);
753 if (w
!= width
|| h
!= height
) {
754 /* must rescale image to get "top" mipmap texture image */
755 image
= malloc((w
+ 4) * h
* bpp
);
757 return GLU_OUT_OF_MEMORY
;
759 error
= gluScaleImage(format
, width
, height
, type
, data
,
767 image
= (void *) data
;
773 /* set pixel unpacking */
774 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
775 glPixelStorei(GL_UNPACK_ALIGNMENT
, 1);
776 glPixelStorei(GL_UNPACK_SKIP_ROWS
, 0);
777 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, 0);
780 glTexImage2D(target
, level
, components
, w
, h
, 0, format
, type
, image
);
782 if (w
== 1 && h
== 1)
785 neww
= (w
< 2) ? 1 : w
/ 2;
786 newh
= (h
< 2) ? 1 : h
/ 2;
787 newimage
= malloc((neww
+ 4) * newh
* bpp
);
789 return GLU_OUT_OF_MEMORY
;
792 error
= gluScaleImage(format
, w
, h
, type
, image
,
793 neww
, newh
, type
, newimage
);
813 /* Restore original glPixelStore state */
814 glPixelStorei(GL_UNPACK_ROW_LENGTH
, unpackrowlength
);
815 glPixelStorei(GL_UNPACK_ALIGNMENT
, unpackalignment
);
816 glPixelStorei(GL_UNPACK_SKIP_ROWS
, unpackskiprows
);
817 glPixelStorei(GL_UNPACK_SKIP_PIXELS
, unpackskippixels
);
818 glPixelStorei(GL_PACK_ROW_LENGTH
, packrowlength
);
819 glPixelStorei(GL_PACK_ALIGNMENT
, packalignment
);
820 glPixelStorei(GL_PACK_SKIP_ROWS
, packskiprows
);
821 glPixelStorei(GL_PACK_SKIP_PIXELS
, packskippixels
);