home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / mesa-1.2.8 / src-glu / mipmap.c < prev    next >
C/C++ Source or Header  |  1996-05-27  |  18KB  |  731 lines

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