#include "glt_texture.h" /*! \file \ingroup GLT $Id: texture.cpp,v 1.26 2002/10/09 15:09:38 nigels Exp $ $Log: texture.cpp,v $ Revision 1.26 2002/10/09 15:09:38 nigels Added RCS Id and Log tags */ #include "glt_gl.h" #include "glt_glu.h" #include "glt_error.h" //#include "glt_compress.h" //#include "glt_image.h" #if !defined(NDEBUG) #include #endif #include #include #include using namespace std; ////////////////////////////////////////////////////////////////////////// GltTexture::GltTexture(const GLenum target) : _target(target), _components(0), _width(0), _height(0), _border(0), _format(0), _type(0), _alignment(0), _wrapS(GL_REPEAT), _wrapT(GL_REPEAT), _filterMin(GL_LINEAR), _filterMag(GL_LINEAR), _gamma(1.0), _hue(0.0), _saturation(0.0), _value(0.0), _id(0) { } GltTexture::GltTexture(const GltTexture &) { // Can't copy textures assert(0); } GltTexture::~GltTexture() { #if !defined(NDEBUG) if (_id) cerr << "WARNING: Potential OpenGL texture leak (" << this << ")" << endl; #endif clear(); } GltTexture & GltTexture::operator=(const GltTexture &) { // Can't copy textures assert(0); return *this; } void GltTexture::setWrap(const GLenum s,const GLenum t) { _wrapS = s; _wrapT = t; if (_id!=0) { glPushAttrib(GL_TEXTURE_BIT); glBindTexture(_target,_id); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,_wrapS); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,_wrapT); glPopAttrib(); } } void GltTexture::setFilter(const GLenum min,const GLenum mag) { _filterMin = min; _filterMag = mag; if (_id!=0) { glPushAttrib(GL_TEXTURE_BIT); glBindTexture(_target,_id); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,_filterMin); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,_filterMag); glPopAttrib(); } } void GltTexture::setGamma(const real gamma) { _gamma = gamma; } void GltTexture::setHSVAdjust(const real hue,const real saturation,const real value) { _hue = hue; _saturation = saturation; _value = value; } #if 0 bool GltTexture::init(const void *data,const bool mipmap) { GLERROR clear(); if (!data) return true; // Extract the header int type,width,height,alignment,compressed; void *pixels = getHeader((const byte *) data,type,width,height,alignment,compressed); bool deletePixels = false; // If the header is valid, initialise texture assert(pixels); if (pixels) { switch (type) { case TEXTURE_TYPE_RGB: _components = 3; _format = GL_RGB; break; case TEXTURE_TYPE_RGBA: _components = 4; _format = GL_RGBA; break; case TEXTURE_TYPE_GREY: _components = 1; _format = GL_LUMINANCE; break; case TEXTURE_TYPE_GREYA: _components = 2; _format = GL_LUMINANCE_ALPHA; break; case TEXTURE_TYPE_ALPHA: _components = 1; _format = GL_ALPHA; break; case TEXTURE_TYPE_BITMAP: _components = 1; _format = TEXTURE_TYPE_BITMAP;break; case TEXTURE_TYPE_INDEXED_RGB: _components = 3; _format = GL_RGB; break; case TEXTURE_TYPE_INDEXED_RGBA: _components = 4; _format = GL_RGBA; break; default: assert(0); break; } if (compressed) { string tmp; bool ok = decompress(tmp,pixels); assert(ok); assert(tmp.size()); if (ok && tmp.size()) { const int n = width*height*_components; pixels = new unsigned char[n]; deletePixels = true; if (type==TEXTURE_TYPE_INDEXED_RGB) { string rgb; indexed2rgb(rgb,tmp); if (_gamma!=1.0) adjustGamma(rgb,_gamma); if (_hue!=0.0 || _saturation!=0.0 || _value!=0.0) adjustHSV(rgb,width,height,_hue,_saturation,_value); memcpy(pixels,rgb.c_str(),n); /* TODO - Deal with indexed data */ } else { if (_gamma!=1.0) adjustGamma(tmp,_gamma); if (_hue!=0.0 || _saturation!=0.0 || _value!=0.0) adjustHSV(tmp,width,height,_hue,_saturation,_value); memcpy(pixels,tmp.c_str(),n); } } } /* TODO - Deal with uncompressed indexed data */ _width = width; _height = height; _type = GL_UNSIGNED_BYTE; } assert(_components!=0); if (pixels && _components!=0) { GLERROR if (_target==GL_TEXTURE_2D) { glGenTextures(1,&_id); glBindTexture(GL_TEXTURE_2D,_id); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,_filterMin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,_filterMag); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _wrapT); } if (mipmap) gluBuild2DMipmaps(_target,_components,_width,_height,_format,_type,pixels); else glTexImage2D(_target,0,_components,_width,_height,_border,_format,_type,pixels); if (deletePixels) delete [] (unsigned char *) pixels; GLERROR return true; } GLERROR return false; } bool GltTexture::init(const GLsizei width,const GLsizei height,const std::string &image,const bool mipmap) { clear(); GLenum mode = 0; int channels = 0; if (width*height == (GLsizei)image.size()) { mode = GL_LUMINANCE; channels = 1; } if (width*height*2== (GLsizei)image.size()) { mode = GL_LUMINANCE_ALPHA; channels = 2; } if (width*height*3== (GLsizei)image.size()) { mode = GL_RGB; channels = 3; } if (width*height*4== (GLsizei)image.size()) { mode = GL_RGBA; channels = 3; } if (!mode || !channels) return false; if (_target==GL_TEXTURE_2D) { glGenTextures(1,&_id); glBindTexture(GL_TEXTURE_2D,_id); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,_filterMin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,_filterMag); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _wrapT); } if (mipmap) gluBuild2DMipmaps(_target,channels,width,height,mode,GL_UNSIGNED_BYTE,image.data()); else glTexImage2D(_target,0,channels,width,height,0,mode,GL_UNSIGNED_BYTE,image.data()); return true; } #endif bool GltTexture::init(const GLsizei width,const GLsizei height,const byte *image,const GLsizei channels,const bool mipmap) { clear(); GLenum mode = 0; switch (channels) { case 1: mode = GL_LUMINANCE; break; case 2: mode = GL_LUMINANCE_ALPHA; break; case 3: mode = GL_RGB; break; case 4: mode = GL_RGBA; break; default: return false; } if (_target==GL_TEXTURE_2D) { glGenTextures(1,&_id); glBindTexture(GL_TEXTURE_2D,_id); glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,_filterMin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,_filterMag); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _wrapS); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _wrapT); } if (mipmap) gluBuild2DMipmaps(_target,channels,width,height,mode,GL_UNSIGNED_BYTE,image); else glTexImage2D(_target,0,channels,width,height,0,mode,GL_UNSIGNED_BYTE,image); return true; } void GltTexture::clear() { if (_id) glDeleteTextures(1,&_id); _id = 0; _components = 0; _width = 0; _height = 0; _border = 0; _format = 0; _type = 0; _alignment = 0; } void GltTexture::set() const { if (_id!=0 && _target==GL_TEXTURE_2D) glBindTexture(_target,_id); } const GLsizei &GltTexture::width() const { return _width; } const GLsizei &GltTexture::height() const { return _height; } const GLuint GltTexture::id() const { return _id; } //////////////////////////////////////////////////////////////////////////// // Create variable-length header for texture data bool GltTexture::makeHeader ( string &header, const int type, const int width, const int height, const int alignment, const int compressed ) { // 11 characters is big enough for integer 2^32 + \0 char buffer[5+11+11+11+11+11]; sprintf(buffer,"GLTT %u %u %u %u %u",type,width,height,alignment,compressed); header = buffer; header += '\0'; return true; } // Decode variable-length header for texture data void *GltTexture::getHeader ( const void * const data, int &type, int &width, int &height, int &alignment, int &compressed ) { const char * const h = (const char * const) data; if (h[0]=='G' && h[1]=='L' && h[2]=='T' && h[3]=='T' && h[4]==' ') { if (sscanf(h+5,"%i %i %i %i %i",&type,&width,&height,&alignment,&compressed)==5) return (void *) (h + strlen(h) + 1); } return NULL; }