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