home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / mesa / src-glu / mipmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-31  |  17.5 KB  |  738 lines

  1. /* $Id: mipmap.c,v 1.5 1997/07/24 01:28:44 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.4
  6.  * Copyright (C) 1995-1997  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * $Log: mipmap.c,v $
  26.  * Revision 1.5  1997/07/24 01:28:44  brianp
  27.  * changed precompiled header symbol from PCH to PC_HEADER
  28.  *
  29.  * Revision 1.4  1997/06/23 00:22:56  brianp
  30.  * added dummy() call to work around an MSVC 4.1 bug
  31.  *
  32.  * Revision 1.3  1997/05/28 02:29:38  brianp
  33.  * added support for precompiled headers (PCH), inserted APIENTRY keyword
  34.  *
  35.  * Revision 1.2  1997/05/24 13:32:25  brianp
  36.  * undef EPSILON in case it's already defined
  37.  *
  38.  * Revision 1.1  1996/09/27 01:19:39  brianp
  39.  * Initial revision
  40.  *
  41.  */
  42.  
  43.  
  44. #ifdef PC_HEADER
  45. #include "all.h"
  46. #else
  47. #include <assert.h>
  48. #include <math.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include "gluP.h"
  52. #endif
  53.  
  54.  
  55. /*
  56.  * Compute ceiling of integer quotient of A divided by B:
  57.  */
  58. #define CEILING( A, B )  ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
  59.  
  60.  
  61.  
  62. #ifdef EPSILON
  63. #undef EPSILON
  64. #endif
  65. #define EPSILON 0.001
  66.  
  67.  
  68. /* To work around optimizer bug in MSVC4.1 */
  69. #ifdef __WIN32__
  70. void dummy(GLuint j, GLuint k){
  71. }
  72. #else
  73. #define dummy(J, K)
  74. #endif
  75.  
  76.  
  77. GLint APIENTRY gluScaleImage( GLenum format,
  78.                               GLint widthin, GLint heightin,
  79.                               GLenum typein, const void *datain,
  80.                               GLint widthout, GLint heightout,
  81.                               GLenum typeout, void *dataout )
  82. {
  83.    GLint components, i, j, k;
  84.    GLfloat *tempin, *tempout;
  85.    GLfloat sx, sy;
  86.    GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
  87.    GLint packrowlength, packalignment, packskiprows, packskippixels;
  88.    GLint sizein, sizeout;
  89.    GLint rowstride, rowlen;
  90.  
  91.  
  92.    /* Determine number of components per pixel */
  93.    switch (format) {
  94.       case GL_COLOR_INDEX:
  95.       case GL_STENCIL_INDEX:
  96.       case GL_DEPTH_COMPONENT:
  97.       case GL_RED:
  98.       case GL_GREEN:
  99.       case GL_BLUE:
  100.       case GL_ALPHA:
  101.       case GL_LUMINANCE:
  102.          components = 1;
  103.      break;
  104.       case GL_LUMINANCE_ALPHA:
  105.      components = 2;
  106.      break;
  107.       case GL_RGB:
  108.      components = 3;
  109.      break;
  110.       case GL_RGBA:
  111.      components = 4;
  112.      break;
  113.       default:
  114.      return GLU_INVALID_ENUM;
  115.    }
  116.  
  117.    /* Determine bytes per input datum */
  118.    switch (typein) {
  119.       case GL_UNSIGNED_BYTE:    sizein = sizeof(GLubyte);    break;
  120.       case GL_BYTE:        sizein = sizeof(GLbyte);    break;
  121.       case GL_UNSIGNED_SHORT:    sizein = sizeof(GLushort);    break;
  122.       case GL_SHORT:        sizein = sizeof(GLshort);    break;
  123.       case GL_UNSIGNED_INT:    sizein = sizeof(GLuint);    break;
  124.       case GL_INT:        sizein = sizeof(GLint);        break;
  125.       case GL_FLOAT:        sizein = sizeof(GLfloat);    break;
  126.       case GL_BITMAP:
  127.      /* not implemented yet */
  128.       default:
  129.      return GL_INVALID_ENUM;
  130.    }
  131.  
  132.    /* Determine bytes per output datum */
  133.    switch (typeout) {
  134.       case GL_UNSIGNED_BYTE:    sizeout = sizeof(GLubyte);    break;
  135.       case GL_BYTE:        sizeout = sizeof(GLbyte);    break;
  136.       case GL_UNSIGNED_SHORT:    sizeout = sizeof(GLushort);    break;
  137.       case GL_SHORT:        sizeout = sizeof(GLshort);    break;
  138.       case GL_UNSIGNED_INT:    sizeout = sizeof(GLuint);    break;
  139.       case GL_INT:        sizeout = sizeof(GLint);    break;
  140.       case GL_FLOAT:        sizeout = sizeof(GLfloat);    break;
  141.       case GL_BITMAP:
  142.      /* not implemented yet */
  143.       default:
  144.      return GL_INVALID_ENUM;
  145.    }
  146.  
  147.    /* Get glPixelStore state */
  148.    glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength );
  149.    glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment );
  150.    glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows );
  151.    glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels );
  152.    glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength );
  153.    glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment );
  154.    glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows );
  155.    glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels );
  156.  
  157.    /* Allocate storage for intermediate images */
  158.    tempin = (GLfloat *) malloc( widthin * heightin
  159.                     * components * sizeof(GLfloat) );
  160.    if (!tempin) {
  161.       return GLU_OUT_OF_MEMORY;
  162.    }
  163.    tempout = (GLfloat *) malloc( widthout * heightout
  164.                       * components * sizeof(GLfloat) );
  165.    if (!tempout) {
  166.       free( tempin );
  167.       return GLU_OUT_OF_MEMORY;
  168.    }
  169.  
  170.  
  171.    /*
  172.     * Unpack the pixel data and convert to floating point
  173.     */
  174.  
  175.    if (unpackrowlength>0) {
  176.       rowlen = unpackrowlength;
  177.    }
  178.    else {
  179.       rowlen = widthin;
  180.    }
  181.    if (sizein >= unpackalignment) {
  182.       rowstride = components * rowlen;
  183.    }
  184.    else {
  185.       rowstride = unpackalignment/sizein
  186.             * CEILING( components * rowlen * sizein, unpackalignment );
  187.    }
  188.  
  189.    switch (typein) {
  190.       case GL_UNSIGNED_BYTE:
  191.      k = 0;
  192.      for (i=0;i<heightin;i++) {
  193.         GLubyte *ubptr = (GLubyte *) datain
  194.                        + i * rowstride
  195.                + unpackskiprows * rowstride
  196.                + unpackskippixels * components;
  197.         for (j=0;j<widthin*components;j++) {
  198.                dummy(j, k);
  199.            tempin[k++] = (GLfloat) *ubptr++;
  200.         }
  201.      }
  202.      break;
  203.       case GL_BYTE:
  204.      k = 0;
  205.      for (i=0;i<heightin;i++) {
  206.         GLbyte *bptr = (GLbyte *) datain
  207.                      + i * rowstride
  208.              + unpackskiprows * rowstride
  209.              + unpackskippixels * components;
  210.         for (j=0;j<widthin*components;j++) {
  211.                dummy(j, k);
  212.            tempin[k++] = (GLfloat) *bptr++;
  213.         }
  214.      }
  215.      break;
  216.       case GL_UNSIGNED_SHORT:
  217.      k = 0;
  218.      for (i=0;i<heightin;i++) {
  219.         GLushort *usptr = (GLushort *) datain
  220.                         + i * rowstride
  221.                 + unpackskiprows * rowstride
  222.                 + unpackskippixels * components;
  223.         for (j=0;j<widthin*components;j++) {
  224.                dummy(j, k);
  225.            tempin[k++] = (GLfloat) *usptr++;
  226.         }
  227.      }
  228.      break;
  229.       case GL_SHORT:
  230.      k = 0;
  231.      for (i=0;i<heightin;i++) {
  232.         GLshort *sptr = (GLshort *) datain
  233.                       + i * rowstride
  234.               + unpackskiprows * rowstride
  235.               + unpackskippixels * components;
  236.         for (j=0;j<widthin*components;j++) {
  237.                dummy(j, k);
  238.            tempin[k++] = (GLfloat) *sptr++;
  239.         }
  240.      }
  241.      break;
  242.       case GL_UNSIGNED_INT:
  243.      k = 0;
  244.      for (i=0;i<heightin;i++) {
  245.         GLuint *uiptr = (GLuint *) datain
  246.                       + i * rowstride
  247.               + unpackskiprows * rowstride
  248.               + unpackskippixels * components;
  249.         for (j=0;j<widthin*components;j++) {
  250.                dummy(j, k);
  251.            tempin[k++] = (GLfloat) *uiptr++;
  252.         }
  253.      }
  254.      break;
  255.       case GL_INT:
  256.      k = 0;
  257.      for (i=0;i<heightin;i++) {
  258.         GLint *iptr = (GLint *) datain
  259.                     + i * rowstride
  260.             + unpackskiprows * rowstride
  261.             + unpackskippixels * components;
  262.         for (j=0;j<widthin*components;j++) {
  263.                dummy(j, k);
  264.            tempin[k++] = (GLfloat) *iptr++;
  265.         }
  266.      }
  267.      break;
  268.       case GL_FLOAT:
  269.      k = 0;
  270.      for (i=0;i<heightin;i++) {
  271.         GLfloat *fptr = (GLfloat *) datain
  272.                       + i * rowstride
  273.               + unpackskiprows * rowstride
  274.               + unpackskippixels * components;
  275.         for (j=0;j<widthin*components;j++) {
  276.                dummy(j, k);
  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.                dummy(j, k+i);
  403.            *ubptr++ = (GLubyte) tempout[k++];
  404.         }
  405.      }
  406.      break;
  407.       case GL_BYTE:
  408.      k = 0;
  409.      for (i=0;i<heightout;i++) {
  410.         GLbyte *bptr = (GLbyte *) dataout
  411.                      + i * rowstride
  412.              + packskiprows * rowstride
  413.              + packskippixels * components;
  414.         for (j=0;j<widthout*components;j++) {
  415.                dummy(j, k+i);
  416.            *bptr++ = (GLbyte) tempout[k++];
  417.         }
  418.      }
  419.      break;
  420.       case GL_UNSIGNED_SHORT:
  421.      k = 0;
  422.      for (i=0;i<heightout;i++) {
  423.         GLushort *usptr = (GLushort *) dataout
  424.                         + i * rowstride
  425.                 + packskiprows * rowstride
  426.                 + packskippixels * components;
  427.         for (j=0;j<widthout*components;j++) {
  428.                dummy(j, k+i);
  429.            *usptr++ = (GLushort) tempout[k++];
  430.         }
  431.      }
  432.      break;
  433.       case GL_SHORT:
  434.      k = 0;
  435.      for (i=0;i<heightout;i++) {
  436.         GLshort *sptr = (GLshort *) dataout
  437.                       + i * rowstride
  438.               + packskiprows * rowstride
  439.               + packskippixels * components;
  440.         for (j=0;j<widthout*components;j++) {
  441.                dummy(j, k+i);
  442.            *sptr++ = (GLshort) tempout[k++];
  443.         }
  444.      }
  445.      break;
  446.       case GL_UNSIGNED_INT:
  447.      k = 0;
  448.      for (i=0;i<heightout;i++) {
  449.         GLuint *uiptr = (GLuint *) dataout
  450.                       + i * rowstride
  451.               + packskiprows * rowstride
  452.               + packskippixels * components;
  453.         for (j=0;j<widthout*components;j++) {
  454.                dummy(j, k+i);
  455.            *uiptr++ = (GLuint) tempout[k++];
  456.         }
  457.      }
  458.      break;
  459.       case GL_INT:
  460.      k = 0;
  461.      for (i=0;i<heightout;i++) {
  462.         GLint *iptr = (GLint *) dataout
  463.                     + i * rowstride
  464.             + packskiprows * rowstride
  465.             + packskippixels * components;
  466.         for (j=0;j<widthout*components;j++) {
  467.                dummy(j, k+i);
  468.            *iptr++ = (GLint) tempout[k++];
  469.         }
  470.      }
  471.      break;
  472.       case GL_FLOAT:
  473.      k = 0;
  474.      for (i=0;i<heightout;i++) {
  475.         GLfloat *fptr = (GLfloat *) dataout
  476.                       + i * rowstride
  477.               + packskiprows * rowstride
  478.               + packskippixels * components;
  479.         for (j=0;j<widthout*components;j++) {
  480.                dummy(j, k+i);
  481.            *fptr++ = tempout[k++];
  482.         }
  483.      }
  484.      break;
  485.       default:
  486.      return GLU_INVALID_ENUM;
  487.    }
  488.  
  489.  
  490.    /* free temporary image storage */
  491.    free( tempin );
  492.    free( tempout );
  493.  
  494.    return 0;
  495. }
  496.  
  497.  
  498.  
  499. /*
  500.  * Return the largest k such that 2^k <= n.
  501.  */
  502. static GLint ilog2( GLint n )
  503. {
  504.    GLint k;
  505.  
  506.    if (n<=0) return 0;
  507.    for (k=0; n>>=1; k++) ;
  508.    return k;
  509. }
  510.  
  511.  
  512.  
  513. /*
  514.  * Find the value nearest to n which is also a power of two.
  515.  */
  516. static GLint round2( GLint n )
  517. {
  518.    GLint m;
  519.  
  520.    for (m=1; m<n; m*=2)
  521.      ;
  522.  
  523.    /* m>=n */
  524.    if (m-n <= n-m/2) {
  525.       return m;
  526.    }
  527.    else {
  528.       return m/2;
  529.    }
  530. }
  531.  
  532.  
  533. /*
  534.  * Given an pixel format and datatype, return the number of bytes to
  535.  * store one pixel.
  536.  */
  537. static GLint bytes_per_pixel( GLenum format, GLenum type )
  538. {
  539.    GLint n, m;
  540.  
  541.    switch (format) {
  542.       case GL_COLOR_INDEX:
  543.       case GL_STENCIL_INDEX:
  544.       case GL_DEPTH_COMPONENT:
  545.       case GL_RED:
  546.       case GL_GREEN:
  547.       case GL_BLUE:
  548.       case GL_ALPHA:
  549.       case GL_LUMINANCE:
  550.      n = 1;
  551.      break;
  552.       case GL_LUMINANCE_ALPHA:
  553.      n = 2;
  554.      break;
  555.       case GL_RGB:
  556.      n = 3;
  557.      break;
  558.       case GL_RGBA:
  559.      n = 4;
  560.      break;
  561.       default:
  562.      n = 0;
  563.    }
  564.  
  565.    switch (type) {
  566.       case GL_UNSIGNED_BYTE:    m = sizeof(GLubyte);    break;
  567.       case GL_BYTE:        m = sizeof(GLbyte);    break;
  568.       case GL_BITMAP:        m = 1;            break;
  569.       case GL_UNSIGNED_SHORT:    m = sizeof(GLushort);    break;
  570.       case GL_SHORT:        m = sizeof(GLshort);    break;
  571.       case GL_UNSIGNED_INT:    m = sizeof(GLuint);    break;
  572.       case GL_INT:        m = sizeof(GLint);    break;
  573.       case GL_FLOAT:        m = sizeof(GLfloat);    break;
  574.       default:            m = 0;
  575.    }
  576.  
  577.    return n * m;
  578. }
  579.  
  580.  
  581.  
  582. /*
  583.  * WARNING: This function isn't finished and has never been tested!!!!
  584.  */
  585. GLint APIENTRY gluBuild1DMipmaps( GLenum target, GLint components,
  586.                                   GLint width, GLenum format,
  587.                                   GLenum type, const void *data )
  588. {
  589.    GLubyte *texture;
  590.    GLint levels, max_levels;
  591.    GLint new_width, max_width;
  592.    GLint i, j, k, l;
  593.  
  594.    glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width );
  595.    max_levels = ilog2( max_width ) + 1;
  596.  
  597.    /* Compute how many mipmap images to make */
  598.    levels = ilog2( width ) + 1;
  599.    if (levels>max_levels) {
  600.       levels = max_levels;
  601.    }
  602.  
  603.    new_width = 1 << (levels-1);
  604.  
  605.    texture = (GLubyte *) malloc( new_width * components );
  606.    if (!texture) {
  607.       return GLU_OUT_OF_MEMORY;
  608.    }
  609.  
  610.    if (width != new_width) {
  611.       /* initial rescaling */
  612.       switch (type) {
  613.      case GL_UNSIGNED_BYTE:
  614.         {
  615.            GLubyte *ub_data = (GLubyte *) data;
  616.            for (i=0;i<new_width;i++) {
  617.           j = i * width / new_width;
  618.           for (k=0;k<components;k++) {
  619.              texture[i*components+k] = ub_data[j*components+k];
  620.           }
  621.            }
  622.         }
  623.         break;
  624.      default:
  625.         /* Not implemented */
  626.         return GLU_ERROR;
  627.       }
  628.    }
  629.  
  630.    /* generate and load mipmap images */
  631.    for (l=0;l<levels;l++) {
  632.       glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0,
  633.             format, GL_UNSIGNED_BYTE, texture );
  634.  
  635.       /* Scale image down to 1/2 size */
  636.       new_width = new_width / 2;
  637.       for (i=0;i<new_width;i++) {
  638.      for (k=0;k<components;k++) {
  639.         GLint sample1, sample2;
  640.         sample1 = (GLint) texture[i*2*components+k];
  641.         sample2 = (GLint) texture[(i*2+1)*components+k];
  642.         texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2);
  643.      }
  644.       }
  645.    }
  646.  
  647.    free( texture );
  648.  
  649.    /* make sure remaining mipmap levels are removed */
  650.    for (l=levels;l<max_levels;l++) {
  651.       glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0,
  652.             format, GL_UNSIGNED_BYTE, NULL );
  653.    }
  654.  
  655.    return 0;
  656. }
  657.  
  658.  
  659.  
  660. GLint APIENTRY gluBuild2DMipmaps( GLenum target, GLint components,
  661.                                   GLint width, GLint height, GLenum format,
  662.                                   GLenum type, const void *data )
  663. {
  664.    GLint w, h, maxsize;
  665.    void *image, *newimage;
  666.    GLint neww, newh, level, bpp;
  667.    int error;
  668.  
  669.    glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize );
  670.  
  671.    w = round2( width );
  672.    if (w>maxsize) {
  673.       w = maxsize;
  674.    }
  675.    h = round2( height );
  676.    if (h>maxsize) {
  677.       h = maxsize;
  678.    }
  679.  
  680.    bpp = bytes_per_pixel( format, type );
  681.    if (bpp==0) {
  682.       /* probably a bad format or type enum */
  683.       return GLU_INVALID_ENUM;
  684.    }
  685.  
  686.    if (w!=width || h!=height) {
  687.       /* must rescale image to get "top" mipmap texture image */
  688.       image = malloc( (w+4) * h * bpp );
  689.       if (!image) {
  690.      return GLU_OUT_OF_MEMORY;
  691.       }
  692.       error = gluScaleImage( format, width, height, type, data,
  693.                  w, h, type, image );
  694.       if (error) {
  695.      return error;
  696.       }
  697.    }
  698.    else {
  699.       image = (void *) data;
  700.    }
  701.  
  702.    level = 0;
  703.    while (1) {
  704.       glTexImage2D( target, level, components, w, h, 0, format, type, image );
  705.  
  706.       if (w==1 && h==1)  break;
  707.  
  708.       neww = (w<2) ? 1 : w/2;
  709.       newh = (h<2) ? 1 : h/2;
  710.       newimage = malloc( (neww+4) * newh * bpp );
  711.       if (!newimage) {
  712.      return GLU_OUT_OF_MEMORY;
  713.       }
  714.  
  715.       error =  gluScaleImage( format, w, h, type, image,
  716.                   neww, newh, type, newimage );
  717.       if (error) {
  718.      return error;
  719.       }
  720.  
  721.       if (image!=data) {
  722.      free( image );
  723.       }
  724.       image = newimage;
  725.  
  726.       w = neww;
  727.       h = newh;
  728.       level++;
  729.    }
  730.  
  731.    if (image!=data) {
  732.       free( image );
  733.    }
  734.  
  735.    return 0;
  736. }
  737.  
  738.