Files
glest-source/source/shared_lib/sources/graphics/md5/md5Texture.cpp

537 lines
16 KiB
C++

// ==============================================================
// 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) <year> <copyright holders>
//
// 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 <windows.h>
#endif // _WIN32
#include <GL/glew.h>
#include <iostream>
#include <stdexcept>
#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<Image> 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<Image> 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<string> &files,
TextureFlags flags)
{
try
{
_name = basename;
vector<ImagePtr> 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<ImagePtr> &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<ImagePtr> &faces, TextureFlags flags)
{
// Create a list of image buffers and associate a target
// for each one
typedef map<const Image*, GLenum> 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