#include #include #include namespace sp { namespace { GLint pixelFormatToInternal(enum PixelFormat format) { switch(format) { case PixelFormat::PF_RGBA : return GL_RGBA8; case PixelFormat::PF_RGB : return GL_RGB8; case PixelFormat::PF_Alpha : default : return GL_R8; } } GLint pixelFormatToGL(enum PixelFormat format) { switch(format) { case PixelFormat::PF_RGBA : return GL_RGBA; case PixelFormat::PF_RGB : return GL_RGB; case PixelFormat::PF_Alpha : default : return GL_RED; } } } Texture::Texture() : m_id (0), m_size (0, 0) { } Texture::~Texture() { destroy(); } void Texture::create(unsigned width, unsigned heigth, PixelFormat format) { // TODO: Should have getBpp() in PixelFormat instead. // Always allocate 32 bit (4 byte) pixel buffer for now. std::vector empty_pixels(width * heigth * 4); if (!m_id) { glGenTextures(1, &m_id); } enable(); m_size = vec2u(width, heigth); m_format = format; if (format == PixelFormat::PF_RGBA) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } glTexImage2D(GL_TEXTURE_2D, 0, pixelFormatToInternal(format), width, heigth, 0, pixelFormatToGL(format), GL_UNSIGNED_BYTE, &empty_pixels[0]); setSmooth(true); setRepeat(false); disable(); } void Texture::create(const Vector2u& size, PixelFormat format) { create(size.x, size.y, format); } void Texture::create(const Image& image) { GLint srcFormat; GLint glFormat; if (!m_id) { glGenTextures(1, &m_id); } m_size = image.getSize(); m_format = image.getFormat(); enable(); if (image.getBpp() == 32) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } srcFormat = pixelFormatToGL(image.getFormat()); glFormat = pixelFormatToInternal(image.getFormat()); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, m_size.x, m_size.y, 0, srcFormat, GL_UNSIGNED_BYTE, image.getPixels()); setSmooth(true); setRepeat(false); disable(); } void Texture::create(const std::string& filename, bool isTopDown) { Image img; if (img.loadFromFile(filename)) { // OpenGL expects bottom-up images, flip. if (isTopDown) { img.flipY(); } create(img); } } void Texture::destroy() { if (m_id) { glDeleteTextures(1, &m_id); m_id = 0; } m_size = vec2u(0, 0); m_format = PixelFormat::PF_Unknown; } bool Texture::isEmpty() const { return m_id == 0 || m_size == vec2u(0, 0); } const Vector2u& Texture::getSize() const { return m_size; } void Texture::update(vec2u pos, const Image& image) { GLuint format; enable(); if (image.getFormat() == PixelFormat::PF_RGBA) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } format = pixelFormatToGL(image.getFormat()); glTexSubImage2D(GL_TEXTURE_2D, 0, pos.x, pos.y, image.getWidth(), image.getHeight(), format, GL_UNSIGNED_BYTE, image.getPixels()); disable(); } void Texture::update(const Image& image) { update(Vector2u(0, 0), image); } Image Texture::copyToImage() const { Image img; if (!isEmpty()) { std::vector pixels(m_size.x * m_size.y * 4); enable(); //glPixelStorei(GL_PACK_ALIGNMENT, 4); glGetTexImage(GL_TEXTURE_2D, 0, pixelFormatToGL(m_format), GL_UNSIGNED_BYTE, &pixels[0]); img.create(m_format, m_size.x, m_size.y, &pixels[0]); disable(); } return img; } void Texture::setMinFilter(enum Filter filter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); } void Texture::setMagFilter(enum Filter filter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); } void Texture::setSmooth(bool value) { Filter filter = value ? Filter::Linear : Filter::Nearest; setMinFilter(filter); setMagFilter(filter); } void Texture::setWrapMode(enum WrapMode mode) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode); } void Texture::setRepeat(bool value) { setWrapMode(value ? WrapMode::Repeat : WrapMode::ClampToEdge); } void Texture::enable() const { glBindTexture(GL_TEXTURE_2D, m_id); } void Texture::disable() const { glBindTexture(GL_TEXTURE_2D, 0); } static unsigned int _getMaxSize() { GLint size; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size); return static_cast(size); } unsigned int Texture::getMaxSize() { static unsigned maxSize = _getMaxSize(); return maxSize; } bool Texture::operator<(const Texture* other) const { return m_id < other->m_id; } bool Texture::operator!=(const Texture* other) const { return m_id != other->m_id; } } // namespace sp