9f4ffcfea8989eaddcdaa95633e7fed5812596d1
[mesa.git] / src / glu / mesa / mipmap.c
1 /* $Id: mipmap.c,v 1.3 1999/11/09 06:16:59 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 * Copyright (C) 1995-1999 Brian Paul
7 *
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.
12 *
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.
17 *
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.
21 */
22
23
24 /*
25 * $Log: mipmap.c,v $
26 * Revision 1.3 1999/11/09 06:16:59 brianp
27 * replace GLint with GLsizei in a gluScaleImage, gluBuild1/2DMipmaps()
28 *
29 * Revision 1.2 1999/09/14 00:30:28 brianp
30 * fixed pixel packing/unpacking code in gluBuild2DMipmaps()
31 *
32 * Revision 1.1.1.1 1999/08/19 00:55:42 jtg
33 * Imported sources
34 *
35 * Revision 1.13 1999/03/05 17:49:06 brianp
36 * added support for GL_EXT_abgr (devernay@istar.fr)
37 *
38 * Revision 1.12 1999/01/03 03:23:15 brianp
39 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
40 *
41 * Revision 1.11 1998/09/18 02:44:03 brianp
42 * further changes to gluScaleImage() per Randy Frank
43 *
44 * Revision 1.10 1998/09/17 03:20:26 brianp
45 * fixed another bug in gluScaleImage() per Sven Panne
46 *
47 * Revision 1.9 1998/07/31 03:06:20 brianp
48 * tweaked the gluScaleImage() function per Randy Frank
49 *
50 * Revision 1.8 1998/07/08 01:02:53 brianp
51 * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE
52 *
53 * Revision 1.7 1998/07/01 00:18:02 brianp
54 * if gluBuildxDMipmaps() width or height <= 0 just return 0
55 *
56 * Revision 1.6 1998/06/01 01:06:41 brianp
57 * small update for Next/OpenStep from Alexander Mai
58 *
59 * Revision 1.5 1997/07/24 01:28:44 brianp
60 * changed precompiled header symbol from PCH to PC_HEADER
61 *
62 * Revision 1.4 1997/06/23 00:22:56 brianp
63 * added dummy() call to work around an MSVC 4.1 bug
64 *
65 * Revision 1.3 1997/05/28 02:29:38 brianp
66 * added support for precompiled headers (PCH), inserted APIENTRY keyword
67 *
68 * Revision 1.2 1997/05/24 13:32:25 brianp
69 * undef EPSILON in case it's already defined
70 *
71 * Revision 1.1 1996/09/27 01:19:39 brianp
72 * Initial revision
73 *
74 */
75
76
77 #ifdef PC_HEADER
78 #include "all.h"
79 #else
80 #include <assert.h>
81 #include <math.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include "gluP.h"
85 #endif
86
87
88 /*
89 * Compute ceiling of integer quotient of A divided by B:
90 */
91 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
92
93
94
95 #ifdef EPSILON
96 #undef EPSILON
97 #endif
98 #define EPSILON 0.001
99
100
101 /* To work around optimizer bug in MSVC4.1 */
102 #if defined(__WIN32__) && !defined(OPENSTEP)
103 void dummy(GLuint j, GLuint k){
104 }
105 #else
106 #define dummy(J, K)
107 #endif
108
109
110 GLint GLAPIENTRY gluScaleImage( GLenum format,
111 GLsizei widthin, GLsizei heightin,
112 GLenum typein, const void *datain,
113 GLsizei widthout, GLsizei heightout,
114 GLenum typeout, void *dataout )
115 {
116 GLint components, i, j, k;
117 GLfloat *tempin, *tempout;
118 GLfloat sx, sy;
119 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
120 GLint packrowlength, packalignment, packskiprows, packskippixels;
121 GLint sizein, sizeout;
122 GLint rowstride, rowlen;
123
124
125 /* Determine number of components per pixel */
126 switch (format) {
127 case GL_COLOR_INDEX:
128 case GL_STENCIL_INDEX:
129 case GL_DEPTH_COMPONENT:
130 case GL_RED:
131 case GL_GREEN:
132 case GL_BLUE:
133 case GL_ALPHA:
134 case GL_LUMINANCE:
135 components = 1;
136 break;
137 case GL_LUMINANCE_ALPHA:
138 components = 2;
139 break;
140 case GL_RGB:
141 components = 3;
142 break;
143 case GL_RGBA:
144 #ifdef GL_EXT_abgr
145 case GL_ABGR_EXT:
146 #endif
147 components = 4;
148 break;
149 default:
150 return GLU_INVALID_ENUM;
151 }
152
153 /* Determine bytes per input datum */
154 switch (typein) {
155 case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break;
156 case GL_BYTE: sizein = sizeof(GLbyte); break;
157 case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break;
158 case GL_SHORT: sizein = sizeof(GLshort); break;
159 case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break;
160 case GL_INT: sizein = sizeof(GLint); break;
161 case GL_FLOAT: sizein = sizeof(GLfloat); break;
162 case GL_BITMAP:
163 /* not implemented yet */
164 default:
165 return GL_INVALID_ENUM;
166 }
167
168 /* Determine bytes per output datum */
169 switch (typeout) {
170 case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break;
171 case GL_BYTE: sizeout = sizeof(GLbyte); break;
172 case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break;
173 case GL_SHORT: sizeout = sizeof(GLshort); break;
174 case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break;
175 case GL_INT: sizeout = sizeof(GLint); break;
176 case GL_FLOAT: sizeout = sizeof(GLfloat); break;
177 case GL_BITMAP:
178 /* not implemented yet */
179 default:
180 return GL_INVALID_ENUM;
181 }
182
183 /* Get glPixelStore state */
184 glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
185 glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
186 glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
187 glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
188 glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
189 glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
190 glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
191 glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
192
193 /* Allocate storage for intermediate images */
194 tempin = (GLfloat *) malloc( widthin * heightin
195 * components * sizeof(GLfloat) );
196 if (!tempin) {
197 return GLU_OUT_OF_MEMORY;
198 }
199 tempout = (GLfloat *) malloc( widthout * heightout
200 * components * sizeof(GLfloat) );
201 if (!tempout) {
202 free( tempin );
203 return GLU_OUT_OF_MEMORY;
204 }
205
206
207 /*
208 * Unpack the pixel data and convert to floating point
209 */
210
211 if (unpackrowlength>0) {
212 rowlen = unpackrowlength;
213 }
214 else {
215 rowlen = widthin;
216 }
217 if (sizein >= unpackalignment) {
218 rowstride = components * rowlen;
219 }
220 else {
221 rowstride = unpackalignment/sizein
222 * CEILING( components * rowlen * sizein, unpackalignment );
223 }
224
225 switch (typein) {
226 case GL_UNSIGNED_BYTE:
227 k = 0;
228 for (i=0;i<heightin;i++) {
229 GLubyte *ubptr = (GLubyte *) datain
230 + i * rowstride
231 + unpackskiprows * rowstride
232 + unpackskippixels * components;
233 for (j=0;j<widthin*components;j++) {
234 dummy(j, k);
235 tempin[k++] = (GLfloat) *ubptr++;
236 }
237 }
238 break;
239 case GL_BYTE:
240 k = 0;
241 for (i=0;i<heightin;i++) {
242 GLbyte *bptr = (GLbyte *) datain
243 + i * rowstride
244 + unpackskiprows * rowstride
245 + unpackskippixels * components;
246 for (j=0;j<widthin*components;j++) {
247 dummy(j, k);
248 tempin[k++] = (GLfloat) *bptr++;
249 }
250 }
251 break;
252 case GL_UNSIGNED_SHORT:
253 k = 0;
254 for (i=0;i<heightin;i++) {
255 GLushort *usptr = (GLushort *) datain
256 + i * rowstride
257 + unpackskiprows * rowstride
258 + unpackskippixels * components;
259 for (j=0;j<widthin*components;j++) {
260 dummy(j, k);
261 tempin[k++] = (GLfloat) *usptr++;
262 }
263 }
264 break;
265 case GL_SHORT:
266 k = 0;
267 for (i=0;i<heightin;i++) {
268 GLshort *sptr = (GLshort *) datain
269 + i * rowstride
270 + unpackskiprows * rowstride
271 + unpackskippixels * components;
272 for (j=0;j<widthin*components;j++) {
273 dummy(j, k);
274 tempin[k++] = (GLfloat) *sptr++;
275 }
276 }
277 break;
278 case GL_UNSIGNED_INT:
279 k = 0;
280 for (i=0;i<heightin;i++) {
281 GLuint *uiptr = (GLuint *) datain
282 + i * rowstride
283 + unpackskiprows * rowstride
284 + unpackskippixels * components;
285 for (j=0;j<widthin*components;j++) {
286 dummy(j, k);
287 tempin[k++] = (GLfloat) *uiptr++;
288 }
289 }
290 break;
291 case GL_INT:
292 k = 0;
293 for (i=0;i<heightin;i++) {
294 GLint *iptr = (GLint *) datain
295 + i * rowstride
296 + unpackskiprows * rowstride
297 + unpackskippixels * components;
298 for (j=0;j<widthin*components;j++) {
299 dummy(j, k);
300 tempin[k++] = (GLfloat) *iptr++;
301 }
302 }
303 break;
304 case GL_FLOAT:
305 k = 0;
306 for (i=0;i<heightin;i++) {
307 GLfloat *fptr = (GLfloat *) datain
308 + i * rowstride
309 + unpackskiprows * rowstride
310 + unpackskippixels * components;
311 for (j=0;j<widthin*components;j++) {
312 dummy(j, k);
313 tempin[k++] = *fptr++;
314 }
315 }
316 break;
317 default:
318 return GLU_INVALID_ENUM;
319 }
320
321
322 /*
323 * Scale the image!
324 */
325
326 if (widthout > 1)
327 sx = (GLfloat) (widthin-1) / (GLfloat) (widthout-1);
328 else
329 sx = (GLfloat) (widthin-1);
330 if (heightout > 1)
331 sy = (GLfloat) (heightin-1) / (GLfloat) (heightout-1);
332 else
333 sy = (GLfloat) (heightin-1);
334
335 /*#define POINT_SAMPLE*/
336 #ifdef POINT_SAMPLE
337 for (i=0;i<heightout;i++) {
338 GLint ii = i * sy;
339 for (j=0;j<widthout;j++) {
340 GLint jj = j * sx;
341
342 GLfloat *src = tempin + (ii * widthin + jj) * components;
343 GLfloat *dst = tempout + (i * widthout + j) * components;
344
345 for (k=0;k<components;k++) {
346 *dst++ = *src++;
347 }
348 }
349 }
350 #else
351 if (sx<1.0 && sy<1.0) {
352 /* magnify both width and height: use weighted sample of 4 pixels */
353 GLint i0, i1, j0, j1;
354 GLfloat alpha, beta;
355 GLfloat *src00, *src01, *src10, *src11;
356 GLfloat s1, s2;
357 GLfloat *dst;
358
359 for (i=0;i<heightout;i++) {
360 i0 = i * sy;
361 i1 = i0 + 1;
362 if (i1 >= heightin) i1 = heightin-1;
363 /* i1 = (i+1) * sy - EPSILON;*/
364 alpha = i*sy - i0;
365 for (j=0;j<widthout;j++) {
366 j0 = j * sx;
367 j1 = j0 + 1;
368 if (j1 >= widthin) j1 = widthin-1;
369 /* j1 = (j+1) * sx - EPSILON; */
370 beta = j*sx - j0;
371
372 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
373 src00 = tempin + (i0 * widthin + j0) * components;
374 src01 = tempin + (i0 * widthin + j1) * components;
375 src10 = tempin + (i1 * widthin + j0) * components;
376 src11 = tempin + (i1 * widthin + j1) * components;
377
378 dst = tempout + (i * widthout + j) * components;
379
380 for (k=0;k<components;k++) {
381 s1 = *src00++ * (1.0-beta) + *src01++ * beta;
382 s2 = *src10++ * (1.0-beta) + *src11++ * beta;
383 *dst++ = s1 * (1.0-alpha) + s2 * alpha;
384 }
385 }
386 }
387 }
388 else {
389 /* shrink width and/or height: use an unweighted box filter */
390 GLint i0, i1;
391 GLint j0, j1;
392 GLint ii, jj;
393 GLfloat sum, *dst;
394
395 for (i=0;i<heightout;i++) {
396 i0 = i * sy;
397 i1 = i0 + 1;
398 if (i1 >= heightin) i1 = heightin-1;
399 /* i1 = (i+1) * sy - EPSILON; */
400 for (j=0;j<widthout;j++) {
401 j0 = j * sx;
402 j1 = j0 + 1;
403 if (j1 >= widthin) j1 = widthin-1;
404 /* j1 = (j+1) * sx - EPSILON; */
405
406 dst = tempout + (i * widthout + j) * components;
407
408 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
409 for (k=0;k<components;k++) {
410 sum = 0.0;
411 for (ii=i0;ii<=i1;ii++) {
412 for (jj=j0;jj<=j1;jj++) {
413 sum += *(tempin + (ii * widthin + jj) * components + k);
414 }
415 }
416 sum /= (j1-j0+1) * (i1-i0+1);
417 *dst++ = sum;
418 }
419 }
420 }
421 }
422 #endif
423
424
425 /*
426 * Return output image
427 */
428
429 if (packrowlength>0) {
430 rowlen = packrowlength;
431 }
432 else {
433 rowlen = widthout;
434 }
435 if (sizeout >= packalignment) {
436 rowstride = components * rowlen;
437 }
438 else {
439 rowstride = packalignment/sizeout
440 * CEILING( components * rowlen * sizeout, packalignment );
441 }
442
443 switch (typeout) {
444 case GL_UNSIGNED_BYTE:
445 k = 0;
446 for (i=0;i<heightout;i++) {
447 GLubyte *ubptr = (GLubyte *) dataout
448 + i * rowstride
449 + packskiprows * rowstride
450 + packskippixels * components;
451 for (j=0;j<widthout*components;j++) {
452 dummy(j, k+i);
453 *ubptr++ = (GLubyte) tempout[k++];
454 }
455 }
456 break;
457 case GL_BYTE:
458 k = 0;
459 for (i=0;i<heightout;i++) {
460 GLbyte *bptr = (GLbyte *) dataout
461 + i * rowstride
462 + packskiprows * rowstride
463 + packskippixels * components;
464 for (j=0;j<widthout*components;j++) {
465 dummy(j, k+i);
466 *bptr++ = (GLbyte) tempout[k++];
467 }
468 }
469 break;
470 case GL_UNSIGNED_SHORT:
471 k = 0;
472 for (i=0;i<heightout;i++) {
473 GLushort *usptr = (GLushort *) dataout
474 + i * rowstride
475 + packskiprows * rowstride
476 + packskippixels * components;
477 for (j=0;j<widthout*components;j++) {
478 dummy(j, k+i);
479 *usptr++ = (GLushort) tempout[k++];
480 }
481 }
482 break;
483 case GL_SHORT:
484 k = 0;
485 for (i=0;i<heightout;i++) {
486 GLshort *sptr = (GLshort *) dataout
487 + i * rowstride
488 + packskiprows * rowstride
489 + packskippixels * components;
490 for (j=0;j<widthout*components;j++) {
491 dummy(j, k+i);
492 *sptr++ = (GLshort) tempout[k++];
493 }
494 }
495 break;
496 case GL_UNSIGNED_INT:
497 k = 0;
498 for (i=0;i<heightout;i++) {
499 GLuint *uiptr = (GLuint *) dataout
500 + i * rowstride
501 + packskiprows * rowstride
502 + packskippixels * components;
503 for (j=0;j<widthout*components;j++) {
504 dummy(j, k+i);
505 *uiptr++ = (GLuint) tempout[k++];
506 }
507 }
508 break;
509 case GL_INT:
510 k = 0;
511 for (i=0;i<heightout;i++) {
512 GLint *iptr = (GLint *) dataout
513 + i * rowstride
514 + packskiprows * rowstride
515 + packskippixels * components;
516 for (j=0;j<widthout*components;j++) {
517 dummy(j, k+i);
518 *iptr++ = (GLint) tempout[k++];
519 }
520 }
521 break;
522 case GL_FLOAT:
523 k = 0;
524 for (i=0;i<heightout;i++) {
525 GLfloat *fptr = (GLfloat *) dataout
526 + i * rowstride
527 + packskiprows * rowstride
528 + packskippixels * components;
529 for (j=0;j<widthout*components;j++) {
530 dummy(j, k+i);
531 *fptr++ = tempout[k++];
532 }
533 }
534 break;
535 default:
536 return GLU_INVALID_ENUM;
537 }
538
539
540 /* free temporary image storage */
541 free( tempin );
542 free( tempout );
543
544 return 0;
545 }
546
547
548
549 /*
550 * Return the largest k such that 2^k <= n.
551 */
552 static GLint ilog2( GLint n )
553 {
554 GLint k;
555
556 if (n<=0) return 0;
557 for (k=0; n>>=1; k++) ;
558 return k;
559 }
560
561
562
563 /*
564 * Find the value nearest to n which is also a power of two.
565 */
566 static GLint round2( GLint n )
567 {
568 GLint m;
569
570 for (m=1; m<n; m*=2)
571 ;
572
573 /* m>=n */
574 if (m-n <= n-m/2) {
575 return m;
576 }
577 else {
578 return m/2;
579 }
580 }
581
582
583 /*
584 * Given an pixel format and datatype, return the number of bytes to
585 * store one pixel.
586 */
587 static GLint bytes_per_pixel( GLenum format, GLenum type )
588 {
589 GLint n, m;
590
591 switch (format) {
592 case GL_COLOR_INDEX:
593 case GL_STENCIL_INDEX:
594 case GL_DEPTH_COMPONENT:
595 case GL_RED:
596 case GL_GREEN:
597 case GL_BLUE:
598 case GL_ALPHA:
599 case GL_LUMINANCE:
600 n = 1;
601 break;
602 case GL_LUMINANCE_ALPHA:
603 n = 2;
604 break;
605 case GL_RGB:
606 n = 3;
607 break;
608 case GL_RGBA:
609 #ifdef GL_EXT_abgr
610 case GL_ABGR_EXT:
611 #endif
612 n = 4;
613 break;
614 default:
615 n = 0;
616 }
617
618 switch (type) {
619 case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break;
620 case GL_BYTE: m = sizeof(GLbyte); break;
621 case GL_BITMAP: m = 1; break;
622 case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break;
623 case GL_SHORT: m = sizeof(GLshort); break;
624 case GL_UNSIGNED_INT: m = sizeof(GLuint); break;
625 case GL_INT: m = sizeof(GLint); break;
626 case GL_FLOAT: m = sizeof(GLfloat); break;
627 default: m = 0;
628 }
629
630 return n * m;
631 }
632
633
634
635 /*
636 * WARNING: This function isn't finished and has never been tested!!!!
637 */
638 GLint GLAPIENTRY gluBuild1DMipmaps( GLenum target, GLint components,
639 GLsizei width, GLenum format,
640 GLenum type, const void *data )
641 {
642 GLubyte *texture;
643 GLint levels, max_levels;
644 GLint new_width, max_width;
645 GLint i, j, k, l;
646
647 if (width < 1)
648 return GLU_INVALID_VALUE;
649
650 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width );
651 max_levels = ilog2( max_width ) + 1;
652
653 /* Compute how many mipmap images to make */
654 levels = ilog2( width ) + 1;
655 if (levels>max_levels) {
656 levels = max_levels;
657 }
658
659 new_width = 1 << (levels-1);
660
661 texture = (GLubyte *) malloc( new_width * components );
662 if (!texture) {
663 return GLU_OUT_OF_MEMORY;
664 }
665
666 if (width != new_width) {
667 /* initial rescaling */
668 switch (type) {
669 case GL_UNSIGNED_BYTE:
670 {
671 GLubyte *ub_data = (GLubyte *) data;
672 for (i=0;i<new_width;i++) {
673 j = i * width / new_width;
674 for (k=0;k<components;k++) {
675 texture[i*components+k] = ub_data[j*components+k];
676 }
677 }
678 }
679 break;
680 default:
681 /* Not implemented */
682 return GLU_ERROR;
683 }
684 }
685
686 /* generate and load mipmap images */
687 for (l=0;l<levels;l++) {
688 glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0,
689 format, GL_UNSIGNED_BYTE, texture );
690
691 /* Scale image down to 1/2 size */
692 new_width = new_width / 2;
693 for (i=0;i<new_width;i++) {
694 for (k=0;k<components;k++) {
695 GLint sample1, sample2;
696 sample1 = (GLint) texture[i*2*components+k];
697 sample2 = (GLint) texture[(i*2+1)*components+k];
698 texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2);
699 }
700 }
701 }
702
703 free( texture );
704
705 /* make sure remaining mipmap levels are removed */
706 for (l=levels;l<max_levels;l++) {
707 glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0,
708 format, GL_UNSIGNED_BYTE, NULL );
709 }
710
711 return 0;
712 }
713
714
715
716 GLint GLAPIENTRY gluBuild2DMipmaps( GLenum target, GLint components,
717 GLsizei width, GLsizei height, GLenum format,
718 GLenum type, const void *data )
719 {
720 GLint w, h, maxsize;
721 void *image, *newimage;
722 GLint neww, newh, level, bpp;
723 int error;
724 GLboolean done;
725 GLint retval = 0;
726 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
727 GLint packrowlength, packalignment, packskiprows, packskippixels;
728
729 if (width < 1 || height < 1)
730 return GLU_INVALID_VALUE;
731
732 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize );
733
734 w = round2( width );
735 if (w>maxsize) {
736 w = maxsize;
737 }
738 h = round2( height );
739 if (h>maxsize) {
740 h = maxsize;
741 }
742
743 bpp = bytes_per_pixel( format, type );
744 if (bpp==0) {
745 /* probably a bad format or type enum */
746 return GLU_INVALID_ENUM;
747 }
748
749 /* Get current glPixelStore values */
750 glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
751 glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
752 glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
753 glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
754 glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
755 glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
756 glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
757 glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
758
759 /* set pixel packing */
760 glPixelStorei( GL_PACK_ROW_LENGTH, 0 );
761 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
762 glPixelStorei( GL_PACK_SKIP_ROWS, 0 );
763 glPixelStorei( GL_PACK_SKIP_PIXELS, 0 );
764
765 done = GL_FALSE;
766
767 if (w!=width || h!=height) {
768 /* must rescale image to get "top" mipmap texture image */
769 image = malloc( (w+4) * h * bpp );
770 if (!image) {
771 return GLU_OUT_OF_MEMORY;
772 }
773 error = gluScaleImage( format, width, height, type, data,
774 w, h, type, image );
775 if (error) {
776 retval = error;
777 done = GL_TRUE;
778 }
779 }
780 else {
781 image = (void *) data;
782 }
783
784 level = 0;
785 while (!done) {
786 if (image != data) {
787 /* set pixel unpacking */
788 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
789 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
790 glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
791 glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
792 }
793
794 glTexImage2D( target, level, components, w, h, 0, format, type, image );
795
796 if (w==1 && h==1) break;
797
798 neww = (w<2) ? 1 : w/2;
799 newh = (h<2) ? 1 : h/2;
800 newimage = malloc( (neww+4) * newh * bpp );
801 if (!newimage) {
802 return GLU_OUT_OF_MEMORY;
803 }
804
805 error = gluScaleImage( format, w, h, type, image,
806 neww, newh, type, newimage );
807 if (error) {
808 retval = error;
809 done = GL_TRUE;
810 }
811
812 if (image!=data) {
813 free( image );
814 }
815 image = newimage;
816
817 w = neww;
818 h = newh;
819 level++;
820 }
821
822 if (image!=data) {
823 free( image );
824 }
825
826 /* Restore original glPixelStore state */
827 glPixelStorei( GL_UNPACK_ROW_LENGTH, unpackrowlength );
828 glPixelStorei( GL_UNPACK_ALIGNMENT, unpackalignment );
829 glPixelStorei( GL_UNPACK_SKIP_ROWS, unpackskiprows );
830 glPixelStorei( GL_UNPACK_SKIP_PIXELS, unpackskippixels );
831 glPixelStorei( GL_PACK_ROW_LENGTH, packrowlength );
832 glPixelStorei( GL_PACK_ALIGNMENT, packalignment );
833 glPixelStorei( GL_PACK_SKIP_ROWS, packskiprows );
834 glPixelStorei( GL_PACK_SKIP_PIXELS, packskippixels );
835
836 return retval;
837 }
838