This is mipmap.c in view mode; [Download] [Up]
/* $Id: mipmap.c,v 1.4 1997/06/23 00:22:56 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 2.3 * Copyright (C) 1995-1997 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.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 PCH #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 */ #ifdef __WIN32__ void dummy(GLuint j, GLuint k){ } #else #define dummy(J, K) #endif GLint APIENTRY 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: 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! */ sx = (GLfloat) widthin / (GLfloat) widthout; sy = (GLfloat) heightin / (GLfloat) heightout; /*#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 = (i+1) * sy - EPSILON; alpha = i*sy - i0; for (j=0;j<widthout;j++) { j0 = j * sx; 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 = (i+1) * sy - EPSILON; for (j=0;j<widthout;j++) { j0 = j * sx; 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: 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 APIENTRY 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; 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 APIENTRY 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; 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; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.