Files
openglplayground/texture.cc

261 lines
6.3 KiB
C++

#include <glbinding/gl/gl.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#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<GLint>(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<GLint>(GL_LINEAR));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, static_cast<GLint>(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()
: texID_(0), width_(0), height_(0), alpha_(false)
{
}
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)
{
SDLSurfaceUPtr 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.get());
} catch (...) {
glDeleteTextures(1, &texID_);
throw;
}
}
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
{
assert(texID_ != 0);
glBindTexture(GL_TEXTURE_2D, texID_);
}
void Texture2D::copyFromSurface(SDL_Surface *src)
{
SDLSurfaceUPtr tmpSurf;
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) {
tmpSurf.reset(SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_RGB24, 0));
} else {
tmpSurf.reset(SDL_ConvertSurfaceFormat(src, SDL_PIXELFORMAT_ABGR8888, 0));
}
if (!tmpSurf)
throw SDLException{};
surf = tmpSurf.get();
} else {
surf = src;
}
if (SDL_MUSTLOCK(surf))
SDL_LockSurface(surf);
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);
}
SDLSurfaceUPtr 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{};
SDLSurfaceUPtr dst(SDL_CreateRGBSurface(0, width_, height_, bpp,
rmask, gmask, bmask, amask));
if(!dst)
throw SDLException{};
glGetTexImage(GL_TEXTURE_2D, 0, alpha_?GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, dst->pixels);
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<const int>(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_);
}
}