1
0
Fork 0
spectre/source/Graphics/Texture.cpp

251 lines
4.5 KiB
C++

#include <Spectre/Graphics/Image.h>
#include <Spectre/Graphics/Texture.h>
#include <Graphics/GL/gl.h>
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),
m_format (PixelFormat::PF_Unknown)
{
}
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<unsigned char> 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();
glPixelStorei(GL_UNPACK_ALIGNMENT, image.getNumChannels());
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();
glPixelStorei(GL_UNPACK_ALIGNMENT, image.getNumChannels());
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<unsigned char> 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_size.x, m_size.y, &pixels[0], m_format);
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<unsigned int>(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