// ============================================================== // This file is part of MegaGlest (www.glest.org) // // Texture.cpp -- Copyright (c) 2006 David Henry // changed for use with MegaGlest: Copyright (C) 2011- by Mark Vejvoda // // This code is licensed under the MIT license: // http://www.opensource.org/licenses/mit-license.php // // Open Source Initiative OSI - The MIT License (MIT):Licensing // // The MIT License (MIT) // Copyright (c) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE.// // // Implementation of an OpenGL texture classes. // ///////////////////////////////////////////////////////////////////////////// #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #endif // _WIN32 #include #include #include #include "GlErrors.h" #include "md5Texture.h" #include "Image.h" namespace Shared { namespace Graphics { namespace md5 { using std::cout; using std::cerr; using std::endl; using std::max; ///////////////////////////////////////////////////////////////////////////// // // class Texture implementation. // ///////////////////////////////////////////////////////////////////////////// // -------------------------------------------------------------------------- // Texture::Texture // // Constructor. // -------------------------------------------------------------------------- Texture::Texture () : _handle (0), _flags (kDefault), _standardCoordSystem (true), _fail (true) { // Inhibit possible previous OpenGL error checkOpenGLErrors (__FILE__, __LINE__); } // -------------------------------------------------------------------------- // Texture::~Texture // // Destructor. Delete texture object. // -------------------------------------------------------------------------- Texture::~Texture () { // Delete texture object if (glIsTexture(_handle)) glDeleteTextures (1, &_handle); } // -------------------------------------------------------------------------- // Texture::bind // // Bind texture to the active texture unit. // -------------------------------------------------------------------------- void Texture::bind () const { glBindTexture (target (), _handle); } void Texture::bind (GLenum texUnit) const { glActiveTexture (texUnit); glBindTexture (target (), _handle); } // -------------------------------------------------------------------------- // Texture::getCompressionFormat // // Return the corresponding format for a compressed image given // image's internal format (pixel components). // -------------------------------------------------------------------------- GLint Texture::getCompressionFormat (GLint internalFormat) { if (!GLEW_EXT_texture_compression_s3tc || !GLEW_ARB_texture_compression) // No compression possible on this target machine return internalFormat; switch (internalFormat) { case 1: return GL_COMPRESSED_LUMINANCE; case 2: return GL_COMPRESSED_LUMINANCE_ALPHA; case 3: return GL_COMPRESSED_RGB; case 4: return GL_COMPRESSED_RGBA; default: // Error! throw std::invalid_argument ("Texture::getCompressionFormat: " "Bad internal format"); } } // -------------------------------------------------------------------------- // Texture::getInternalFormat // // Return texture's internal format depending to whether compression // is used or not. // -------------------------------------------------------------------------- GLint Texture::getInternalFormat (GLint components) { if (_flags & kCompress) return getCompressionFormat (components); else return components; } ///////////////////////////////////////////////////////////////////////////// // // class Texture2D implementation. // ///////////////////////////////////////////////////////////////////////////// // -------------------------------------------------------------------------- // Texture2D::Texture2D // // Constructors. Try to load a texture 2D. Don't throw any exception // if it fails to create the texture; the program can still run whithout // textures. // -------------------------------------------------------------------------- Texture2D::Texture2D () : Texture () { } Texture2D::Texture2D (const string &filename, TextureFlags flags) { try { // Load image file into a buffer ImageBuffer ibuff (filename); auto_ptr img (ImageFactory::createImage (ibuff)); // Create texture from image buffer create (img.get (), flags); } catch (std::exception &err) { cerr << "Error: Couldn't create texture 2D from " << filename << endl << "Reason: " << err.what () << endl; } } Texture2D::Texture2D (const Image *img, TextureFlags flags) { try { // Create texture from image buffer create (img, flags); } catch (std::exception &err) { cerr << "Error: Couldn't create texture 2D from " << img->name () << endl << "Reason: " << err.what () << endl; } } // -------------------------------------------------------------------------- // Texture2D::create // // Create a texture 2D from an image. // -------------------------------------------------------------------------- void Texture2D::create (const Image *img, TextureFlags flags) { if (!img->pixels ()) throw std::runtime_error ("Invalid image data"); // Fill texture's vars _name = img->name (); _flags = flags; _standardCoordSystem = img->stdCoordSystem (); // Generate a texture name glGenTextures (1, &_handle); glBindTexture (target (), _handle); // Setup texture filters glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (img->isCompressed ()) { // Image use S3 compression. Only S3TC DXT1, DXT3 // and DXT5 formats are supported. GLsizei mipWidth = img->width (); GLsizei mipHeight = img->height (); int offset = 0; int blockSize = (img->format () == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; // Upload mipmaps to video memory for (GLint mipLevel = 0; mipLevel < img->numMipmaps (); ++mipLevel) { GLsizei mipSize = ((mipWidth + 3) / 4) * ((mipHeight + 3) / 4) * blockSize; glCompressedTexImage2D (GL_TEXTURE_2D, mipLevel, img->format (), mipWidth, mipHeight, 0, mipSize, img->pixels () + offset); mipWidth = max (mipWidth >> 1, 1); mipHeight = max (mipHeight >> 1, 1); offset += mipSize; } } else { // Build the texture and generate mipmaps if (GLEW_SGIS_generate_mipmap && img->isPowerOfTwo ()) { // Hardware mipmap generation glTexParameteri (GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); glHint (GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); glTexImage2D (GL_TEXTURE_2D, 0, getInternalFormat (img->components ()), img->width (), img->height (), 0, img->format (), GL_UNSIGNED_BYTE, img->pixels ()); } else { // No hardware mipmap generation support, fall back to the // good old gluBuild2DMipmaps function gluBuild2DMipmaps (GL_TEXTURE_2D, getInternalFormat (img->components ()), img->width (), img->height (), img->format (), GL_UNSIGNED_BYTE, img->pixels ()); } } // Does texture creation succeeded? if (GL_NO_ERROR == checkOpenGLErrors (__FILE__, __LINE__)) _fail = false; } ///////////////////////////////////////////////////////////////////////////// // // class TextureRectangle implementation. // ///////////////////////////////////////////////////////////////////////////// // -------------------------------------------------------------------------- // TextureRectangle::TextureRectangle // // Constructors. Try to load a texture rectangle. Don't throw any // exception if it fails to create the texture; the program can still // run whithout textures. // -------------------------------------------------------------------------- TextureRectangle::TextureRectangle (const string &filename, TextureFlags flags) : _width (0), _height (0) { try { // Check if is not a DDS image if (filename.find (".dds") != string::npos) throw ImageException ("Compressed textures are not supported for" " texture rectangles!", filename); // Load image file into a buffer ImageBuffer ibuff (filename); auto_ptr img (ImageFactory::createImage (ibuff)); // Create texture from image buffer create (img.get (), flags); } catch (std::exception &err) { cerr << "Error: Couldn't create texture rectangle from " << filename << endl << "Reason: " << err.what () << endl; } } TextureRectangle::TextureRectangle (const Image *img, TextureFlags flags) : _width (0), _height (0) { try { // Check if is not a compressed DDS image if (img->isCompressed ()) throw ImageException ("Compressed textures are not supported for" " texture rectangles!", img->name ()); // Create texture from image buffer create (img, flags); } catch (std::exception &err) { cerr << "Error: Couldn't create texture rectangle from " << img->name () << endl << "Reason: " << err.what () << endl; } } // -------------------------------------------------------------------------- // TextureRectangle::create // // Create a texture rectangle from an image. No mipmap // filtering is permitted for texture rectangles. // -------------------------------------------------------------------------- void TextureRectangle::create (const Image *img, TextureFlags flags) { if (!img->pixels ()) throw std::runtime_error ("Invalid image data"); // Get image info _standardCoordSystem = img->stdCoordSystem (); _width = img->width (); _height = img->height (); _name = img->name (); _flags = flags; // Generate a texture name glGenTextures (1, &_handle); glBindTexture (target (), _handle); // Setup texture filters glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Create texture from image glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, getInternalFormat (img->components ()), img->width (), img->height (), 0, img->format (), GL_UNSIGNED_BYTE, img->pixels ()); // Does texture creation succeeded? if (GL_NO_ERROR == checkOpenGLErrors (__FILE__, __LINE__)) _fail = false; } ///////////////////////////////////////////////////////////////////////////// // // class TextureCubeMap implementation. // ///////////////////////////////////////////////////////////////////////////// // -------------------------------------------------------------------------- // TextureCubeMap::TextureCubeMap // // Constructors. Try to load a texture cube map. Don't throw any // exception if it fails to create the texture; the program can still // run whithout textures. // -------------------------------------------------------------------------- TextureCubeMap::TextureCubeMap (const string &basename, const vector &files, TextureFlags flags) { try { _name = basename; vector faces; faces.reserve(6); // Load images for (int i = 0; i < 6; ++i) { ImageBuffer ibuff (files[i]); faces.push_back (ImagePtr (ImageFactory::createImage (ibuff))); } // Create texture from faces create (faces, flags); } catch (ImageException &err) { cerr << "Error: Couldn't create texture cube map from " << basename << endl; cerr << "Reason: " << err.what () << " (" << err.which () << ")" << endl; } catch (std::exception &err) { cerr << "Error: Couldn't create texture cube map from " << basename << endl; cerr << "Reason: " << err.what () << endl; } } TextureCubeMap::TextureCubeMap (const string &basename, const vector &faces, TextureFlags flags) { try { _name = basename; // Create texture from image buffer create (faces, flags); } catch (ImageException &err) { cerr << "Error: Couldn't create texture cube map from " << basename << endl; cerr << "Reason: " << err.what () << " (" << err.which () << ")" << endl; } catch (std::exception &err) { cerr << "Error: Couldn't create texture cube map from " << basename << endl; cerr << "Reason: " << err.what () << endl; } } // -------------------------------------------------------------------------- // TextureCubeMap::create // // Create a cube map texture from images. // -------------------------------------------------------------------------- void TextureCubeMap::create (const vector &faces, TextureFlags flags) { // Create a list of image buffers and associate a target // for each one typedef map TexTarget; typedef TexTarget::value_type TexPair; TexTarget texImages; texImages.insert (TexPair (faces[0].get(), GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB)); texImages.insert (TexPair (faces[1].get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB)); texImages.insert (TexPair (faces[2].get(), GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB)); texImages.insert (TexPair (faces[3].get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB)); texImages.insert (TexPair (faces[4].get(), GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB)); texImages.insert (TexPair (faces[5].get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)); _standardCoordSystem = faces[0]->stdCoordSystem (); _flags = flags; // Generate a texture name glGenTextures (1, &_handle); glBindTexture (GL_TEXTURE_CUBE_MAP_ARB, _handle); // Setup texture filters glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Load each side of the cube for (TexTarget::iterator itor = texImages.begin (); itor != texImages.end (); ++itor) { // Get image data const Image *img = itor->first; if (!img->pixels ()) throw std::runtime_error ("Invalid image data"); if (img->isCompressed ()) { // Image use S3 compression GLsizei mipWidth = img->width (); GLsizei mipHeight = img->height (); int offset = 0; int blockSize = (img->format () == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; // Upload mipmaps to video memory for (GLint mipLevel = 0; mipLevel < img->numMipmaps (); ++mipLevel) { GLsizei mipSize = ((mipWidth + 3) / 4) * ((mipHeight + 3) / 4) * blockSize; glCompressedTexImage2D (itor->second, mipLevel, img->format (), mipWidth, mipHeight, 0, mipSize, img->pixels () + offset); mipWidth = max (mipWidth >> 1, 1); mipHeight = max (mipHeight >> 1, 1); offset += mipSize; } } else { // No hardware mipmap generation support for texture cube // maps, use gluBuild2DMipmaps function instead gluBuild2DMipmaps (itor->second, getInternalFormat (img->components ()), img->width (), img->height (), img->format (), GL_UNSIGNED_BYTE, img->pixels ()); } } // Does texture creation succeeded? if (GL_NO_ERROR == checkOpenGLErrors (__FILE__, __LINE__)) _fail = false; } }}} //end namespace