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