diff options
author | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
---|---|---|
committer | jtg <jtg> | 1999-08-19 00:55:39 +0000 |
commit | afb833d4e89c312460a4ab9ed6a7a8ca4ebbfe1c (patch) | |
tree | 59d65b4da12fb5379224cf5f6b808fde91523c7f /src/glu/mesa/mipmap.c | |
parent | f2544d4920ce168bec9cd94d774b7ea5103a3d74 (diff) |
Initial revision
Diffstat (limited to 'src/glu/mesa/mipmap.c')
-rw-r--r-- | src/glu/mesa/mipmap.c | 790 |
1 files changed, 790 insertions, 0 deletions
diff --git a/src/glu/mesa/mipmap.c b/src/glu/mesa/mipmap.c new file mode 100644 index 00000000000..24af0ba33c0 --- /dev/null +++ b/src/glu/mesa/mipmap.c @@ -0,0 +1,790 @@ +/* $Id: mipmap.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */ + +/* + * Mesa 3-D graphics library + * Version: 3.1 + * Copyright (C) 1995-1999 Brian Paul + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * $Log: mipmap.c,v $ + * Revision 1.1 1999/08/19 00:55:42 jtg + * Initial revision + * + * Revision 1.13 1999/03/05 17:49:06 brianp + * added support for GL_EXT_abgr ([email protected]) + * + * Revision 1.12 1999/01/03 03:23:15 brianp + * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump) + * + * Revision 1.11 1998/09/18 02:44:03 brianp + * further changes to gluScaleImage() per Randy Frank + * + * Revision 1.10 1998/09/17 03:20:26 brianp + * fixed another bug in gluScaleImage() per Sven Panne + * + * Revision 1.9 1998/07/31 03:06:20 brianp + * tweaked the gluScaleImage() function per Randy Frank + * + * Revision 1.8 1998/07/08 01:02:53 brianp + * if gluBuildxDMipmaps() width or height <= 0 return GLU_INVALID_VALUE + * + * Revision 1.7 1998/07/01 00:18:02 brianp + * if gluBuildxDMipmaps() width or height <= 0 just return 0 + * + * Revision 1.6 1998/06/01 01:06:41 brianp + * small update for Next/OpenStep from Alexander Mai + * + * Revision 1.5 1997/07/24 01:28:44 brianp + * changed precompiled header symbol from PCH to PC_HEADER + * + * Revision 1.4 1997/06/23 00:22:56 brianp + * added dummy() call to work around an MSVC 4.1 bug + * + * Revision 1.3 1997/05/28 02:29:38 brianp + * added support for precompiled headers (PCH), inserted APIENTRY keyword + * + * Revision 1.2 1997/05/24 13:32:25 brianp + * undef EPSILON in case it's already defined + * + * Revision 1.1 1996/09/27 01:19:39 brianp + * Initial revision + * + */ + + +#ifdef PC_HEADER +#include "all.h" +#else +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "gluP.h" +#endif + + +/* + * Compute ceiling of integer quotient of A divided by B: + */ +#define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) + + + +#ifdef EPSILON +#undef EPSILON +#endif +#define EPSILON 0.001 + + +/* To work around optimizer bug in MSVC4.1 */ +#if defined(__WIN32__) && !defined(OPENSTEP) +void dummy(GLuint j, GLuint k){ +} +#else +#define dummy(J, K) +#endif + + +GLint GLAPIENTRY gluScaleImage( GLenum format, + GLint widthin, GLint heightin, + GLenum typein, const void *datain, + GLint widthout, GLint heightout, + GLenum typeout, void *dataout ) +{ + GLint components, i, j, k; + GLfloat *tempin, *tempout; + GLfloat sx, sy; + GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels; + GLint packrowlength, packalignment, packskiprows, packskippixels; + GLint sizein, sizeout; + GLint rowstride, rowlen; + + + /* Determine number of components per pixel */ + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + components = 1; + break; + case GL_LUMINANCE_ALPHA: + components = 2; + break; + case GL_RGB: + components = 3; + break; + case GL_RGBA: +#ifdef GL_EXT_abgr + case GL_ABGR_EXT: +#endif + components = 4; + break; + default: + return GLU_INVALID_ENUM; + } + + /* Determine bytes per input datum */ + switch (typein) { + case GL_UNSIGNED_BYTE: sizein = sizeof(GLubyte); break; + case GL_BYTE: sizein = sizeof(GLbyte); break; + case GL_UNSIGNED_SHORT: sizein = sizeof(GLushort); break; + case GL_SHORT: sizein = sizeof(GLshort); break; + case GL_UNSIGNED_INT: sizein = sizeof(GLuint); break; + case GL_INT: sizein = sizeof(GLint); break; + case GL_FLOAT: sizein = sizeof(GLfloat); break; + case GL_BITMAP: + /* not implemented yet */ + default: + return GL_INVALID_ENUM; + } + + /* Determine bytes per output datum */ + switch (typeout) { + case GL_UNSIGNED_BYTE: sizeout = sizeof(GLubyte); break; + case GL_BYTE: sizeout = sizeof(GLbyte); break; + case GL_UNSIGNED_SHORT: sizeout = sizeof(GLushort); break; + case GL_SHORT: sizeout = sizeof(GLshort); break; + case GL_UNSIGNED_INT: sizeout = sizeof(GLuint); break; + case GL_INT: sizeout = sizeof(GLint); break; + case GL_FLOAT: sizeout = sizeof(GLfloat); break; + case GL_BITMAP: + /* not implemented yet */ + default: + return GL_INVALID_ENUM; + } + + /* Get glPixelStore state */ + glGetIntegerv( GL_UNPACK_ROW_LENGTH, &unpackrowlength ); + glGetIntegerv( GL_UNPACK_ALIGNMENT, &unpackalignment ); + glGetIntegerv( GL_UNPACK_SKIP_ROWS, &unpackskiprows ); + glGetIntegerv( GL_UNPACK_SKIP_PIXELS, &unpackskippixels ); + glGetIntegerv( GL_PACK_ROW_LENGTH, &packrowlength ); + glGetIntegerv( GL_PACK_ALIGNMENT, &packalignment ); + glGetIntegerv( GL_PACK_SKIP_ROWS, &packskiprows ); + glGetIntegerv( GL_PACK_SKIP_PIXELS, &packskippixels ); + + /* Allocate storage for intermediate images */ + tempin = (GLfloat *) malloc( widthin * heightin + * components * sizeof(GLfloat) ); + if (!tempin) { + return GLU_OUT_OF_MEMORY; + } + tempout = (GLfloat *) malloc( widthout * heightout + * components * sizeof(GLfloat) ); + if (!tempout) { + free( tempin ); + return GLU_OUT_OF_MEMORY; + } + + + /* + * Unpack the pixel data and convert to floating point + */ + + if (unpackrowlength>0) { + rowlen = unpackrowlength; + } + else { + rowlen = widthin; + } + if (sizein >= unpackalignment) { + rowstride = components * rowlen; + } + else { + rowstride = unpackalignment/sizein + * CEILING( components * rowlen * sizein, unpackalignment ); + } + + switch (typein) { + case GL_UNSIGNED_BYTE: + k = 0; + for (i=0;i<heightin;i++) { + GLubyte *ubptr = (GLubyte *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *ubptr++; + } + } + break; + case GL_BYTE: + k = 0; + for (i=0;i<heightin;i++) { + GLbyte *bptr = (GLbyte *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *bptr++; + } + } + break; + case GL_UNSIGNED_SHORT: + k = 0; + for (i=0;i<heightin;i++) { + GLushort *usptr = (GLushort *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *usptr++; + } + } + break; + case GL_SHORT: + k = 0; + for (i=0;i<heightin;i++) { + GLshort *sptr = (GLshort *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *sptr++; + } + } + break; + case GL_UNSIGNED_INT: + k = 0; + for (i=0;i<heightin;i++) { + GLuint *uiptr = (GLuint *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *uiptr++; + } + } + break; + case GL_INT: + k = 0; + for (i=0;i<heightin;i++) { + GLint *iptr = (GLint *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = (GLfloat) *iptr++; + } + } + break; + case GL_FLOAT: + k = 0; + for (i=0;i<heightin;i++) { + GLfloat *fptr = (GLfloat *) datain + + i * rowstride + + unpackskiprows * rowstride + + unpackskippixels * components; + for (j=0;j<widthin*components;j++) { + dummy(j, k); + tempin[k++] = *fptr++; + } + } + break; + default: + return GLU_INVALID_ENUM; + } + + + /* + * Scale the image! + */ + + if (widthout > 1) + sx = (GLfloat) (widthin-1) / (GLfloat) (widthout-1); + else + sx = (GLfloat) (widthin-1); + if (heightout > 1) + sy = (GLfloat) (heightin-1) / (GLfloat) (heightout-1); + else + sy = (GLfloat) (heightin-1); + +/*#define POINT_SAMPLE*/ +#ifdef POINT_SAMPLE + for (i=0;i<heightout;i++) { + GLint ii = i * sy; + for (j=0;j<widthout;j++) { + GLint jj = j * sx; + + GLfloat *src = tempin + (ii * widthin + jj) * components; + GLfloat *dst = tempout + (i * widthout + j) * components; + + for (k=0;k<components;k++) { + *dst++ = *src++; + } + } + } +#else + if (sx<1.0 && sy<1.0) { + /* magnify both width and height: use weighted sample of 4 pixels */ + GLint i0, i1, j0, j1; + GLfloat alpha, beta; + GLfloat *src00, *src01, *src10, *src11; + GLfloat s1, s2; + GLfloat *dst; + + for (i=0;i<heightout;i++) { + i0 = i * sy; + i1 = i0 + 1; + if (i1 >= heightin) i1 = heightin-1; +/* i1 = (i+1) * sy - EPSILON;*/ + alpha = i*sy - i0; + for (j=0;j<widthout;j++) { + j0 = j * sx; + j1 = j0 + 1; + if (j1 >= widthin) j1 = widthin-1; +/* j1 = (j+1) * sx - EPSILON; */ + beta = j*sx - j0; + + /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */ + src00 = tempin + (i0 * widthin + j0) * components; + src01 = tempin + (i0 * widthin + j1) * components; + src10 = tempin + (i1 * widthin + j0) * components; + src11 = tempin + (i1 * widthin + j1) * components; + + dst = tempout + (i * widthout + j) * components; + + for (k=0;k<components;k++) { + s1 = *src00++ * (1.0-beta) + *src01++ * beta; + s2 = *src10++ * (1.0-beta) + *src11++ * beta; + *dst++ = s1 * (1.0-alpha) + s2 * alpha; + } + } + } + } + else { + /* shrink width and/or height: use an unweighted box filter */ + GLint i0, i1; + GLint j0, j1; + GLint ii, jj; + GLfloat sum, *dst; + + for (i=0;i<heightout;i++) { + i0 = i * sy; + i1 = i0 + 1; + if (i1 >= heightin) i1 = heightin-1; +/* i1 = (i+1) * sy - EPSILON; */ + for (j=0;j<widthout;j++) { + j0 = j * sx; + j1 = j0 + 1; + if (j1 >= widthin) j1 = widthin-1; +/* j1 = (j+1) * sx - EPSILON; */ + + dst = tempout + (i * widthout + j) * components; + + /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */ + for (k=0;k<components;k++) { + sum = 0.0; + for (ii=i0;ii<=i1;ii++) { + for (jj=j0;jj<=j1;jj++) { + sum += *(tempin + (ii * widthin + jj) * components + k); + } + } + sum /= (j1-j0+1) * (i1-i0+1); + *dst++ = sum; + } + } + } + } +#endif + + + /* + * Return output image + */ + + if (packrowlength>0) { + rowlen = packrowlength; + } + else { + rowlen = widthout; + } + if (sizeout >= packalignment) { + rowstride = components * rowlen; + } + else { + rowstride = packalignment/sizeout + * CEILING( components * rowlen * sizeout, packalignment ); + } + + switch (typeout) { + case GL_UNSIGNED_BYTE: + k = 0; + for (i=0;i<heightout;i++) { + GLubyte *ubptr = (GLubyte *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *ubptr++ = (GLubyte) tempout[k++]; + } + } + break; + case GL_BYTE: + k = 0; + for (i=0;i<heightout;i++) { + GLbyte *bptr = (GLbyte *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *bptr++ = (GLbyte) tempout[k++]; + } + } + break; + case GL_UNSIGNED_SHORT: + k = 0; + for (i=0;i<heightout;i++) { + GLushort *usptr = (GLushort *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *usptr++ = (GLushort) tempout[k++]; + } + } + break; + case GL_SHORT: + k = 0; + for (i=0;i<heightout;i++) { + GLshort *sptr = (GLshort *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *sptr++ = (GLshort) tempout[k++]; + } + } + break; + case GL_UNSIGNED_INT: + k = 0; + for (i=0;i<heightout;i++) { + GLuint *uiptr = (GLuint *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *uiptr++ = (GLuint) tempout[k++]; + } + } + break; + case GL_INT: + k = 0; + for (i=0;i<heightout;i++) { + GLint *iptr = (GLint *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *iptr++ = (GLint) tempout[k++]; + } + } + break; + case GL_FLOAT: + k = 0; + for (i=0;i<heightout;i++) { + GLfloat *fptr = (GLfloat *) dataout + + i * rowstride + + packskiprows * rowstride + + packskippixels * components; + for (j=0;j<widthout*components;j++) { + dummy(j, k+i); + *fptr++ = tempout[k++]; + } + } + break; + default: + return GLU_INVALID_ENUM; + } + + + /* free temporary image storage */ + free( tempin ); + free( tempout ); + + return 0; +} + + + +/* + * Return the largest k such that 2^k <= n. + */ +static GLint ilog2( GLint n ) +{ + GLint k; + + if (n<=0) return 0; + for (k=0; n>>=1; k++) ; + return k; +} + + + +/* + * Find the value nearest to n which is also a power of two. + */ +static GLint round2( GLint n ) +{ + GLint m; + + for (m=1; m<n; m*=2) + ; + + /* m>=n */ + if (m-n <= n-m/2) { + return m; + } + else { + return m/2; + } +} + + +/* + * Given an pixel format and datatype, return the number of bytes to + * store one pixel. + */ +static GLint bytes_per_pixel( GLenum format, GLenum type ) +{ + GLint n, m; + + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + n = 1; + break; + case GL_LUMINANCE_ALPHA: + n = 2; + break; + case GL_RGB: + n = 3; + break; + case GL_RGBA: +#ifdef GL_EXT_abgr + case GL_ABGR_EXT: +#endif + n = 4; + break; + default: + n = 0; + } + + switch (type) { + case GL_UNSIGNED_BYTE: m = sizeof(GLubyte); break; + case GL_BYTE: m = sizeof(GLbyte); break; + case GL_BITMAP: m = 1; break; + case GL_UNSIGNED_SHORT: m = sizeof(GLushort); break; + case GL_SHORT: m = sizeof(GLshort); break; + case GL_UNSIGNED_INT: m = sizeof(GLuint); break; + case GL_INT: m = sizeof(GLint); break; + case GL_FLOAT: m = sizeof(GLfloat); break; + default: m = 0; + } + + return n * m; +} + + + +/* + * WARNING: This function isn't finished and has never been tested!!!! + */ +GLint GLAPIENTRY gluBuild1DMipmaps( GLenum target, GLint components, + GLint width, GLenum format, + GLenum type, const void *data ) +{ + GLubyte *texture; + GLint levels, max_levels; + GLint new_width, max_width; + GLint i, j, k, l; + + if (width < 1) + return GLU_INVALID_VALUE; + + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max_width ); + max_levels = ilog2( max_width ) + 1; + + /* Compute how many mipmap images to make */ + levels = ilog2( width ) + 1; + if (levels>max_levels) { + levels = max_levels; + } + + new_width = 1 << (levels-1); + + texture = (GLubyte *) malloc( new_width * components ); + if (!texture) { + return GLU_OUT_OF_MEMORY; + } + + if (width != new_width) { + /* initial rescaling */ + switch (type) { + case GL_UNSIGNED_BYTE: + { + GLubyte *ub_data = (GLubyte *) data; + for (i=0;i<new_width;i++) { + j = i * width / new_width; + for (k=0;k<components;k++) { + texture[i*components+k] = ub_data[j*components+k]; + } + } + } + break; + default: + /* Not implemented */ + return GLU_ERROR; + } + } + + /* generate and load mipmap images */ + for (l=0;l<levels;l++) { + glTexImage1D( GL_TEXTURE_1D, l, components, new_width, 0, + format, GL_UNSIGNED_BYTE, texture ); + + /* Scale image down to 1/2 size */ + new_width = new_width / 2; + for (i=0;i<new_width;i++) { + for (k=0;k<components;k++) { + GLint sample1, sample2; + sample1 = (GLint) texture[i*2*components+k]; + sample2 = (GLint) texture[(i*2+1)*components+k]; + texture[i*components+k] = (GLubyte) ((sample1 + sample2) / 2); + } + } + } + + free( texture ); + + /* make sure remaining mipmap levels are removed */ + for (l=levels;l<max_levels;l++) { + glTexImage1D( GL_TEXTURE_1D, l, components, 0, 0, + format, GL_UNSIGNED_BYTE, NULL ); + } + + return 0; +} + + + +GLint GLAPIENTRY gluBuild2DMipmaps( GLenum target, GLint components, + GLint width, GLint height, GLenum format, + GLenum type, const void *data ) +{ + GLint w, h, maxsize; + void *image, *newimage; + GLint neww, newh, level, bpp; + int error; + + if (width < 1 || height < 1) + return GLU_INVALID_VALUE; + + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxsize ); + + w = round2( width ); + if (w>maxsize) { + w = maxsize; + } + h = round2( height ); + if (h>maxsize) { + h = maxsize; + } + + bpp = bytes_per_pixel( format, type ); + if (bpp==0) { + /* probably a bad format or type enum */ + return GLU_INVALID_ENUM; + } + + if (w!=width || h!=height) { + /* must rescale image to get "top" mipmap texture image */ + image = malloc( (w+4) * h * bpp ); + if (!image) { + return GLU_OUT_OF_MEMORY; + } + error = gluScaleImage( format, width, height, type, data, + w, h, type, image ); + if (error) { + return error; + } + } + else { + image = (void *) data; + } + + level = 0; + while (1) { + glTexImage2D( target, level, components, w, h, 0, format, type, image ); + + if (w==1 && h==1) break; + + neww = (w<2) ? 1 : w/2; + newh = (h<2) ? 1 : h/2; + newimage = malloc( (neww+4) * newh * bpp ); + if (!newimage) { + return GLU_OUT_OF_MEMORY; + } + + error = gluScaleImage( format, w, h, type, image, + neww, newh, type, newimage ); + if (error) { + return error; + } + + if (image!=data) { + free( image ); + } + image = newimage; + + w = neww; + h = newh; + level++; + } + + if (image!=data) { + free( image ); + } + + return 0; +} + |