home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
System
/
Mesa-3.1
/
src-glu
/
mipmap.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-01-05
|
21KB
|
836 lines
/* $Id: mipmap.c,v 1.3.2.1 1999/12/12 17:23:33 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.3.2.1 1999/12/12 17:23:33 brianp
* removed unneeded code in gluBuild1DMipmaps()
*
* Revision 1.3 1999/11/09 06:16:59 brianp
* replace GLint with GLsizei in a gluScaleImage, gluBuild1/2DMipmaps()
*
* 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 <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,
GLsizei widthin, GLsizei heightin,
GLenum typein, const void *datain,
GLsizei widthout, GLsizei 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;
}
#if 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;
}
#endif
/*
* 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,
GLsizei 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 );
return 0;
}
GLint GLAPIENTRY gluBuild2DMipmaps( GLenum target, GLint components,
GLsizei width, GLsizei height, GLenum format,
GLenum type, const void *data )
{
GLint w, h, maxsize;
void *image, *newimage;
GLint neww, newh, level, bpp;
int error;
GLboolean done;
GLint retval = 0;
GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
GLint packrowlength, packalignment, packskiprows, packskippixels;
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;
}
/* 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;
}