Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

glu_mipmap.cpp

Go to the documentation of this file.
00001 
00002 /*
00003  * Mesa 3-D graphics library
00004  * Version:  3.4
00005  * Copyright (C) 1995-2000  Brian Paul
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Library General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Library General Public
00018  * License along with this library; if not, write to the Free
00019  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020  */
00021 
00022 
00023 #include "Teddy/Graphics/Device.h"
00024 
00025 
00026 /* ErrorCode */
00027 #define GLU_ERROR                          100103
00028 #define GLU_INVALID_ENUM                   100900
00029 #define GLU_INVALID_VALUE                  100901
00030 #define GLU_OUT_OF_MEMORY                  100902
00031 #define GLU_INVALID_OPERATION              100904
00032 
00033 
00034 #include "Teddy/SysSupport/StdMaths.h"
00035 #ifndef SWIG
00036 # include <cassert>
00037 # include <cstdio>
00038 # include <cstdlib>
00039 #endif
00040 /*#include "gluP.h"
00041 #endif*/
00042 
00043 
00044 /*
00045  * Compute ceiling of integer quotient of A divided by B:
00046  */
00047 #define CEILING( A, B )  ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
00048 
00049 
00050 
00051 #ifdef EPSILON
00052 #undef EPSILON
00053 #endif
00054 #define EPSILON 0.001
00055 
00056 
00057 /* To work around optimizer bug in MSVC4.1 */
00058 #if defined(__WIN32__) && !defined(OPENSTEP)
00059 void
00060 dummy(GLuint j, GLuint k)
00061 {
00062 }
00063 #else
00064 #define dummy(J, K)
00065 #endif
00066 
00067 
00068 GLint /*GLAPIENTRY*/
00069 glu_ScaleImage(GLenum format,
00070           GLsizei widthin, GLsizei heightin,
00071           GLenum typein, const void *datain,
00072           GLsizei widthout, GLsizei heightout,
00073           GLenum typeout, void **dataoutp)
00074 {
00075    GLint components, i, j, k;
00076    GLfloat *tempin, *tempout;
00077    GLfloat sx, sy;
00078    GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
00079    GLint packrowlength, packalignment, packskiprows, packskippixels;
00080    GLint sizein, sizeout;
00081    GLint rowstride, rowlen;
00082    GLint dataoutsize;
00083    void *dataout;
00084 
00085 
00086    /* Determine number of components per pixel */
00087    switch (format) {
00088    case GL_COLOR_INDEX:
00089    case GL_STENCIL_INDEX:
00090    case GL_DEPTH_COMPONENT:
00091    case GL_RED:
00092    case GL_GREEN:
00093    case GL_BLUE:
00094    case GL_ALPHA:
00095    case GL_LUMINANCE:
00096       components = 1;
00097       break;
00098    case GL_LUMINANCE_ALPHA:
00099       components = 2;
00100       break;
00101    case GL_RGB:
00102 #ifdef GL_BGR
00103    case GL_BGR:
00104 #endif
00105       components = 3;
00106       break;
00107    case GL_RGBA:
00108 #ifdef GL_BGRA
00109    case GL_BGRA:
00110 #endif
00111 #ifdef GL_EXT_abgr
00112    case GL_ABGR_EXT:
00113 #endif
00114       components = 4;
00115       break;
00116    default:
00117       return GLU_INVALID_ENUM;
00118    }
00119 
00120    /* Determine bytes per input datum */
00121    switch (typein) {
00122    case GL_UNSIGNED_BYTE:
00123       sizein = sizeof(GLubyte);
00124       break;
00125    case GL_BYTE:
00126       sizein = sizeof(GLbyte);
00127       break;
00128    case GL_UNSIGNED_SHORT:
00129       sizein = sizeof(GLushort);
00130       break;
00131    case GL_SHORT:
00132       sizein = sizeof(GLshort);
00133       break;
00134    case GL_UNSIGNED_INT:
00135       sizein = sizeof(GLuint);
00136       break;
00137    case GL_INT:
00138       sizein = sizeof(GLint);
00139       break;
00140    case GL_FLOAT:
00141       sizein = sizeof(GLfloat);
00142       break;
00143    case GL_BITMAP:
00144       /* not implemented yet */
00145    default:
00146       return GL_INVALID_ENUM;
00147    }
00148 
00149    /* Determine bytes per output datum */
00150    switch (typeout) {
00151    case GL_UNSIGNED_BYTE:
00152       sizeout = sizeof(GLubyte);
00153       break;
00154    case GL_BYTE:
00155       sizeout = sizeof(GLbyte);
00156       break;
00157    case GL_UNSIGNED_SHORT:
00158       sizeout = sizeof(GLushort);
00159       break;
00160    case GL_SHORT:
00161       sizeout = sizeof(GLshort);
00162       break;
00163    case GL_UNSIGNED_INT:
00164       sizeout = sizeof(GLuint);
00165       break;
00166    case GL_INT:
00167       sizeout = sizeof(GLint);
00168       break;
00169    case GL_FLOAT:
00170       sizeout = sizeof(GLfloat);
00171       break;
00172    case GL_BITMAP:
00173       /* not implemented yet */
00174    default:
00175       return GL_INVALID_ENUM;
00176    }
00177 
00178    /* Get glPixelStore state */
00179 #   if defined( USE_TINY_GL )
00180     unpackrowlength  = 0;
00181     unpackalignment  = 1;
00182     unpackskiprows   = 0;
00183     unpackskippixels = 0;
00184     packrowlength    = 0;
00185     packalignment    = 1;
00186     packskiprows     = 0;
00187     packskippixels   = 0;
00188 #   else
00189    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
00190    glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
00191    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
00192    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
00193    glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
00194    glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
00195    glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
00196    glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
00197 #   endif
00198 
00199    /* Allocate storage for intermediate images */
00200    tempin = (GLfloat *) malloc(widthin * heightin
00201                    * components * sizeof(GLfloat));
00202    if (!tempin) {
00203       return GLU_OUT_OF_MEMORY;
00204    }
00205    tempout = (GLfloat *) malloc(widthout * heightout
00206                 * components * sizeof(GLfloat));
00207    if (!tempout) {
00208       free(tempin);
00209       return GLU_OUT_OF_MEMORY;
00210    }
00211 
00212 
00213    /*
00214     * Unpack the pixel data and convert to floating point
00215     */
00216 
00217    if (unpackrowlength > 0) {
00218       rowlen = unpackrowlength;
00219    }
00220    else {
00221       rowlen = widthin;
00222    }
00223    if (sizein >= unpackalignment) {
00224       rowstride = components * rowlen;
00225    }
00226    else {
00227       rowstride = unpackalignment / sizein
00228      * CEILING(components * rowlen * sizein, unpackalignment);
00229    }
00230 
00231    switch (typein) {
00232    case GL_UNSIGNED_BYTE:
00233       k = 0;
00234       for (i = 0; i < heightin; i++) {
00235      GLubyte *ubptr = (GLubyte *) datain
00236         + i * rowstride
00237         + unpackskiprows * rowstride + unpackskippixels * components;
00238      for (j = 0; j < widthin * components; j++) {
00239         dummy(j, k);
00240         tempin[k++] = (GLfloat) * ubptr++;
00241      }
00242       }
00243       break;
00244    case GL_BYTE:
00245       k = 0;
00246       for (i = 0; i < heightin; i++) {
00247      GLbyte *bptr = (GLbyte *) datain
00248         + i * rowstride
00249         + unpackskiprows * rowstride + unpackskippixels * components;
00250      for (j = 0; j < widthin * components; j++) {
00251         dummy(j, k);
00252         tempin[k++] = (GLfloat) * bptr++;
00253      }
00254       }
00255       break;
00256    case GL_UNSIGNED_SHORT:
00257       k = 0;
00258       for (i = 0; i < heightin; i++) {
00259      GLushort *usptr = (GLushort *) datain
00260         + i * rowstride
00261         + unpackskiprows * rowstride + unpackskippixels * components;
00262      for (j = 0; j < widthin * components; j++) {
00263         dummy(j, k);
00264         tempin[k++] = (GLfloat) * usptr++;
00265      }
00266       }
00267       break;
00268    case GL_SHORT:
00269       k = 0;
00270       for (i = 0; i < heightin; i++) {
00271      GLshort *sptr = (GLshort *) datain
00272         + i * rowstride
00273         + unpackskiprows * rowstride + unpackskippixels * components;
00274      for (j = 0; j < widthin * components; j++) {
00275         dummy(j, k);
00276         tempin[k++] = (GLfloat) * sptr++;
00277      }
00278       }
00279       break;
00280    case GL_UNSIGNED_INT:
00281       k = 0;
00282       for (i = 0; i < heightin; i++) {
00283      GLuint *uiptr = (GLuint *) datain
00284         + i * rowstride
00285         + unpackskiprows * rowstride + unpackskippixels * components;
00286      for (j = 0; j < widthin * components; j++) {
00287         dummy(j, k);
00288         tempin[k++] = (GLfloat) * uiptr++;
00289      }
00290       }
00291       break;
00292    case GL_INT:
00293       k = 0;
00294       for (i = 0; i < heightin; i++) {
00295      GLint *iptr = (GLint *) datain
00296         + i * rowstride
00297         + unpackskiprows * rowstride + unpackskippixels * components;
00298      for (j = 0; j < widthin * components; j++) {
00299         dummy(j, k);
00300         tempin[k++] = (GLfloat) * iptr++;
00301      }
00302       }
00303       break;
00304    case GL_FLOAT:
00305       k = 0;
00306       for (i = 0; i < heightin; i++) {
00307      GLfloat *fptr = (GLfloat *) datain
00308         + i * rowstride
00309         + unpackskiprows * rowstride + unpackskippixels * components;
00310      for (j = 0; j < widthin * components; j++) {
00311         dummy(j, k);
00312         tempin[k++] = *fptr++;
00313      }
00314       }
00315       break;
00316    default:
00317       return GLU_INVALID_ENUM;
00318    }
00319 
00320 
00321    /*
00322     * Scale the image!
00323     */
00324 
00325    if (widthout > 1)
00326       sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1);
00327    else
00328       sx = (GLfloat) (widthin - 1);
00329    if (heightout > 1)
00330       sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1);
00331    else
00332       sy = (GLfloat) (heightin - 1);
00333 
00334 /*#define POINT_SAMPLE*/
00335 #ifdef POINT_SAMPLE
00336    for (i = 0; i < heightout; i++) {
00337       GLint ii = i * sy;
00338       for (j = 0; j < widthout; j++) {
00339      GLint jj = j * sx;
00340 
00341      GLfloat *src = tempin + (ii * widthin + jj) * components;
00342      GLfloat *dst = tempout + (i * widthout + j) * components;
00343 
00344      for (k = 0; k < components; k++) {
00345         *dst++ = *src++;
00346      }
00347       }
00348    }
00349 #else
00350    if (sx < 1.0 && sy < 1.0) {
00351       /* magnify both width and height:  use weighted sample of 4 pixels */
00352       GLint i0, i1, j0, j1;
00353       GLfloat alpha, beta;
00354       GLfloat *src00, *src01, *src10, *src11;
00355       GLdouble s1, s2;
00356       GLfloat *dst;
00357 
00358       for (i = 0; i < heightout; i++) {
00359      i0 = (int)(i * sy);
00360      i1 = i0 + 1;
00361      if (i1 >= heightin)
00362         i1 = heightin - 1;
00363 /*   i1 = (i+1) * sy - EPSILON;*/
00364      alpha = i * sy - i0;
00365      for (j = 0; j < widthout; j++) {
00366         j0 = (int)(j * sx);
00367         j1 = j0 + 1;
00368         if (j1 >= widthin)
00369            j1 = widthin - 1;
00370 /*      j1 = (j+1) * sx - EPSILON; */
00371         beta = j * sx - j0;
00372 
00373         /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
00374         src00 = tempin + (i0 * widthin + j0) * components;
00375         src01 = tempin + (i0 * widthin + j1) * components;
00376         src10 = tempin + (i1 * widthin + j0) * components;
00377         src11 = tempin + (i1 * widthin + j1) * components;
00378 
00379         dst = tempout + (i * widthout + j) * components;
00380 
00381         for (k = 0; k < components; k++) {
00382            s1 = *src00++ * (1.0 - beta) + *src01++ * beta;
00383            s2 = *src10++ * (1.0 - beta) + *src11++ * beta;
00384            *dst++ = (float)(s1 * (1.0 - alpha) + s2 * alpha);
00385         }
00386      }
00387       }
00388    }
00389    else {
00390       /* shrink width and/or height:  use an unweighted box filter */
00391       GLint i0, i1;
00392       GLint j0, j1;
00393       GLint ii, jj;
00394       GLfloat sum, *dst;
00395 
00396       for (i = 0; i < heightout; i++) {
00397      i0 = (int)(i * sy);
00398      i1 = i0 + 1;
00399      if (i1 >= heightin)
00400         i1 = heightin - 1;
00401 /*   i1 = (i+1) * sy - EPSILON; */
00402      for (j = 0; j < widthout; j++) {
00403         j0 = (int)(j * sx);
00404         j1 = j0 + 1;
00405         if (j1 >= widthin)
00406            j1 = widthin - 1;
00407 /*      j1 = (j+1) * sx - EPSILON; */
00408 
00409         dst = tempout + (i * widthout + j) * components;
00410 
00411         /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
00412         for (k = 0; k < components; k++) {
00413            sum = 0.0;
00414            for (ii = i0; ii <= i1; ii++) {
00415           for (jj = j0; jj <= j1; jj++) {
00416              sum += *(tempin + (ii * widthin + jj) * components + k);
00417           }
00418            }
00419            sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
00420            *dst++ = sum;
00421         }
00422      }
00423       }
00424    }
00425 #endif
00426 
00427 
00428    /*
00429     * Return output image
00430     */
00431    if (packrowlength > 0) {
00432       rowlen = packrowlength;
00433    }
00434    else {
00435       rowlen = widthout;
00436    }
00437    if (sizeout >= packalignment) {
00438       rowstride = components * rowlen;
00439    }
00440    else {
00441       rowstride = packalignment / sizeout
00442      * CEILING(components * rowlen * sizeout, packalignment);
00443    }
00444 
00445    dataoutsize =
00446        (heightout)    * rowstride + 
00447        packskiprows   * rowstride + 
00448        packskippixels * components;
00449 /* printf(
00450        "dataoutsize %d x %d, rowstride %d makes %ld bytes\n", 
00451        widthout,
00452        heightout, 
00453        rowstride, 
00454        dataoutsize
00455    );*/
00456 
00457    switch (typeout) {
00458    case GL_UNSIGNED_BYTE:
00459         dataout = malloc( dataoutsize * sizeof(GLubyte) );
00460         if (!dataout) {
00461             free(tempin);
00462             free(tempout);
00463             return GLU_OUT_OF_MEMORY;
00464         }
00465       k = 0;
00466       for (i = 0; i < heightout; i++) {
00467      GLubyte *ubptr = (GLubyte *) dataout
00468         + i * rowstride
00469         + packskiprows * rowstride + packskippixels * components;
00470      for (j = 0; j < widthout * components; j++) {
00471         dummy(j, k + i);
00472         *ubptr++ = (GLubyte) tempout[k++];
00473      }
00474       }
00475       break;
00476    case GL_BYTE:
00477         dataout = malloc( dataoutsize * sizeof(GLbyte) );
00478         if (!dataout) {
00479             free(tempin);
00480             free(tempout);
00481             return GLU_OUT_OF_MEMORY;
00482         }
00483       k = 0;
00484       for (i = 0; i < heightout; i++) {
00485      GLbyte *bptr = (GLbyte *) dataout
00486         + i * rowstride
00487         + packskiprows * rowstride + packskippixels * components;
00488      for (j = 0; j < widthout * components; j++) {
00489         dummy(j, k + i);
00490         *bptr++ = (GLbyte) tempout[k++];
00491      }
00492       }
00493       break;
00494    case GL_UNSIGNED_SHORT:
00495         dataout = malloc( dataoutsize * sizeof(GLushort) );
00496         if (!dataout) {
00497             free(tempin);
00498             free(tempout);
00499             return GLU_OUT_OF_MEMORY;
00500         }
00501       k = 0;
00502       for (i = 0; i < heightout; i++) {
00503      GLushort *usptr = (GLushort *) dataout
00504         + i * rowstride
00505         + packskiprows * rowstride + packskippixels * components;
00506      for (j = 0; j < widthout * components; j++) {
00507         dummy(j, k + i);
00508         *usptr++ = (GLushort) tempout[k++];
00509      }
00510       }
00511       break;
00512    case GL_SHORT:
00513         dataout = malloc( dataoutsize * sizeof(GLshort) );
00514         if (!dataout) {
00515             free(tempin);
00516             free(tempout);
00517             return GLU_OUT_OF_MEMORY;
00518         }
00519       k = 0;
00520       for (i = 0; i < heightout; i++) {
00521      GLshort *sptr = (GLshort *) dataout
00522         + i * rowstride
00523         + packskiprows * rowstride + packskippixels * components;
00524      for (j = 0; j < widthout * components; j++) {
00525         dummy(j, k + i);
00526         *sptr++ = (GLshort) tempout[k++];
00527      }
00528       }
00529       break;
00530    case GL_UNSIGNED_INT:
00531         dataout = malloc( dataoutsize * sizeof(GLuint) );
00532         if (!dataout) {
00533             free(tempin);
00534             free(tempout);
00535             return GLU_OUT_OF_MEMORY;
00536         }
00537       k = 0;
00538       for (i = 0; i < heightout; i++) {
00539      GLuint *uiptr = (GLuint *) dataout
00540         + i * rowstride
00541         + packskiprows * rowstride + packskippixels * components;
00542      for (j = 0; j < widthout * components; j++) {
00543         dummy(j, k + i);
00544         *uiptr++ = (GLuint) tempout[k++];
00545      }
00546       }
00547       break;
00548    case GL_INT:
00549         dataout = malloc( dataoutsize * sizeof(GLint) );
00550         if (!dataout) {
00551             free(tempin);
00552             free(tempout);
00553             return GLU_OUT_OF_MEMORY;
00554         }
00555       k = 0;
00556       for (i = 0; i < heightout; i++) {
00557      GLint *iptr = (GLint *) dataout
00558         + i * rowstride
00559         + packskiprows * rowstride + packskippixels * components;
00560      for (j = 0; j < widthout * components; j++) {
00561         dummy(j, k + i);
00562         *iptr++ = (GLint) tempout[k++];
00563      }
00564       }
00565       break;
00566    case GL_FLOAT:
00567         dataout = malloc( dataoutsize * sizeof(GLfloat) );
00568         if (!dataout) {
00569             free(tempin);
00570             free(tempout);
00571             return GLU_OUT_OF_MEMORY;
00572         }
00573       k = 0;
00574       for (i = 0; i < heightout; i++) {
00575      GLfloat *fptr = (GLfloat *) dataout
00576         + i * rowstride
00577         + packskiprows * rowstride + packskippixels * components;
00578      for (j = 0; j < widthout * components; j++) {
00579         dummy(j, k + i);
00580         *fptr++ = tempout[k++];
00581      }
00582       }
00583       break;
00584    default:
00585       return GLU_INVALID_ENUM;
00586    }
00587 
00588 
00589    /* free temporary image storage */
00590    free(tempin);
00591    free(tempout);
00592    *dataoutp = dataout;
00593 
00594    return 0;
00595 }
00596 
00597 
00598 
00599 /*
00600  * Return the largest k such that 2^k <= n.
00601  */
00602 static GLint
00603 ilog2(GLint n)
00604 {
00605    GLint k;
00606 
00607    if (n <= 0)
00608       return 0;
00609    for (k = 0; n >>= 1; k++);
00610    return k;
00611 }
00612 
00613 
00614 
00615 /*
00616  * Find the value nearest to n which is also a power of two.
00617  */
00618 static GLint
00619 round2(GLint n)
00620 {
00621    GLint m;
00622 
00623    for (m = 1; m < n; m *= 2);
00624 
00625    /* m>=n */
00626    if (m - n <= n - m / 2) {
00627       return m;
00628    }
00629    else {
00630       return m / 2;
00631    }
00632 }
00633 
00634 
00635 /*
00636  * Given an pixel format and datatype, return the number of bytes to
00637  * store one pixel.
00638  */
00639 static GLint
00640 bytes_per_pixel(GLenum format, GLenum type)
00641 {
00642    GLint n, m;
00643 
00644    switch (format) {
00645    case GL_COLOR_INDEX:
00646    case GL_STENCIL_INDEX:
00647    case GL_DEPTH_COMPONENT:
00648    case GL_RED:
00649    case GL_GREEN:
00650    case GL_BLUE:
00651    case GL_ALPHA:
00652    case GL_LUMINANCE:
00653       n = 1;
00654       break;
00655    case GL_LUMINANCE_ALPHA:
00656       n = 2;
00657       break;
00658    case GL_RGB:
00659 #ifdef GL_BGR
00660    case GL_BGR:
00661 #endif
00662       n = 3;
00663       break;
00664    case GL_RGBA:
00665 #ifdef GL_BGRA
00666    case GL_BGRA:
00667 #endif
00668 #ifdef GL_EXT_abgr
00669    case GL_ABGR_EXT:
00670 #endif
00671       n = 4;
00672       break;
00673    default:
00674       n = 0;
00675    }
00676 
00677    switch (type) {
00678    case GL_UNSIGNED_BYTE:
00679       m = sizeof(GLubyte);
00680       break;
00681    case GL_BYTE:
00682       m = sizeof(GLbyte);
00683       break;
00684    case GL_BITMAP:
00685       m = 1;
00686       break;
00687    case GL_UNSIGNED_SHORT:
00688       m = sizeof(GLushort);
00689       break;
00690    case GL_SHORT:
00691       m = sizeof(GLshort);
00692       break;
00693    case GL_UNSIGNED_INT:
00694       m = sizeof(GLuint);
00695       break;
00696    case GL_INT:
00697       m = sizeof(GLint);
00698       break;
00699    case GL_FLOAT:
00700       m = sizeof(GLfloat);
00701       break;
00702    default:
00703       m = 0;
00704    }
00705 
00706    return n * m;
00707 }
00708 
00709 
00710 
00711 /*
00712  * WARNING: This function isn't finished and has never been tested!!!!
00713  */
00714 GLint /*GLAPIENTRY*/
00715 glu_Build1DMipmaps(GLenum target, GLint components,
00716           GLsizei width, GLenum format, GLenum type, const void *data)
00717 {
00718 #ifndef USE_TINY_GL
00719    GLubyte *texture;
00720    GLint levels, max_levels;
00721    GLint new_width, max_width;
00722    GLint i, j, k, l;
00723 
00724    if (width < 1)
00725       return GLU_INVALID_VALUE;
00726 
00727    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_width);
00728    max_levels = ilog2(max_width) + 1;
00729 
00730    /* Compute how many mipmap images to make */
00731    levels = ilog2(width) + 1;
00732    if (levels > max_levels) {
00733       levels = max_levels;
00734    }
00735 
00736    new_width = 1 << (levels - 1);
00737 
00738    texture = (GLubyte *) malloc(new_width * components);
00739    if (!texture) {
00740       return GLU_OUT_OF_MEMORY;
00741    }
00742 
00743    if (width != new_width) {
00744       /* initial rescaling */
00745       switch (type) {
00746       case GL_UNSIGNED_BYTE:
00747      {
00748         GLubyte *ub_data = (GLubyte *) data;
00749         for (i = 0; i < new_width; i++) {
00750            j = i * width / new_width;
00751            for (k = 0; k < components; k++) {
00752           texture[i * components + k] = ub_data[j * components + k];
00753            }
00754         }
00755      }
00756      break;
00757       default:
00758      /* Not implemented */
00759      return GLU_ERROR;
00760       }
00761    }
00762 
00763    /* generate and load mipmap images */
00764    for (l = 0; l < levels; l++) {
00765       glTexImage1D(GL_TEXTURE_1D, l, components, new_width, 0,
00766            format, GL_UNSIGNED_BYTE, texture);
00767 
00768       /* Scale image down to 1/2 size */
00769       new_width = new_width / 2;
00770       for (i = 0; i < new_width; i++) {
00771      for (k = 0; k < components; k++) {
00772         GLint sample1, sample2;
00773         sample1 = (GLint) texture[i * 2 * components + k];
00774         sample2 = (GLint) texture[(i * 2 + 1) * components + k];
00775         texture[i * components + k] = (GLubyte) ((sample1 + sample2) / 2);
00776      }
00777       }
00778    }
00779 
00780    free(texture);
00781 
00782    return 0;
00783 #else 
00784    return GLU_ERROR;
00785 #endif
00786 }
00787 
00788 
00789 
00790 GLint /*GLAPIENTRY*/
00791 glu_Build2DMipmaps(GLenum target, GLint components,
00792           GLsizei width, GLsizei height, GLenum format,
00793           GLenum type, const void *data)
00794 {
00795    GLint w, h, maxsize;
00796    void *image, *newimage;
00797    GLint neww, newh, level, bpp;
00798    int error;
00799    GLboolean done;
00800    GLint retval = 0;
00801    GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
00802    GLint packrowlength, packalignment, packskiprows, packskippixels;
00803 
00804    if (width < 1 || height < 1)
00805       return GLU_INVALID_VALUE;
00806 
00807    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
00808 
00809    w = round2(width);
00810    if (w > maxsize) {
00811       w = maxsize;
00812    }
00813    h = round2(height);
00814    if (h > maxsize) {
00815       h = maxsize;
00816    }
00817 
00818    bpp = bytes_per_pixel(format, type);
00819    if (bpp == 0) {
00820       /* probably a bad format or type enum */
00821       return GLU_INVALID_ENUM;
00822    }
00823 
00824    /* Get current glPixelStore values */
00825    glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
00826    glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
00827    glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
00828    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
00829    glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
00830    glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
00831    glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
00832    glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
00833 
00834    /* set pixel packing */
00835    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
00836    glPixelStorei(GL_PACK_ALIGNMENT, 1);
00837    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
00838    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
00839 
00840    done = GL_FALSE;
00841 
00842    if (w != width || h != height) {
00843       /* must rescale image to get "top" mipmap texture image */
00844 //  printf( "image %d x %d, bpp = %d makes %ld bytes\n", w, h, bpp, (w + 4) * h * bpp );
00845 /*      image = malloc((w + 4) * h * bpp);
00846       if (!image) {
00847      return GLU_OUT_OF_MEMORY;
00848       }*/
00849       error = glu_ScaleImage(format, width, height, type, data,
00850                 w, h, type, &image);
00851       if (error) {
00852      retval = error;
00853      done = GL_TRUE;
00854       }
00855    }
00856    else {
00857       image = (void *) data;
00858    }
00859 
00860    level = 0;
00861    while (!done) {
00862       if (image != data) {
00863      /* set pixel unpacking */
00864      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00865      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00866      glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
00867      glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
00868       }
00869 
00870       glTexImage2D(target, level, components, w, h, 0, format, type, image);
00871 
00872       if (w == 1 && h == 1)
00873      break;
00874 
00875       neww = (w < 2) ? 1 : w / 2;
00876       newh = (h < 2) ? 1 : h / 2;
00877 /*  printf(
00878            "newimage %d x %d, bpp = %d makes %d rowstride and %ld bytes\n",
00879            neww, 
00880            newh, 
00881            bpp, 
00882            bpp*neww,
00883            (neww + 4) * newh * bpp
00884         );*/
00885 /*      newimage = malloc((neww + 4) * newh * bpp);
00886       if (!newimage) {
00887      return GLU_OUT_OF_MEMORY;
00888       }*/
00889 
00890       error = glu_ScaleImage(format, w, h, type, image,
00891                 neww, newh, type, &newimage);
00892       if (error) {
00893      retval = error;
00894      done = GL_TRUE;
00895       }
00896 
00897       if (image != data) {
00898      free(image);
00899       }
00900       image = newimage;
00901 
00902       w = neww;
00903       h = newh;
00904       level++;
00905    }
00906 
00907    if (image != data) {
00908       free(image);
00909    }
00910 
00911    /* Restore original glPixelStore state */
00912    glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
00913    glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
00914    glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
00915    glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
00916    glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
00917    glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
00918    glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
00919    glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
00920 
00921    return retval;
00922 }
00923 
00924