/* $Id: mipmap.c,v 1.2 1999/09/14 00:30:28 brianp 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.2 1999/09/14 00:30:28 brianp * fixed pixel packing/unpacking code in gluBuild2DMipmaps() * * Revision 1.1.1.1 1999/08/19 00:55:42 jtg * Imported sources * * Revision 1.13 1999/03/05 17:49:06 brianp * added support for GL_EXT_abgr (devernay@istar.fr) * * 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 #include #include #include #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 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= heightin) i1 = heightin-1; /* i1 = (i+1) * sy - EPSILON;*/ alpha = i*sy - i0; for (j=0;j= 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= heightin) i1 = heightin-1; /* i1 = (i+1) * sy - EPSILON; */ for (j=0;j= 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;k0) { 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>=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 */ 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;imaxsize) { 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; } /* Get current glPixelStore values */ 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 ); /* set pixel packing */ glPixelStorei( GL_PACK_ROW_LENGTH, 0 ); glPixelStorei( GL_PACK_ALIGNMENT, 1 ); glPixelStorei( GL_PACK_SKIP_ROWS, 0 ); glPixelStorei( GL_PACK_SKIP_PIXELS, 0 ); done = GL_FALSE; 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) { retval = error; done = GL_TRUE; } } else { image = (void *) data; } level = 0; while (!done) { if (image != data) { /* set pixel unpacking */ glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); } 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) { retval = error; done = GL_TRUE; } if (image!=data) { free( image ); } image = newimage; w = neww; h = newh; level++; } if (image!=data) { free( image ); } /* Restore original glPixelStore state */ glPixelStorei( GL_UNPACK_ROW_LENGTH, unpackrowlength ); glPixelStorei( GL_UNPACK_ALIGNMENT, unpackalignment ); glPixelStorei( GL_UNPACK_SKIP_ROWS, unpackskiprows ); glPixelStorei( GL_UNPACK_SKIP_PIXELS, unpackskippixels ); glPixelStorei( GL_PACK_ROW_LENGTH, packrowlength ); glPixelStorei( GL_PACK_ALIGNMENT, packalignment ); glPixelStorei( GL_PACK_SKIP_ROWS, packskiprows ); glPixelStorei( GL_PACK_SKIP_PIXELS, packskippixels ); return retval; }