Code Search for Developers
 
 
  

Texture.cpp from FreeOrion at Krugle


Show Texture.cpp syntax highlighted

/* GG is a GUI for SDL and OpenGL.
   Copyright (C) 2003 T. Zachary Laine

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1
   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
   Lesser General Public License for more details.
    
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA

   If you do not wish to comply with the terms of the LGPL please
   contact the author as other terms are available for a fee.
    
   Zach Laine
   whatwasthataddress@hotmail.com */

#include <GG/Texture.h>

#include <GG/GUI.h>

#include <IL/il.h>
#include <IL/ilu.h>

#include <iostream>
#include <iomanip>


using namespace GG;

namespace {
    const bool VERBOSE_DEVIL_ERROR_REPORTING = true;

    int PowerOfTwo(int input)
    {
        int value = 1;
        while (value < input)
            value <<= 1;
        return value;
    }

    void CheckILErrors(const std::string& function_call)
    {
        ILuint error;
        while ((error = ilGetError()) != IL_NO_ERROR) {
            if (VERBOSE_DEVIL_ERROR_REPORTING) {
                std::cerr << "IL call \"" << function_call << "\" failed with IL error \"" << iluErrorString(error)
                          << "\" (code " << error << ")\n";
            }
        }
    }

    std::string ILenumToString(ILenum il_enum)
    {
#define ENUM_CASE(x) if (il_enum == x) return #x
        ENUM_CASE(IL_COLOR_INDEX);
        ENUM_CASE(IL_RGB);
        ENUM_CASE(IL_RGBA);
        ENUM_CASE(IL_BGR);
        ENUM_CASE(IL_BGRA);
        ENUM_CASE(IL_LUMINANCE);
        ENUM_CASE(IL_LUMINANCE_ALPHA);
        ENUM_CASE(IL_BYTE);
        ENUM_CASE(IL_UNSIGNED_BYTE);
        ENUM_CASE(IL_SHORT);
        ENUM_CASE(IL_UNSIGNED_SHORT);
        ENUM_CASE(IL_INT);
        ENUM_CASE(IL_UNSIGNED_INT);
        ENUM_CASE(IL_FLOAT);
        ENUM_CASE(IL_DOUBLE);
#undef ENUM_CASE
        return "UNKNOWN";
    }
}

///////////////////////////////////////
// class GG::Texture
///////////////////////////////////////
Texture::Texture() :
    m_bytes_pp(0),
    m_width(0),
    m_height(0),
    m_wrap_s(GL_REPEAT),
    m_wrap_t(GL_REPEAT),
    m_min_filter(GL_LINEAR_MIPMAP_LINEAR),
    m_mag_filter(GL_LINEAR),
    m_mipmaps(false),
    m_opengl_id(0),
    m_format(GL_INVALID_ENUM),
    m_type(GL_INVALID_ENUM),
    m_tex_coords(),
    m_default_width(0),
    m_default_height(0)
{
    Clear();
}

Texture::~Texture()
{
    Clear();
}

std::string Texture::Filename() const
{
    return m_filename;
}

GLenum Texture::WrapS() const
{
    return m_wrap_s;
}

GLenum Texture::WrapT() const
{
    return m_wrap_t;
}

GLenum Texture::MinFilter() const
{
    return m_min_filter;
}

GLenum Texture::MagFilter() const
{
    return m_mag_filter;
}

int Texture::BytesPP() const
{
    return m_bytes_pp;
}

GLint Texture::Width() const
{
    return m_width;
}

GLint Texture::Height() const
{
    return m_height;
}

bool Texture::MipMapped() const
{
    return m_mipmaps;
}

GLuint Texture::OpenGLId() const
{
    return m_opengl_id;
}

const GLfloat* Texture::DefaultTexCoords() const
{
    return m_tex_coords;
}

GLint Texture::DefaultWidth() const
{
    return m_default_width;
}

GLint Texture::DefaultHeight() const
{
    return m_default_height;
}

void Texture::OrthoBlit(const Pt& pt1, const Pt& pt2, const GLfloat* tex_coords/* = 0*/) const
{
    if (m_opengl_id) {
        if (!tex_coords) // use default texture coords when not given any others
            tex_coords = m_tex_coords;

        glBindTexture(GL_TEXTURE_2D, m_opengl_id);

        // HACK! This code ensures that unscaled textures are reproduced exactly, even
        // though they theoretically should be even when using non-GL_NEAREST* scaling.
        bool render_scaled = (pt2.x - pt1.x) != m_default_width || (pt2.y - pt1.y) != m_default_height;
        bool need_min_filter_change = !render_scaled && m_min_filter != GL_NEAREST;
        bool need_mag_filter_change = !render_scaled && m_mag_filter != GL_NEAREST;
        if (need_min_filter_change)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        if (need_mag_filter_change)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        // render texture
        glBegin(GL_TRIANGLE_STRIP);
        glTexCoord2f(tex_coords[0], tex_coords[1]); glVertex2i(pt1.x, pt1.y);
        glTexCoord2f(tex_coords[2], tex_coords[1]); glVertex2i(pt2.x, pt1.y);
        glTexCoord2f(tex_coords[0], tex_coords[3]); glVertex2i(pt1.x, pt2.y);
        glTexCoord2f(tex_coords[2], tex_coords[3]); glVertex2i(pt2.x, pt2.y);
        glEnd();

        if (need_min_filter_change)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
        if (need_mag_filter_change)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
    }
}

