Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: mipmap.c,v 1.1 2003-02-28 11:42:07 pj 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
}