When writing the X11 (linux) implementation there was a problem with X11 defining a "Display" type and we also have a Display class in the engine. So to fix that problem and minimize the risk for running into other name conflicts. We move everything from global namespace.
258 lines
No EOL
4.6 KiB
C++
258 lines
No EOL
4.6 KiB
C++
|
|
#include <Spectre/Graphics/Image.h>
|
|
#include <Spectre/Graphics/OpenGL.h>
|
|
#include <Spectre/Graphics/Texture.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)
|
|
{
|
|
}
|
|
|
|
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();
|
|
|
|
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<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_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<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
|