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