#include #include #include #include "texture.hh" using namespace gl; static unsigned ilog2(unsigned in) { unsigned ret = 0u; while (in >>= 1) ++ret; return ret; } Framebuffer::Framebuffer() : _fbID(0) { glGenFramebuffers(1, &_fbID); } Framebuffer::~Framebuffer() { glDeleteFramebuffers(1, &_fbID); } Framebuffer::Framebuffer(Framebuffer && move) : _fbID(move._fbID) { move._fbID = 0; } Framebuffer& Framebuffer::operator=(Framebuffer && move) { glDeleteFramebuffers(1, &_fbID); _fbID = move._fbID; move._fbID = 0; return *this; } void Framebuffer::bind() const { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbID); } void Framebuffer::attachTexture(GLenum textarget, GLuint texID) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textarget, texID, 0); } TextureCubeMap::TextureCubeMap(unsigned size) : _texID(0) { glGenTextures(1, &_texID); glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage")) glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_DEPTH_COMPONENT24, size, size); else { std::printf("Warning: extension GL_ARB_texture_storage not supported!\n"); for (unsigned i = 0;i < 6;++i) { GLenum const face[6] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}; glTexImage2D(face[i], 0, static_cast(GL_DEPTH_COMPONENT16), size, size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); } } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, static_cast(GL_LINEAR)); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast(GL_LINEAR)); } TextureCubeMap::~TextureCubeMap() { glDeleteTextures(1, &_texID); } TextureCubeMap::TextureCubeMap(TextureCubeMap && move) : _texID(move._texID) { move._texID = 0; } TextureCubeMap& TextureCubeMap::operator=(TextureCubeMap && move) { glDeleteTextures(1, &_texID); _texID = move._texID; move._texID = 0; return *this; } void TextureCubeMap::bind() const { glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); } Texture2D::Texture2D(unsigned width, unsigned height, bool alpha) : texID_(0), width_(width), height_(height), alpha_(alpha) { _glCreate(width, height, alpha); } Texture2D::Texture2D(std::string const& file) : texID_(0), width_(0), height_(0), alpha_(false) { SDL_Surface *surf = IMG_Load(file.c_str()); if (!surf) throw SDLException(); if(surf->format->Amask == 0) _glCreate(surf->w, surf->h); else { _glCreate(surf->w, surf->h, true); } try { copyFromSurface(surf); } catch (...) { glDeleteTextures(1, &texID_); SDL_FreeSurface(surf); throw; } SDL_FreeSurface(surf); } Texture2D::Texture2D(SDL_Surface *surface) : texID_(0), width_(0), height_(0), alpha_(false) { if(surface->format->Amask == 0) _glCreate(surface->w, surface->h); else { _glCreate(surface->w, surface->h, true); } try { copyFromSurface(surface); } catch(...) { glDeleteTextures(1, &texID_); throw; } } Texture2D::Texture2D(Texture2D&& move) : texID_(move.texID_), width_(move.width_), height_(move.height_), alpha_(move.alpha_) { move.texID_ = 0; } Texture2D& Texture2D::operator=(Texture2D&& move) { glDeleteTextures(1, &texID_); texID_ = move.texID_; width_ = move.width_; height_ = move.height_; alpha_ = move.alpha_; move.texID_ = 0; return *this; } Texture2D::~Texture2D() { glDeleteTextures(1, &texID_); } void Texture2D::bind() const { glBindTexture(GL_TEXTURE_2D, texID_); } void Texture2D::copyFromSurface(SDL_Surface *src) { SDL_Surface *surf; if ((src->w > width_) || src->h > height_) throw Exception("Cannot replace texture image with larger image"); if ((src->format->format != SDL_PIXELFORMAT_RGB24) && (src->format->format != SDL_PIXELFORMAT_RGBA8888)) { if ((src->format->Amask != 0) != alpha_) throw Exception("Cannot replace texture image with mismatched alpha"); if (src->format->Amask == 0) { surf = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_RGB24, 0); } else { surf = SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_ABGR8888, 0); } if (!surf) throw SDLException{}; } else { surf = src; } if (SDL_MUSTLOCK(surf)) SDL_LockSurface(surf); try { bind(); if(surf->format->Amask == 0) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels); else glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); glGenerateMipmap(GL_TEXTURE_2D); } catch(...) { if (surf != src) SDL_FreeSurface(surf); throw; } if(surf != src) SDL_FreeSurface(surf); } SDL_Surface* Texture2D::copyToSurface() { bind(); uint32_t rmask, gmask, bmask, amask; int bpp; if (!SDL_PixelFormatEnumToMasks(alpha_?SDL_PIXELFORMAT_ABGR8888:SDL_PIXELFORMAT_RGB24, &bpp, &rmask, &gmask, &bmask, &amask)) throw SDLException{}; SDL_Surface *dst = SDL_CreateRGBSurface(0, width_, height_, bpp, rmask, gmask, bmask, amask); if(!dst) throw SDLException{}; try { glGetTexImage(GL_TEXTURE_2D, 0, alpha_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, dst->pixels); } catch(...) { SDL_FreeSurface(dst); throw; } return dst; } void Texture2D::_glCreate(unsigned width, unsigned height, bool alpha) { width_ = width; height_ = height; alpha_ = alpha; glGenTextures(1, &texID_); try { glBindTexture(GL_TEXTURE_2D, texID_); unsigned logWidth = ilog2(width), logHeight = ilog2(height); unsigned levels = std::max(logWidth,logHeight)+1u; if(SDL_GL_ExtensionSupported("GL_ARB_texture_storage")) glTexStorage2D(GL_TEXTURE_2D, levels, alpha?GL_RGBA8:GL_RGB8, width, height); else { std::printf("Warning: extension GL_ARB_texture_storage not supported!\n"); for (unsigned i = 0u; i < levels; ++i) { glTexImage2D(GL_TEXTURE_2D, i, static_cast(alpha?GL_RGBA8:GL_RGB8), width, height, 0, alpha?GL_RGBA8:GL_RGB8, GL_UNSIGNED_BYTE, NULL); width = std::max(1u, (width / 2u)); height = std::max(1u, (height / 2u)); } } } catch(...) { glDeleteTextures(1, &texID_); } }