From e61a664a8b7d18f21f911b81b0722be054ab1496 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 18 Apr 2022 10:46:02 -0300 Subject: [PATCH] ImageData: limited support for integer pixel formats. For now this doesn't support conversions (get/set/mapPixel, etc). Just the ability for ImageData to contain integer pixel contents, for example via Canvas:newImageData. --- src/common/pixelformat.cpp | 12 ++++++ src/common/pixelformat.h | 10 +++++ src/modules/image/ImageData.cpp | 60 +++++----------------------- src/modules/image/ImageData.h | 1 - src/modules/image/wrap_ImageData.lua | 12 ++++-- 5 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index e9b8f7df6..a26f7f1ad 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -240,11 +240,23 @@ const PixelFormatInfo &getPixelFormatInfo(PixelFormat format) return formatInfo[format]; } +const char *getPixelFormatName(PixelFormat format) +{ + const char *name = "unknown"; + getConstant(format, name); + return name; +} + bool isPixelFormatCompressed(PixelFormat format) { return formatInfo[format].compressed; } +bool isPixelFormatColor(PixelFormat format) +{ + return formatInfo[format].color; +} + bool isPixelFormatDepthStencil(PixelFormat format) { const PixelFormatInfo &info = formatInfo[format]; diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index 355acc383..bb3687f49 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -157,11 +157,21 @@ bool getConstant(const char *in, PixelFormat &out); const PixelFormatInfo &getPixelFormatInfo(PixelFormat format); +/** + * Gets the name of the specified pixel format. + **/ +const char *getPixelFormatName(PixelFormat format); + /** * Gets whether the specified pixel format is a compressed type. **/ bool isPixelFormatCompressed(PixelFormat format); +/** + * Gets whether the specified pixel format is a color type. + **/ +bool isPixelFormatColor(PixelFormat format); + /** * Gets whether the specified pixel format is a depth or stencil type. **/ diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index ec24d87f1..2a5be2819 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -43,7 +43,7 @@ ImageData::ImageData(int width, int height, PixelFormat format) : ImageDataBase(format, width, height) { if (!validPixelFormat(format)) - throw love::Exception("Unsupported pixel format for ImageData"); + throw love::Exception("ImageData does not support the %s pixel format.", getPixelFormatName(format)); create(width, height, format); @@ -55,7 +55,7 @@ ImageData::ImageData(int width, int height, PixelFormat format, void *data, bool : ImageDataBase(format, width, height) { if (!validPixelFormat(format)) - throw love::Exception("Unsupported pixel format for ImageData"); + throw love::Exception("ImageData does not support the %s pixel format.", getPixelFormatName(format)); if (own) this->data = (unsigned char *) data; @@ -196,11 +196,7 @@ love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encod } if (encoder == nullptr || encodedimage.data == nullptr) - { - const char *fname = "unknown"; - love::getConstant(format, fname); - throw love::Exception("No suitable image encoder for %s format.", fname); - } + throw love::Exception("No suitable image encoder for the %s pixel format.", getPixelFormatName(format)); love::filesystem::FileData *filedata = nullptr; @@ -540,7 +536,7 @@ void ImageData::setPixel(int x, int y, const Colorf &c) Pixel *p = (Pixel *) (data + ((y * width + x) * pixelsize)); if (pixelSetFunction == nullptr) - throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format); + throw love::Exception("ImageData:setPixel does not currently support the %s pixel format.", getPixelFormatName(format)); Lock lock(mutex); @@ -556,7 +552,7 @@ void ImageData::getPixel(int x, int y, Colorf &c) const const Pixel *p = (const Pixel *) (data + ((y * width + x) * pixelsize)); if (pixelGetFunction == nullptr) - throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format); + throw love::Exception("ImageData:getPixel does not currently support the %s pixel format.", getPixelFormatName(format)); Lock lock(mutex); @@ -759,7 +755,7 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in else if (srcformat == PIXELFORMAT_RGBA32_FLOAT && dstformat == PIXELFORMAT_RGBA16_FLOAT) pasteRGBA32FtoRGBA16F(rowsrc, rowdst, sw); - else + else if (getfunction != nullptr && setfunction != nullptr) { // Slow path: convert src -> Colorf -> dst. Colorf c; @@ -771,6 +767,10 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in setfunction(c, dstp); } } + else if (getfunction == nullptr) + throw love::Exception("ImageData:paste does not currently support converting from the %s pixel format.", getPixelFormatName(srcformat)); + else + throw love::Exception("ImageData:paste does not currently support converting to the %s pixel format.", getPixelFormatName(dstformat)); } } } @@ -787,45 +787,7 @@ size_t ImageData::getPixelSize() const bool ImageData::validPixelFormat(PixelFormat format) { - switch (format) - { - case PIXELFORMAT_R8_UNORM: - case PIXELFORMAT_RG8_UNORM: - case PIXELFORMAT_RGBA8_UNORM: - case PIXELFORMAT_R16_UNORM: - case PIXELFORMAT_RG16_UNORM: - case PIXELFORMAT_RGBA16_UNORM: - case PIXELFORMAT_R16_FLOAT: - case PIXELFORMAT_RG16_FLOAT: - case PIXELFORMAT_RGBA16_FLOAT: - case PIXELFORMAT_R32_FLOAT: - case PIXELFORMAT_RG32_FLOAT: - case PIXELFORMAT_RGBA32_FLOAT: - case PIXELFORMAT_RGBA4_UNORM: - case PIXELFORMAT_RGB5A1_UNORM: - case PIXELFORMAT_RGB565_UNORM: - case PIXELFORMAT_RGB10A2_UNORM: - case PIXELFORMAT_RG11B10_FLOAT: - return true; - default: - return false; - } -} - -bool ImageData::canPaste(PixelFormat src, PixelFormat dst) -{ - if (src == dst) - return true; - - if (!(src == PIXELFORMAT_RGBA8_UNORM || src == PIXELFORMAT_RGBA16_UNORM - || src == PIXELFORMAT_RGBA16_FLOAT || src == PIXELFORMAT_RGBA32_FLOAT)) - return false; - - if (!(dst == PIXELFORMAT_RGBA8_UNORM || dst == PIXELFORMAT_RGBA16_UNORM - || dst == PIXELFORMAT_RGBA16_FLOAT || dst == PIXELFORMAT_RGBA32_FLOAT)) - return false; - - return true; + return isPixelFormatColor(format) && !isPixelFormatCompressed(format); } ImageData::PixelSetFunction ImageData::getPixelSetFunction(PixelFormat format) diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index e3e04c395..83769e797 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -124,7 +124,6 @@ public: PixelGetFunction getPixelGetFunction() const { return pixelGetFunction; } static bool validPixelFormat(PixelFormat format); - static bool canPaste(PixelFormat src, PixelFormat dst); static PixelSetFunction getPixelSetFunction(PixelFormat format); static PixelGetFunction getPixelGetFunction(PixelFormat format); diff --git a/src/modules/image/wrap_ImageData.lua b/src/modules/image/wrap_ImageData.lua index 5d5cac8a9..5092944da 100644 --- a/src/modules/image/wrap_ImageData.lua +++ b/src/modules/image/wrap_ImageData.lua @@ -368,9 +368,9 @@ local objectcache = setmetatable({}, { width = width, height = height, format = format, - pointer = ffi.cast(conv.pointer, imagedata:getFFIPointer()), - tolua = conv.tolua, - fromlua = conv.fromlua, + pointer = conv == nil and nil or ffi.cast(conv.pointer, imagedata:getFFIPointer()), + tolua = conv == nil and nil or conv.tolua, + fromlua = conv == nil and nil or conv.fromlua, } self[imagedata] = p @@ -395,6 +395,8 @@ function ImageData:_mapPixelUnsafe(func, ix, iy, iw, ih) local p = objectcache[self] local idw, idh = p.width, p.height + if p.pointer == nil then error("ImageData:mapPixel does not currently support the "..p.format.." pixel format.", 2) end + ix = floor(ix) iy = floor(iy) iw = floor(iw) @@ -423,6 +425,8 @@ function ImageData:getPixel(x, y) local p = objectcache[self] if not inside(x, y, p.width, p.height) then error("Attempt to get out-of-range pixel!", 2) end + if p.pointer == nil then error("ImageData:getPixel does not currently support the "..p.format.." pixel format.", 2) end + ffifuncs.lockMutex(self) local pixel = p.pointer[y * p.width + x] local r, g, b, a = p.tolua(pixel) @@ -451,6 +455,8 @@ function ImageData:setPixel(x, y, r, g, b, a) local p = objectcache[self] if not inside(x, y, p.width, p.height) then error("Attempt to set out-of-range pixel!", 2) end + if p.pointer == nil then error("ImageData:setPixel does not currently support the "..p.format.." pixel format.", 2) end + ffifuncs.lockMutex(self) p.fromlua(p.pointer[y * p.width + x], r, g, b, a) ffifuncs.unlockMutex(self)