3 * Mesa 3-D graphics library
5 * Copyright (C) 1995-2000 Brian Paul
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 * Compute ceiling of integer quotient of A divided by B:
37 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
47 /* To work around optimizer bug in MSVC4.1 */
48 #if defined(__WIN32__) && !defined(OPENSTEP)
50 dummy(GLuint j
, GLuint k
)
59 gluScaleImage(GLenum format
,
60 GLsizei widthin
, GLsizei heightin
,
61 GLenum typein
, const void *datain
,
62 GLsizei widthout
, GLsizei heightout
,
63 GLenum typeout
, void *dataout
)
65 GLint components
, i
, j
, k
;
66 GLfloat
*tempin
, *tempout
;
68 GLint unpackrowlength
, unpackalignment
, unpackskiprows
, unpackskippixels
;
69 GLint packrowlength
, packalignment
, packskiprows
, packskippixels
;
70 GLint sizein
, sizeout
;
71 GLint rowstride
, rowlen
;
74 /* Determine number of components per pixel */
77 case GL_STENCIL_INDEX
:
78 case GL_DEPTH_COMPONENT
:
86 case GL_LUMINANCE_ALPHA
:
101 return GLU_INVALID_ENUM
;
104 /* Determine bytes per input datum */
106 case GL_UNSIGNED_BYTE
:
107 sizein
= sizeof(GLubyte
);
110 sizein
= sizeof(GLbyte
);
112 case GL_UNSIGNED_SHORT
:
113 sizein
= sizeof(GLushort
);
116 sizein
= sizeof(GLshort
);
118 case GL_UNSIGNED_INT
:
119 sizein
= sizeof(GLuint
);
122 sizein
= sizeof(GLint
);
125 sizein
= sizeof(GLfloat
);
128 /* not implemented yet */
130 return GL_INVALID_ENUM
;
133 /* Determine bytes per output datum */
135 case GL_UNSIGNED_BYTE
:
136 sizeout
= sizeof(GLubyte
);
139 sizeout
= sizeof(GLbyte
);
141 case GL_UNSIGNED_SHORT
:
142 sizeout
= sizeof(GLushort
);
145 sizeout
= sizeof(GLshort
);
147 case GL_UNSIGNED_INT
:
148 sizeout
= sizeof(GLuint
);
151 sizeout
= sizeof(GLint
);
154 sizeout
= sizeof(GLfloat
);
157 /* not implemented yet */
159 return GL_INVALID_ENUM
;
162 /* Get glPixelStore state */
163 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &unpackrowlength
);
164 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpackalignment
);
165 glGetIntegerv(GL_UNPACK_SKIP_ROWS
, &unpackskiprows
);
166 glGetIntegerv(GL_UNPACK_SKIP_PIXELS
, &unpackskippixels
);
167 glGetIntegerv(GL_PACK_ROW_LENGTH
, &packrowlength
);
168 glGetIntegerv(GL_PACK_ALIGNMENT
, &packalignment
);
169 glGetIntegerv(GL_PACK_SKIP_ROWS
, &packskiprows
);
170 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &packskippixels
);
172 /* Allocate storage for intermediate images */
173 tempin
= (GLfloat
*) malloc(widthin
* heightin
174 * components
* sizeof(GLfloat
));
176 return GLU_OUT_OF_MEMORY
;
178 tempout
= (GLfloat
*) malloc(widthout
* heightout
179 * components
* sizeof(GLfloat
));
182 return GLU_OUT_OF_MEMORY
;
187 * Unpack the pixel data and convert to floating point
190 if (unpackrowlength
> 0) {
191 rowlen
= unpackrowlength
;
196 if (sizein
>= unpackalignment
) {
197 rowstride
= components
* rowlen
;
200 rowstride
= unpackalignment
/ sizein
201 * CEILING(components
* rowlen
* sizein
, unpackalignment
);
205 case GL_UNSIGNED_BYTE
:
207 for (i
= 0; i
< heightin
; i
++) {
208 GLubyte
*ubptr
= (GLubyte
*) datain
210 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
211 for (j
= 0; j
< widthin
* components
; j
++) {
213 tempin
[k
++] = (GLfloat
) * ubptr
++;
219 for (i
= 0; i
< heightin
; i
++) {
220 GLbyte
*bptr
= (GLbyte
*) datain
222 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
223 for (j
= 0; j
< widthin
* components
; j
++) {
225 tempin
[k
++] = (GLfloat
) * bptr
++;
229 case GL_UNSIGNED_SHORT
:
231 for (i
= 0; i
< heightin
; i
++) {
232 GLushort
*usptr
= (GLushort
*) datain
234 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
235 for (j
= 0; j
< widthin
* components
; j
++) {
237 tempin
[k
++] = (GLfloat
) * usptr
++;
243 for (i
= 0; i
< heightin
; i
++) {
244 GLshort
*sptr
= (GLshort
*) datain
246 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
247 for (j
= 0; j
< widthin
* components
; j
++) {
249 tempin
[k
++] = (GLfloat
) * sptr
++;
253 case GL_UNSIGNED_INT
:
255 for (i
= 0; i
< heightin
; i
++) {
256 GLuint
*uiptr
= (GLuint
*) datain
258 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
259 for (j
= 0; j
< widthin
* components
; j
++) {
261 tempin
[k
++] = (GLfloat
) * uiptr
++;
267 for (i
= 0; i
< heightin
; i
++) {
268 GLint
*iptr
= (GLint
*) datain
270 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
271 for (j
= 0; j
< widthin
* components
; j
++) {
273 tempin
[k
++] = (GLfloat
) * iptr
++;
279 for (i
= 0; i
< heightin
; i
++) {
280 GLfloat
*fptr
= (GLfloat
*) datain
282 + unpackskiprows
* rowstride
+ unpackskippixels
* components
;
283 for (j
= 0; j
< widthin
* components
; j
++) {
285 tempin
[k
++] = *fptr
++;
290 return GLU_INVALID_ENUM
;
299 sx
= (GLfloat
) (widthin
- 1) / (GLfloat
) (widthout
- 1);
301 sx
= (GLfloat
) (widthin
- 1);
303 sy
= (GLfloat
) (heightin
- 1) / (GLfloat
) (heightout
- 1);
305 sy
= (GLfloat
) (heightin
- 1);
307 /*#define POINT_SAMPLE*/
309 for (i
= 0; i
< heightout
; i
++) {
311 for (j
= 0; j
< widthout
; j
++) {
314 GLfloat
*src
= tempin
+ (ii
* widthin
+ jj
) * components
;
315 GLfloat
*dst
= tempout
+ (i
* widthout
+ j
) * components
;
317 for (k
= 0; k
< components
; k
++) {
323 if (sx
< 1.0 && sy
< 1.0) {
324 /* magnify both width and height: use weighted sample of 4 pixels */
325 GLint i0
, i1
, j0
, j1
;
327 GLfloat
*src00
, *src01
, *src10
, *src11
;
331 for (i
= 0; i
< heightout
; i
++) {
336 /* i1 = (i+1) * sy - EPSILON;*/
338 for (j
= 0; j
< widthout
; j
++) {
343 /* j1 = (j+1) * sx - EPSILON; */
346 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
347 src00
= tempin
+ (i0
* widthin
+ j0
) * components
;
348 src01
= tempin
+ (i0
* widthin
+ j1
) * components
;
349 src10
= tempin
+ (i1
* widthin
+ j0
) * components
;
350 src11
= tempin
+ (i1
* widthin
+ j1
) * components
;
352 dst
= tempout
+ (i
* widthout
+ j
) * components
;
354 for (k
= 0; k
< components
; k
++) {
355 s1
= *src00
++ * (1.0 - beta
) + *src01
++ * beta
;
356 s2
= *src10
++ * (1.0 - beta
) + *src11
++ * beta
;
357 *dst
++ = s1
* (1.0 - alpha
) + s2
* alpha
;
363 /* shrink width and/or height: use an unweighted box filter */
369 for (i
= 0; i
< heightout
; i
++) {
374 /* i1 = (i+1) * sy - EPSILON; */
375 for (j
= 0; j
< widthout
; j
++) {
380 /* j1 = (j+1) * sx - EPSILON; */
382 dst
= tempout
+ (i
* widthout
+ j
) * components
;
384 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
385 for (k
= 0; k
< components
; k
++) {
387 for (ii
= i0
; ii
<= i1
; ii
++) {
388 for (jj
= j0
; jj
<= j1
; jj
++) {
389 sum
+= *(tempin
+ (ii
* widthin
+ jj
) * components
+ k
);
392 sum
/= (j1
- j0
+ 1) * (i1
- i0
+ 1);
402 * Return output image
405 if (packrowlength
> 0) {
406 rowlen
= packrowlength
;
411 if (sizeout
>= packalignment
) {
412 rowstride
= components
* rowlen
;
415 rowstride
= packalignment
/ sizeout
416 * CEILING(components
* rowlen
* sizeout
, packalignment
);
420 case GL_UNSIGNED_BYTE
:
422 for (i
= 0; i
< heightout
; i
++) {
423 GLubyte
*ubptr
= (GLubyte
*) dataout
425 + packskiprows
* rowstride
+ packskippixels
* components
;
426 for (j
= 0; j
< widthout
* components
; j
++) {
428 *ubptr
++ = (GLubyte
) tempout
[k
++];
434 for (i
= 0; i
< heightout
; i
++) {
435 GLbyte
*bptr
= (GLbyte
*) dataout
437 + packskiprows
* rowstride
+ packskippixels
* components
;
438 for (j
= 0; j
< widthout
* components
; j
++) {
440 *bptr
++ = (GLbyte
) tempout
[k
++];
444 case GL_UNSIGNED_SHORT
:
446 for (i
= 0; i
< heightout
; i
++) {
447 GLushort
*usptr
= (GLushort
*) dataout
449 + packskiprows
* rowstride
+ packskippixels
* components
;
450 for (j
= 0; j
< widthout
* components
; j
++) {
452 *usptr
++ = (GLushort
) tempout
[k
++];
458 for (i
= 0; i
< heightout
; i
++) {
459 GLshort
*sptr
= (GLshort
*) dataout
461 + packskiprows
* rowstride
+ packskippixels
* components
;
462 for (j
= 0; j
< widthout
* components
; j
++) {
464 *sptr
++ = (GLshort
) tempout
[k
++];
468 case GL_UNSIGNED_INT
:
470 for (i
= 0; i
< heightout
; i
++) {
471 GLuint
*uiptr
= (GLuint
*) dataout
473 + packskiprows
* rowstride
+ packskippixels
* components
;
474 for (j
= 0; j
< widthout
* components
; j
++) {
476 *uiptr
++ = (GLuint
) tempout
[k
++];
482 for (i
= 0; i
< heightout
; i
++) {
483 GLint
*iptr
= (GLint
*) dataout
485 + packskiprows
* rowstride
+ packskippixels
* components
;
486 for (j
= 0; j
< widthout
* components
; j
++) {
488 *iptr
++ = (GLint
) tempout
[k
++];
494 for (i
= 0; i
< heightout
; i
++) {
495 GLfloat
*fptr
= (GLfloat
*) dataout
497 + packskiprows
* rowstride
+ packskippixels
* components
;
498 for (j
= 0; j
< widthout
* components
; j
++) {
500 *fptr
++ = tempout
[k
++];
505 return GLU_INVALID_ENUM
;
509 /* free temporary image storage */
519 * Return the largest k such that 2^k <= n.
528 for (k
= 0; n
>>= 1; k
++);
535 * Find the value nearest to n which is also a power of two.
542 for (m
= 1; m
< n
; m
*= 2);
545 if (m
- n
<= n
- m
/ 2) {
555 * Given an pixel format and datatype, return the number of bytes to
559 bytes_per_pixel(GLenum format
, GLenum type
)
565 case GL_STENCIL_INDEX
:
566 case GL_DEPTH_COMPONENT
:
574 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
);