void Texture::OrthoBlit(const Pt& pt) const
{
    OrthoBlit(pt, pt + Pt(m_default_width, m_default_height), m_tex_coords);
}

void Texture::Load(const std::string& filename, bool mipmap/* = false*/)
{
    if (m_opengl_id)
        Clear();

    TextureManager::InitDevIL();

    ILuint id, error;
    ilGenImages(1, &id);
    CheckILErrors("ilGenImages(1, &id)");
    ilBindImage(id);
    CheckILErrors("ilBindImage(id)");
    ilLoadImage(const_cast<char*>(filename.c_str()));
    CheckILErrors("ilLoadImage(const_cast<char*>(filename.c_str()))");
    if ((error = ilGetError()) != IL_NO_ERROR)
        throw BadFile("Could not load temporary DevIL image from file \'" + filename + "\'");

    m_filename = filename;
    m_default_width = ilGetInteger(IL_IMAGE_WIDTH);
    CheckILErrors("ilGetInteger(IL_IMAGE_WIDTH)");
    m_default_height = ilGetInteger(IL_IMAGE_HEIGHT);
    CheckILErrors("ilGetInteger(IL_IMAGE_HEIGHT)");
    m_bytes_pp = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
    CheckILErrors("ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL)");
    m_format = ilGetInteger(IL_IMAGE_FORMAT);
    CheckILErrors("ilGetInteger(IL_IMAGE_FORMAT)");
    if (m_format == IL_COLOR_INDEX) {
        m_format = IL_RGBA;
        m_type = IL_UNSIGNED_BYTE;
        m_bytes_pp = 4;
        ilConvertImage(m_format, m_type);
        CheckILErrors("ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE)");
    } else {
        m_type = ilGetInteger(IL_IMAGE_TYPE);
        CheckILErrors("ilGetInteger(IL_IMAGE_TYPE)");
    }
    ILubyte* image_data = ilGetData();
    CheckILErrors("ilGetData()");
    Init(m_default_width, m_default_height, image_data, m_format, m_type, m_bytes_pp, mipmap);

    ilDeleteImages(1, &id);
    CheckILErrors("ilDeleteImages(1, &id)");
}

void Texture::Init(int x, int y, int width, int height, int image_width, const unsigned char* image, GLenum format, GLenum type, int bytes_per_pixel, bool mipmap/* = false*/)
{
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
    glPixelStorei(GL_UNPACK_SWAP_BYTES, false);
    glPixelStorei(GL_UNPACK_LSB_FIRST, false);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, image_width);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    try {
        InitFromRawData(width, height, image, format, type, bytes_per_pixel, mipmap);
    } catch (...) {
        glPopClientAttrib();
        throw;
    }

    glPopClientAttrib();
}

void Texture::Init(int width, int height, const unsigned char* image, GLenum format, GLenum type, int bytes_per_pixel, bool mipmap/* = false*/)
{
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
    glPixelStorei(GL_UNPACK_SWAP_BYTES, false);
    glPixelStorei(GL_UNPACK_LSB_FIRST, false);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    try {
        InitFromRawData(width, height, image, format, type, bytes_per_pixel, mipmap);
    } catch (...) {
        glPopClientAttrib();
        throw;
    }

    glPopClientAttrib();
}

void Texture::SetWrap(GLenum s, GLenum t)
{
    m_wrap_s = s;
    m_wrap_t = t;
    if (m_opengl_id) {
        glBindTexture(GL_TEXTURE_2D, m_opengl_id);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrap_s);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrap_t);
    }
}

void Texture::SetFilters(GLenum min, GLenum mag)
{
    m_min_filter = min;
    m_mag_filter = mag;
    if (m_opengl_id) {
        glBindTexture(GL_TEXTURE_2D, m_opengl_id);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
    }
}

