ImageData (and Images loaded from them) now support different data formats. Resolves issue #1048.

Currently exposed formats are rgba8 and rgba16 (normalized), and rgba16f and rgba32f (floating-point). Some systems, especially mobile ones, won't support every format when creating a love.graphics Image. Use love.graphics.getRawImageFormats to check for support.

love.image.newImageData now takes an optional format parameter as its third argument when creating an empty sized ImageData. It defaults to rgba8.

16-bit PNGs, .hdr images, and floating-point OpenEXR images can now be loaded via love.image.newImageData and love.graphics.newImage.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2016-05-22 15:28:20 -03:00
parent 3e6d01748e
commit e71f95595c
31 changed files with 12018 additions and 241 deletions
+66 -25
View File
@@ -38,7 +38,7 @@ ImageData::~ImageData()
size_t ImageData::getSize() const
{
return size_t(getWidth()*getHeight())*sizeof(pixel);
return size_t(getWidth() * getHeight()) * getPixelSize();
}
void *ImageData::getData() const
@@ -51,6 +51,11 @@ bool ImageData::inside(int x, int y) const
return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
}
ImageData::Format ImageData::getFormat() const
{
return format;
}
int ImageData::getWidth() const
{
return width;
@@ -61,47 +66,41 @@ int ImageData::getHeight() const
return height;
}
void ImageData::setPixel(int x, int y, pixel c)
void ImageData::setPixel(int x, int y, const Pixel &p)
{
if (!inside(x, y))
throw love::Exception("Attempt to set out-of-range pixel!");
size_t pixelsize = getPixelSize();
unsigned char *pixeldata = data + ((y * width + x) * pixelsize);
Lock lock(mutex);
pixel *pixels = (pixel *) getData();
pixels[y*width+x] = c;
memcpy(pixeldata, &p, pixelsize);
}
void ImageData::setPixelUnsafe(int x, int y, pixel c)
{
pixel *pixels = (pixel *) getData();
pixels[y*width+x] = c;
}
pixel ImageData::getPixel(int x, int y) const
void ImageData::getPixel(int x, int y, Pixel &p) const
{
if (!inside(x, y))
throw love::Exception("Attempt to get out-of-range pixel!");
size_t pixelsize = getPixelSize();
Lock lock(mutex);
const pixel *pixels = (const pixel *) getData();
return pixels[y*width+x];
}
pixel ImageData::getPixelUnsafe(int x, int y) const
{
const pixel *pixels = (const pixel *) getData();
return pixels[y*width+x];
memcpy(&p, data + ((y * width + x) * pixelsize), pixelsize);
}
void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh)
{
if (getFormat() != src->getFormat())
throw love::Exception("ImageData formats must match!");
Lock lock2(src->mutex);
Lock lock1(mutex);
pixel *s = (pixel *)src->getData();
pixel *d = (pixel *)getData();
uint8 *s = (uint8 *) src->getData();
uint8 *d = (uint8 *) getData();
size_t pixelsize = getPixelSize();
// Check bounds; if the data ends up completely out of bounds, get out early.
if (sx >= src->getWidth() || sx + sw < 0 || sy >= src->getHeight() || sy + sh < 0
@@ -150,13 +149,13 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in
if (sw == getWidth() && getWidth() == src->getWidth()
&& sh == getHeight() && getHeight() == src->getHeight())
{
memcpy(d, s, sizeof(pixel) * sw * sh);
memcpy(d, s, pixelsize * sw * sh);
}
else if (sw > 0)
{
// Otherwise, copy each row individually.
for (int i = 0; i < sh; i++)
memcpy(d + dx + (i + dy) * getWidth(), s + sx + (i + sy) * src->getWidth(), sizeof(pixel) * sw);
memcpy(d + dx + (i + dy) * getWidth(), s + (sx + (i + sy) * src->getWidth()) * pixelsize, pixelsize * sw);
}
}
@@ -165,6 +164,37 @@ love::thread::Mutex *ImageData::getMutex() const
return mutex;
}
size_t ImageData::getPixelSize() const
{
return getPixelSize(format);
}
size_t ImageData::getPixelSize(Format format)
{
switch (format)
{
case FORMAT_RGBA8:
return 4;
case FORMAT_RGBA16:
case FORMAT_RGBA16F:
return 8;
case FORMAT_RGBA32F:
return 16;
default:
return 0;
}
}
bool ImageData::getConstant(const char *in, Format &out)
{
return formats.find(in, out);
}
bool ImageData::getConstant(Format in, const char *&out)
{
return formats.find(in, out);
}
bool ImageData::getConstant(const char *in, EncodedFormat &out)
{
return encodedFormats.find(in, out);
@@ -175,6 +205,17 @@ bool ImageData::getConstant(EncodedFormat in, const char *&out)
return encodedFormats.find(in, out);
}
StringMap<ImageData::Format, ImageData::FORMAT_MAX_ENUM>::Entry ImageData::formatEntries[] =
{
{"rgba8", FORMAT_RGBA8 },
{"rgba16", FORMAT_RGBA16 },
{"rgba16f", FORMAT_RGBA16F},
{"rgba32f", FORMAT_RGBA32F},
};
StringMap<ImageData::Format, ImageData::FORMAT_MAX_ENUM> ImageData::formats(ImageData::formatEntries, sizeof(ImageData::formatEntries));
StringMap<ImageData::EncodedFormat, ImageData::ENCODED_MAX_ENUM>::Entry ImageData::encodedFormatEntries[] =
{
{"tga", ENCODED_TGA},