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