#ifndef __OPENGLPLAYGROUND_TEXTURE_HH__ #define __OPENGLPLAYGROUND_TEXTURE_HH__ #include #include #include #include #include #include #include #include "common.hh" using namespace gl; static unsigned ilog2(unsigned in) { unsigned ret = 0u; while (in >>= 1) ++ret; return ret; } class Framebuffer { public: Framebuffer() { glGenFramebuffers(1, &_fbID); } ~Framebuffer() { glDeleteFramebuffers(1, &_fbID); } Framebuffer(Framebuffer const& copy) = delete; Framebuffer& operator=(Framebuffer const& copy) = delete; Framebuffer(Framebuffer && move) : _fbID(move._fbID) { move._fbID = 0; } Framebuffer& operator=(Framebuffer && move) { glDeleteFramebuffers(1, &_fbID); _fbID = move._fbID; move._fbID = 0; return *this; } void bind() const { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbID); } GLuint getID() const { return _fbID; } void attachTexture(GLenum textarget, GLuint texID) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textarget, texID, 0); } private: GLuint _fbID; }; class TextureCubeMap { public: TextureCubeMap(unsigned size) { 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() { glDeleteTextures(1, &_texID); } TextureCubeMap(TextureCubeMap const& copy) = delete; TextureCubeMap& operator=(TextureCubeMap const& copy) = delete; TextureCubeMap(TextureCubeMap && move) : _texID(move._texID) { move._texID = 0; } TextureCubeMap& operator=(TextureCubeMap && move) { glDeleteTextures(1, &_texID); _texID = move._texID; move._texID = 0; return *this; } void bind() const { glBindTexture(GL_TEXTURE_CUBE_MAP, _texID); } GLuint getID() const { return _texID; } private: GLuint _texID; }; class Texture2D { public: Texture2D(unsigned width, unsigned height) { _glCreate(width, height); } Texture2D(std::string const& file) { SDL_Surface *surf = IMG_Load(file.c_str()); if (!surf) throw SDLException(); try { _glCreate(surf->w, surf->h); try { assert(surf->format->format == SDL_PIXELFORMAT_RGB24); // TODO: Proper support of many formats if (SDL_MUSTLOCK(surf)) SDL_LockSurface(surf); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surf->w, surf->h, GL_RGB, GL_UNSIGNED_BYTE, surf->pixels); glGenerateMipmap(GL_TEXTURE_2D); } catch(...) { glDeleteTextures(1, &_texID); throw; } } catch(...) { SDL_FreeSurface(surf); throw; } SDL_FreeSurface(surf); } ~Texture2D() { glDeleteTextures(1, &_texID); } Texture2D(Texture2D const& copy) = delete; Texture2D& operator=(Texture2D const& copy) = delete; Texture2D(Texture2D && move) : _texID(move._texID) { move._texID = 0; } Texture2D& operator=(Texture2D && move) { glDeleteTextures(1, &_texID); _texID = move._texID; move._texID = 0; return *this; } void bind() { glBindTexture(GL_TEXTURE_2D, _texID); } private: void _glCreate(unsigned width, unsigned height) { 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, 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(GL_RGB8), width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); width = std::max(1u, (width / 2u)); height = std::max(1u, (height / 2u)); } } } catch(...) { glDeleteTextures(1, &_texID); } } GLuint _texID; }; #endif