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