Texture.cpp

Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /////////////////////////////////////////////////////////////////////////////
00003 //
00004 // Texture.cpp -- Copyright (c) 2006-2007 David Henry
00005 // last modification: may. 7, 2007
00006 //
00007 // This code is licenced under the MIT license.
00008 //
00009 // This software is provided "as is" without express or implied
00010 // warranties. You may freely copy and compile this source into
00011 // applications you distribute provided that the copyright text
00012 // below is included in the resulting source code.
00013 //
00014 // Implementation of an OpenGL texture classes.
00015 //
00016 /////////////////////////////////////////////////////////////////////////////
00017 
00018 #ifdef _WIN32
00019 #define WIN32_LEAN_AND_MEAN
00020 #include <windows.h>
00021 #endif // _WIN32
00022 
00023 #include <GL/glew.h>
00024 #include <GL/gl.h>
00025 #include <GL/glu.h>
00026 #include <iostream>
00027 #include <stdexcept>
00028 
00029 #include "Texture.h"
00030 #include "Image.h"
00031 
00032 using std::cout;
00033 using std::cerr;
00034 using std::endl;
00035 
00036 
00037 /////////////////////////////////////////////////////////////////////////////
00038 //
00039 // class Texture implementation.
00040 //
00041 /////////////////////////////////////////////////////////////////////////////
00042 
00043 // --------------------------------------------------------------------------
00044 // Texture::Texture
00045 //
00046 // Constructor.
00047 // --------------------------------------------------------------------------
00048 
00049 Texture::Texture ()
00050   : _handle (0), _flags (kDefault),
00051     _standardCoordSystem (true), _fail (true)
00052 {
00053   // Inhibit possible previous OpenGL error
00054   GLenum err = glGetError ();
00055   if (GL_NO_ERROR != err)
00056     cerr << "OpenGL Error: " << gluErrorString (err)
00057          << " [Texture::Texture]" << endl;
00058 }
00059 
00060 
00061 // --------------------------------------------------------------------------
00062 // Texture::~Texture
00063 //
00064 // Destructor.  Delete texture object.
00065 // --------------------------------------------------------------------------
00066 
00067 Texture::~Texture ()
00068 {
00069   // Delete texture object
00070   if (glIsTexture(_handle))
00071     glDeleteTextures (1, &_handle);
00072 }
00073 
00074 
00075 // --------------------------------------------------------------------------
00076 // Texture::bind
00077 //
00078 // Bind texture to the active texture unit.
00079 // --------------------------------------------------------------------------
00080 
00081 void
00082 Texture::bind () const
00083 {
00084   glBindTexture (target (), _handle);
00085 }
00086 
00087 
00088 // --------------------------------------------------------------------------
00089 // Texture::getCompressionFormat
00090 //
00091 // Return the corresponding format for a compressed image given
00092 // image's internal format (pixel components).
00093 // --------------------------------------------------------------------------
00094 
00095 GLint
00096 Texture::getCompressionFormat (GLint internalFormat)
00097 {
00098   if (!GLEW_EXT_texture_compression_s3tc ||
00099       !GLEW_ARB_texture_compression)
00100     // No compression possible on this target machine
00101     return internalFormat;
00102 
00103   switch (internalFormat)
00104     {
00105     case 1:
00106       return GL_COMPRESSED_LUMINANCE;
00107 
00108     case 2:
00109       return GL_COMPRESSED_LUMINANCE_ALPHA;
00110 
00111     case 3:
00112       return GL_COMPRESSED_RGB;
00113 
00114     case 4:
00115       return GL_COMPRESSED_RGBA;
00116 
00117     default:
00118       // Error!
00119       throw std::invalid_argument ("Texture::getCompressionFormat: "
00120                                    "Bad internal format");
00121     }
00122 }
00123 
00124 
00125 // --------------------------------------------------------------------------
00126 // Texture::getInternalFormat
00127 //
00128 // Return texture's internal format depending to whether compression
00129 // is used or not.
00130 // --------------------------------------------------------------------------
00131 
00132 GLint
00133 Texture::getInternalFormat (GLint components)
00134 {
00135   if (_flags & kCompress)
00136     return getCompressionFormat (components);
00137   else
00138     return components;
00139 }
00140 
00141 
00142 /////////////////////////////////////////////////////////////////////////////
00143 //
00144 // class Texture2D implementation.
00145 //
00146 /////////////////////////////////////////////////////////////////////////////
00147 
00148 // --------------------------------------------------------------------------
00149 // Texture2D::Texture2D
00150 //
00151 // Constructors.  Try to load a texture 2D.  Don't throw any exception
00152 // if it fails to create the texture; the program can still run whithout
00153 // textures.
00154 // --------------------------------------------------------------------------
00155 
00156 Texture2D::Texture2D ()
00157   : Texture ()
00158 {
00159 }
00160 
00161 
00162 Texture2D::Texture2D (const string &filename, TextureFlags flags)
00163 {
00164   try
00165     {
00166       // Load image file into a buffer
00167       ImageBuffer ibuff (filename);
00168       auto_ptr<Image> img (ImageFactory::createImage (ibuff));
00169 
00170       // Create texture from image buffer
00171       create (img.get (), flags);
00172     }
00173   catch (std::exception &err)
00174     {
00175       cerr << "Error: Couldn't create texture 2D from "
00176            << filename << endl;
00177       cerr << "Reason: " << err.what () << endl;
00178     }
00179 }
00180 
00181 
00182 Texture2D::Texture2D (const Image *img, TextureFlags flags)
00183 {
00184   try
00185     {
00186       // Create texture from image buffer
00187       create (img, flags);
00188     }
00189   catch (std::exception &err)
00190     {
00191       cerr << "Error: Couldn't create texture 2D from "
00192            << img->name () << endl;
00193       cerr << "Reason: " << err.what () << endl;
00194     }
00195 }
00196 
00197 
00198 // --------------------------------------------------------------------------
00199 // Texture2D::create
00200 //
00201 // Create a texture 2D from an image.
00202 // --------------------------------------------------------------------------
00203 
00204 void
00205 Texture2D::create (const Image *img, TextureFlags flags)
00206 {
00207   if (!img->pixels ())
00208     throw std::runtime_error ("Invalid image data");
00209 
00210   // Fill texture's vars
00211   _name = img->name ();
00212   _flags = flags;
00213   _standardCoordSystem = img->stdCoordSystem ();
00214 
00215   // Generate a texture name
00216   glGenTextures (1, &_handle);
00217   glBindTexture (target (), _handle);
00218 
00219   // Setup texture filters
00220   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00221   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00222   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00223   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00224 
00225   // Build the texture and generate mipmaps
00226   if (GLEW_SGIS_generate_mipmap && img->isPowerOfTwo ())
00227     {
00228       // Hardware mipmap generation
00229       glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00230       glHint (GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
00231 
00232       glTexImage2D (GL_TEXTURE_2D, 0, getInternalFormat (img->components ()),
00233                     img->width (), img->height (), 0, img->format (),
00234                     GL_UNSIGNED_BYTE, img->pixels ());
00235     }
00236   else
00237     {
00238       // No hardware mipmap generation support, fall back to the
00239       // good old gluBuild2DMipmaps function
00240       gluBuild2DMipmaps (GL_TEXTURE_2D, getInternalFormat (img->components ()),
00241                          img->width (), img->height (), img->format (),
00242                          GL_UNSIGNED_BYTE, img->pixels ());
00243     }
00244 
00245   // Does texture creation succeeded?
00246   GLenum err = glGetError ();
00247   if (GL_NO_ERROR == err)
00248      _fail = false;
00249   else
00250       cerr << "OpenGL Error: " << gluErrorString (err)
00251            << " [Texture2D::create ()]" << endl;
00252 }