251 lines
4.5 KiB
C++
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
|