1
0
Fork 0

Graphics/Image: dont store PixelFormat, instead define a new enum for number of channels.

The image class has a strict internal representation so we dont need "format".
PixelFormat enum can be passed to functions that modify the pixel data (like setPixels()) so that a proper convertion can be done.
This commit is contained in:
Henrik Hautakoski 2020-10-22 13:05:41 +02:00
parent 6f9b33be8f
commit f7fcc2633c
4 changed files with 53 additions and 86 deletions

View file

@ -13,13 +13,16 @@ namespace sp {
class Image class Image
{ {
public : public :
enum Channels {
Alpha,
RGB,
RGBA
};
Image(); Image();
void create(unsigned width, unsigned height, const Color& color = Color::Black); void create(unsigned width, unsigned height, const Color& color = Color::Black, enum Channels comp = Channels::RGBA);
void create(unsigned width, unsigned height, const void* pixels, PixelFormat format = PixelFormat::PF_RGBA);
void create(unsigned width, unsigned height, const void* pixels);
void create(PixelFormat format, unsigned width, unsigned height, const Color& color = Color::Black);
void create(PixelFormat format, unsigned width, unsigned height, const void* pixels);
const Vector2u& getSize() const; const Vector2u& getSize() const;
@ -27,7 +30,7 @@ public :
unsigned int getHeight() const; unsigned int getHeight() const;
unsigned int getBpp() const; unsigned int getNumChannels() const;
unsigned int getStride() const; unsigned int getStride() const;
@ -46,7 +49,7 @@ public :
Color getPixel(unsigned x, unsigned y) const; Color getPixel(unsigned x, unsigned y) const;
void setPixels(const void* pixels); void setPixels(const void* pixels, PixelFormat format = PixelFormat::PF_RGBA);
const unsigned char* getPixels() const; const unsigned char* getPixels() const;
@ -56,7 +59,7 @@ private :
Vector2u m_size; Vector2u m_size;
PixelFormat m_format; enum Channels m_channels;
std::vector<unsigned char> m_pixels; std::vector<unsigned char> m_pixels;
}; };

View file

@ -99,10 +99,7 @@ Glyph FreeTypeEngine::loadGlyph(unsigned int codepoint, Image& img, unsigned int
FT_Glyph_To_Bitmap(&glyph_info, FT_RENDER_MODE_NORMAL, 0, true); FT_Glyph_To_Bitmap(&glyph_info, FT_RENDER_MODE_NORMAL, 0, true);
FT_Bitmap& bmp = reinterpret_cast<FT_BitmapGlyph>(glyph_info)->bitmap; FT_Bitmap& bmp = reinterpret_cast<FT_BitmapGlyph>(glyph_info)->bitmap;
img.create(PixelFormat::PF_Alpha, img.create(bmp.width, bmp.rows, bmp.buffer, PixelFormat::PF_Alpha);
bmp.width,
bmp.rows,
bmp.buffer);
glyph.offset.x = static_cast<unsigned char>(metrics.horiBearingX / (1 << 6)); glyph.offset.x = static_cast<unsigned char>(metrics.horiBearingX / (1 << 6));
glyph.offset.y = static_cast<unsigned char>(metrics.horiBearingY / (1 << 6)); glyph.offset.y = static_cast<unsigned char>(metrics.horiBearingY / (1 << 6));

View file

@ -10,17 +10,17 @@ static ImageLoader _loader;
Image::Image() : Image::Image() :
m_size (0, 0), m_size (0, 0),
m_format (PF_Unknown) m_channels (RGBA)
{ {
} }
void Image::create(unsigned width, unsigned height, const Color& color) void Image::create(unsigned width, unsigned height, const Color& color, enum Channels comp)
{ {
m_size.x = width; m_size.x = width;
m_size.y = height; m_size.y = height;
m_format = PixelFormat::PF_RGBA; m_channels = comp;
m_pixels.resize(m_size.x * m_size.y * (getBpp() / 8)); m_pixels.resize(m_size.x * m_size.y * getNumChannels());
for(size_t i = 0; i < m_pixels.size(); i += 4) { for(size_t i = 0; i < m_pixels.size(); i += 4) {
@ -31,48 +31,12 @@ void Image::create(unsigned width, unsigned height, const Color& color)
} }
} }
void Image::create(unsigned width, unsigned height, const void* pixels) void Image::create(unsigned width, unsigned height, const void* pixels, PixelFormat format)
{
create(PixelFormat::PF_RGBA, width, height, pixels);
}
void Image::create(PixelFormat format, unsigned width, unsigned height, const Color& color)
{ {
m_size.x = width; m_size.x = width;
m_size.y = height; m_size.y = height;
m_format = format;
m_pixels.resize(m_size.x * m_size.y * (getBpp() / 8)); setPixels(pixels, format);
if (getBpp() == 32) {
for(size_t i = 0; i < m_pixels.size(); i += 4) {
m_pixels[i+0] = color.r;
m_pixels[i+1] = color.g;
m_pixels[i+2] = color.b;
m_pixels[i+3] = color.a;
}
} else if (getBpp() == 24) {
for(size_t i = 0; i < m_pixels.size(); i += 3) {
m_pixels[i+0] = color.r;
m_pixels[i+1] = color.g;
m_pixels[i+2] = color.b;
}
} else {
for(size_t i = 0; i < m_pixels.size(); i += 1) {
m_pixels[i] = color.a;
}
}
}
void Image::create(PixelFormat format, unsigned width, unsigned height, const void* pixels)
{
m_size.x = width;
m_size.y = height;
m_format = format;
setPixels(pixels);
} }
const Vector2u& Image::getSize() const const Vector2u& Image::getSize() const
@ -90,31 +54,36 @@ unsigned int Image::getHeight() const
return m_size.y; return m_size.y;
} }
unsigned int Image::getBpp() const unsigned int Image::getNumChannels() const
{ {
switch(m_format) { switch(m_channels) {
case PixelFormat::PF_RGBA : return 32; case Channels::RGBA : return 4;
case PixelFormat::PF_RGB : return 24; case Channels::RGB : return 3;
case PixelFormat::PF_Alpha : return 8; case Channels::Alpha :
case PixelFormat::PF_Unknown :
default : break; default : break;
} }
return 0; return 1;
} }
unsigned int Image::getStride() const unsigned int Image::getStride() const
{ {
return m_size.x * (getBpp() / 8); return m_size.x * getNumChannels();
} }
PixelFormat Image::getFormat() const PixelFormat Image::getFormat() const
{ {
return m_format; switch(m_channels) {
case Channels::RGBA : return PixelFormat::PF_RGBA;
case Channels::RGB : return PixelFormat::PF_RGB;
case Channels::Alpha :
default : break;
}
return PixelFormat::PF_Alpha;
} }
bool Image::hasAlpha() const bool Image::hasAlpha() const
{ {
return m_format == PixelFormat::PF_RGBA || m_format == PixelFormat::PF_Alpha; return m_channels != Channels::RGB;
} }
bool Image::loadFromFile(const std::string& filename) bool Image::loadFromFile(const std::string& filename)
@ -138,17 +107,17 @@ void Image::saveToFile(const std::string& filename) const
void Image::setPixel(unsigned x, unsigned y, const Color& c) void Image::setPixel(unsigned x, unsigned y, const Color& c)
{ {
unsigned char *base = m_pixels.data() + ((getBpp() / 8) * ((y * m_size.x) + x)); unsigned char *base = m_pixels.data() + (getNumChannels() * ((y * m_size.x) + x));
if (m_format == PixelFormat::PF_RGB || m_format == PixelFormat::PF_RGBA) { if (m_channels == RGB || m_channels == RGBA) {
base[0] = c.r; base[0] = c.r;
base[1] = c.g; base[1] = c.g;
base[2] = c.b; base[2] = c.b;
if (m_format == PixelFormat::PF_RGBA) { if (m_channels == RGBA) {
base[3] = c.a; base[3] = c.a;
} }
} }
else if (m_format == PixelFormat::PF_Alpha) { else if (m_channels == Alpha) {
base[0] = c.a; base[0] = c.a;
} }
} }
@ -156,21 +125,21 @@ void Image::setPixel(unsigned x, unsigned y, const Color& c)
Color Image::getPixel(unsigned x, unsigned y) const Color Image::getPixel(unsigned x, unsigned y) const
{ {
Color c; Color c;
const unsigned char *base = m_pixels.data() + ((getBpp() / 8) * ((y * m_size.x) + x)); const unsigned char *base = m_pixels.data() + (getNumChannels() * ((y * m_size.x) + x));
// RGB / RGBA formats. // RGB / RGBA formats.
if (m_format == PixelFormat::PF_RGB || m_format == PixelFormat::PF_RGBA) { if (m_channels == RGB || m_channels == RGBA) {
c.r = base[0]; c.r = base[0];
c.g = base[1]; c.g = base[1];
c.b = base[2]; c.b = base[2];
if (m_format == PixelFormat::PF_RGBA) { if (m_channels == RGBA) {
c.a = base[3]; c.a = base[3];
} else { } else {
c.a = 255; c.a = 255;
} }
} }
// Alpha, single channel format. // Alpha, single channel format.
else if (m_format == PixelFormat::PF_Alpha) { else if (m_channels == Alpha) {
c = Color(0, 0, 0, base[0]); c = Color(0, 0, 0, base[0]);
} }
return c; return c;
@ -194,11 +163,17 @@ void Image::flipY()
} }
} }
void Image::setPixels(const void *pixels) void Image::setPixels(const void *pixels, PixelFormat format)
{ {
unsigned int size = m_size.y * getStride(); if (format == PixelFormat::PF_RGB) {
m_channels = RGB;
} else if (format == PixelFormat::PF_RGBA) {
m_channels = RGBA;
} else if (format == PixelFormat::PF_Alpha) {
m_channels = Alpha;
}
m_pixels.resize(size); m_pixels.resize(m_size.y * getStride());
memcpy(&m_pixels[0], pixels, m_pixels.size()); memcpy(&m_pixels[0], pixels, m_pixels.size());
} }

View file

@ -89,11 +89,7 @@ void Texture::create(const Image& image)
enable(); enable();
if (image.getBpp() == 32) { glPixelStorei(GL_UNPACK_ALIGNMENT, image.getNumChannels());
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
srcFormat = pixelFormatToGL(image.getFormat()); srcFormat = pixelFormatToGL(image.getFormat());
glFormat = pixelFormatToInternal(image.getFormat()); glFormat = pixelFormatToInternal(image.getFormat());
@ -149,11 +145,7 @@ void Texture::update(vec2u pos, const Image& image)
enable(); enable();
if (image.getFormat() == PixelFormat::PF_RGBA) { glPixelStorei(GL_UNPACK_ALIGNMENT, image.getNumChannels());
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
format = pixelFormatToGL(image.getFormat()); format = pixelFormatToGL(image.getFormat());
@ -185,7 +177,7 @@ Image Texture::copyToImage() const
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
&pixels[0]); &pixels[0]);
img.create(m_format, m_size.x, m_size.y, &pixels[0]); img.create(m_size.x, m_size.y, &pixels[0], m_format);
disable(); disable();
} }