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