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