void Texture::Clear()
{
    if (m_opengl_id)
        glDeleteTextures(1, &m_opengl_id);

    m_filename = "";

    m_bytes_pp = 4;
    m_default_width = m_width = 0;
    m_default_height = m_height = 0;

    m_wrap_s = m_wrap_t = GL_REPEAT;
    m_min_filter = GL_LINEAR_MIPMAP_LINEAR;
    m_mag_filter = GL_LINEAR;

    m_mipmaps = false;
    m_opengl_id = 0;
    m_format = GL_INVALID_ENUM;
    m_type = GL_INVALID_ENUM;

    m_tex_coords[0] = m_tex_coords[1] = 0.0f;   // min x, y
    m_tex_coords[2] = m_tex_coords[3] = 1.0f;   // max x, y
}

void Texture::InitFromRawData(int width, int height, const unsigned char* image, GLenum format, GLenum type, int bytes_per_pixel, bool mipmap)
{
    if (!image)
        return;

    if (m_opengl_id)
        Clear();

    int GL_texture_width = PowerOfTwo(width);
    int GL_texture_height = PowerOfTwo(height);

    glGenTextures(1, &m_opengl_id);
    glBindTexture(GL_TEXTURE_2D, m_opengl_id);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_wrap_s);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_wrap_t);

    glTexImage2D(GL_PROXY_TEXTURE_2D, 0, format, GL_texture_width, GL_texture_height, 0, format, type, image);
    GLint checked_format;
    glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &checked_format);
    if (!checked_format)
        throw InsufficientResources("Insufficient resources to create requested OpenGL texture");
    bool image_is_power_of_two = width == GL_texture_width && height == GL_texture_height;
    if (image_is_power_of_two) {
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, image);
    } else {
        std::vector<unsigned char> zero_data(bytes_per_pixel * GL_texture_width * GL_texture_height);
        glTexImage2D(GL_TEXTURE_2D, 0, format, GL_texture_width, GL_texture_height, 0, format, type, &zero_data[0]);
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, image);
    }

    m_mipmaps = mipmap;
    m_default_width = width;
    m_default_height = height;
    m_bytes_pp = bytes_per_pixel;
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &m_width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &m_height);
    m_tex_coords[2] = m_default_width / double(m_width);
    m_tex_coords[3] = m_default_height / double(m_height);

    if (mipmap) {
        std::auto_ptr<unsigned char> image_copy;
        if (!image_is_power_of_two)
            image_copy.reset(GetRawBytes());
        unsigned char* image_to_use = image_copy.get() ? image_copy.get() : const_cast<unsigned char*>(image);
        gluBuild2DMipmaps(GL_PROXY_TEXTURE_2D, format, GL_texture_width, GL_texture_height, format, type, image_to_use);
        GLint checked_format;
        glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &checked_format);
        if (!checked_format)
            throw InsufficientResources("Insufficient resources to create requested mipmapped OpenGL texture");
        gluBuild2DMipmaps(GL_TEXTURE_2D, format, GL_texture_width, GL_texture_height, format, type, image_to_use);
    } else {
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
    }
}

unsigned char* Texture::GetRawBytes()
{
    unsigned char* retval = 0;
    glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
    glPixelStorei(GL_PACK_SWAP_BYTES, false);
    glPixelStorei(GL_PACK_LSB_FIRST, false);
    glPixelStorei(GL_PACK_ROW_LENGTH, 0);
    glPixelStorei(GL_PACK_SKIP_ROWS, 0);
    glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);

    // get pixel data
    typedef unsigned char uchar;
    retval = new uchar[m_width * m_height * m_bytes_pp];
    glGetTexImage(GL_TEXTURE_2D, 0, m_format, m_type, retval);
    glPopClientAttrib();
    return retval;
}


///////////////////////////////////////
// class GG::SubTexture
///////////////////////////////////////
SubTexture::SubTexture() :
    m_width(0),
    m_height(0),
    m_tex_coords()
{
}

SubTexture::SubTexture(const boost::shared_ptr<const Texture>& texture, int x1, int y1, int x2, int y2) :
    m_texture(texture),
    m_width(x2 - x1),
    m_height(y2 - y1),
    m_tex_coords()
{
    if (!m_texture) throw BadTexture("Attempted to contruct subtexture from invalid texture");
    if (x2 < x1 || y2 < y1) throw InvalidTextureCoordinates("Attempted to contruct subtexture from invalid coordinates");

    m_tex_coords[0] = static_cast<double>(x1) / texture->Width();
    m_tex_coords[1] = static_cast<double>(y1) / texture->Height();
    m_tex_coords[2] = static_cast<double>(x2) / texture->Width();
    m_tex_coords[3] = static_cast<double>(y2) / texture->Height();
}

SubTexture::~SubTexture()
{
}

SubTexture::SubTexture(const SubTexture& rhs)
{
    *this = rhs;
}

