1
0
Fork 0
spectre/source/Graphics/Image.cpp
Henrik Hautakoski c731cda1a2 Spectre/Graphics/PixelFormat: Rework
source/Graphics/Image/IcoFormat.cpp: use new PixelFormat.
source/Graphics/Image.cpp: update to confirm with new PixelFormat
Spectre/Graphics/PixelFormat: add PF_getNumChannels()
Spectre/Graphics/PixelFormat: Rework the enum with proper naming convention and documentation.
2020-11-03 14:23:38 +01:00

207 lines
3.9 KiB
C++

#include <cstring>
#include <Spectre/System/Log.h>
#include <Spectre/Graphics/Image.h>
#include "ImageLoader.h"
namespace sp {
static ImageLoader _loader;
Image::Image() :
m_size (0, 0),
m_channels (RGBA)
{
}
void Image::create(unsigned width, unsigned height, const Color& color, enum Channels comp)
{
m_size.x = width;
m_size.y = height;
m_channels = comp;
m_pixels.resize(m_size.x * m_size.y * getNumChannels());
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;
}
}
void Image::create(unsigned width, unsigned height, const void* pixels, PixelFormat format)
{
m_size.x = width;
m_size.y = height;
setPixels(pixels, format);
}
const Vector2u& Image::getSize() const
{
return m_size;
}
unsigned int Image::getWidth() const
{
return m_size.x;
}
unsigned int Image::getHeight() const
{
return m_size.y;
}
unsigned int Image::getNumChannels() const
{
switch(m_channels) {
case Channels::RGBA : return 4;
case Channels::RGB : return 3;
case Channels::Alpha :
default : break;
}
return 1;
}
unsigned int Image::getStride() const
{
return m_size.x * getNumChannels();
}
PixelFormat Image::getFormat() const
{
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
{
return m_channels != Channels::RGB;
}
bool Image::loadFromFile(const std::string& filename)
{
m_pixels.clear();
return _loader.loadFromFile(filename.c_str(), *this);
}
bool Image::loadFromMemory(const void *data, unsigned int size)
{
m_pixels.clear();
return _loader.loadFromMemory(data, size, *this);
}
void Image::saveToFile(const std::string& filename) const
{
_loader.saveToFile(*this, filename.c_str());
}
void Image::setPixel(unsigned x, unsigned y, const Color& c)
{
unsigned char *base = m_pixels.data() + (getNumChannels() * ((y * m_size.x) + x));
if (m_channels == RGB || m_channels == RGBA) {
base[0] = c.r;
base[1] = c.g;
base[2] = c.b;
if (m_channels == RGBA) {
base[3] = c.a;
}
}
else if (m_channels == Alpha) {
base[0] = c.a;
}
}
Color Image::getPixel(unsigned x, unsigned y) const
{
Color c;
const unsigned char *base = m_pixels.data() + (getNumChannels() * ((y * m_size.x) + x));
// RGB / RGBA formats.
if (m_channels == RGB || m_channels == RGBA) {
c.r = base[0];
c.g = base[1];
c.b = base[2];
if (m_channels == RGBA) {
c.a = base[3];
} else {
c.a = 255;
}
}
// Alpha, single channel format.
else if (m_channels == Alpha) {
c = Color(0, 0, 0, base[0]);
}
return c;
}
void Image::flipY()
{
unsigned int stride = getStride();
// The quick and dirty way :)
for(size_t y = 0; y < m_size.y / 2; y++) {
int row0 = y * stride;
int row1 = (m_size.y - y - 1) * stride;
for(size_t x = 0; x < stride; x++) {
unsigned char tmp = m_pixels[row0 + x];
m_pixels[row0 + x] = m_pixels[row1 + x];
m_pixels[row1 + x] = tmp;
}
}
}
void Image::setPixels(const void *pixels, PixelFormat format)
{
switch(PF_getNumChannels(format)) {
case 4:
m_channels = RGBA;
break;
case 3:
m_channels = RGB;
break;
default :
m_channels = Alpha;
}
m_pixels.resize(m_size.y * getStride());
// TODO: Move pixel format convertion to it's own function(s)
if (format == PixelFormat::PF_BGR || format == PixelFormat::PF_BGRA) {
const uint8_t *ptr = (const uint8_t *) pixels;
for(int i = 0; i < m_pixels.size(); i += 4) {
m_pixels[i+0] = ptr[2];
m_pixels[i+1] = ptr[1];
m_pixels[i+2] = ptr[0];
if (format == PixelFormat::PF_BGRA) {
m_pixels[i+3] = ptr[3];
}
ptr += 4;
}
} else {
memcpy(&m_pixels[0], pixels, m_pixels.size());
}
}
const unsigned char* Image::getPixels() const
{
if (m_pixels.size()) {
return &m_pixels[0];
}
return NULL;
}
} // namespace sp