const SubTexture& SubTexture::operator=(const SubTexture& rhs)
{
    if (this != &rhs) {
        m_texture = rhs.m_texture;
        m_width = rhs.m_width;
        m_height = rhs.m_height;
        m_tex_coords[0] = rhs.m_tex_coords[0];
        m_tex_coords[1] = rhs.m_tex_coords[1];
        m_tex_coords[2] = rhs.m_tex_coords[2];
        m_tex_coords[3] = rhs.m_tex_coords[3];
    }
    return *this;
}

bool SubTexture::Empty() const
{
    return !m_texture;
}

const GLfloat* SubTexture::TexCoords() const
{
    return m_tex_coords;
}

GLint SubTexture::Width() const
{
    return m_width;
}

GLint SubTexture::Height() const
{
    return m_height;
}

const Texture* SubTexture::GetTexture() const
{
    return m_texture.get();
}

void SubTexture::OrthoBlit(const Pt& pt1, const Pt& pt2) const
{
    if (m_texture) m_texture->OrthoBlit(pt1, pt2, m_tex_coords);
}

void SubTexture::OrthoBlit(const Pt& pt) const
{
    if (m_texture) m_texture->OrthoBlit(pt, pt + Pt(m_width, m_height), m_tex_coords);
}


///////////////////////////////////////
// class GG::TextureManager
///////////////////////////////////////
// static member(s)
bool TextureManager::s_il_initialized = false;

TextureManager::TextureManager()
{}

boost::shared_ptr<Texture> TextureManager::StoreTexture(Texture* texture, const std::string& texture_name)
{
    boost::shared_ptr<Texture> temp(texture);
    return StoreTexture(temp, texture_name);
}

boost::shared_ptr<Texture> TextureManager::StoreTexture(const boost::shared_ptr<Texture>& texture, const std::string& texture_name)
{
    return (m_textures[texture_name] = texture);
}

boost::shared_ptr<Texture> TextureManager::GetTexture(const std::string& name, bool mipmap/* = false*/)
{
    std::map<std::string, boost::shared_ptr<Texture> >::iterator it = m_textures.find(name);
    if (it == m_textures.end()) { // if no such texture was found, attempt to load it now, using name as the filename
        return (m_textures[name] = LoadTexture(name, mipmap));
    } else { // otherwise, just return the texture we found
        return it->second;
    }
}

void TextureManager::FreeTexture(const std::string& name)
{
    std::map<std::string, boost::shared_ptr<Texture> >::iterator it = m_textures.find(name);
    if (it != m_textures.end())
        m_textures.erase(it);
}

void TextureManager::InitDevIL()
{
    if (!s_il_initialized) {
        // ensure we're starting with an empty error stack
        while (ilGetError() != IL_NO_ERROR) ;
        ilInit();
        CheckILErrors("ilInit()");
        iluInit();
        CheckILErrors("iluInit()");
        s_il_initialized = true;
    }
}

boost::shared_ptr<Texture> TextureManager::LoadTexture(const std::string& filename, bool mipmap/* = false*/)
{
    boost::shared_ptr<Texture> temp(new Texture());
    temp->Load(filename, mipmap);
    return (m_textures[filename] = temp);
}

TextureManager& GG::GetTextureManager()
{
    static TextureManager manager;
    return manager;
}




See more files for this project here

FreeOrion

FreeOrion brings nation building to a galactic scale with its full-featured grand campaign and in-game racial histories, in addition to the classic 4X model of galactic conquest and tactical combat.

Project homepage: http://sourceforge.net/projects/freeorion
Programming language(s): C,C++
License: other

  Ogre/
    Plugins/
      OISInput.cfg
      OISInput.cpp
      OISInput.h
      OgreGUIInputPlugin.cpp
      OgreGUIInputPlugin.h
      SConscript
    OgreGUI.cpp
    SConscript
  SDL/
    SConscript
    SDLGUI.cpp
  dialogs/
    ColorDlg.cpp
    FileDlg.cpp
    SConscript
    ThreeButtonDlg.cpp
  AlignmentFlags.cpp
  Base.cpp
  BrowseInfoWnd.cpp
  Button.cpp
  Clr.cpp
  Control.cpp
  Cursor.cpp
  DrawUtil.cpp
  DropDownList.cpp
  DynamicGraphic.cpp
  Edit.cpp
  EventPump.cpp
  Font.cpp
  GUI.cpp
  Layout.cpp
  ListBox.cpp
  Menu.cpp
  MultiEdit.cpp
  Plugin.cpp
  PluginInterface.cpp
  PtRect.cpp
  SConscript
  Scroll.cpp
  Slider.cpp
  StaticGraphic.cpp
  StyleFactory.cpp
  TabWnd.cpp
  TextControl.cpp
  Texture.cpp
  Timer.cpp
  Wnd.cpp
  WndEditor.cpp
  WndEvent.cpp
  ZList.cpp
  _vsnprintf.c