From e11d43507e8a6b8939b4392a305dc27743f8186a Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 21 Sep 2019 21:48:03 -0300 Subject: [PATCH] Reorganize ImageData:set/mapPixel code so less of it is in the Lua wrapper and more of it is in the ImageData class itself. --- src/common/pixelformat.cpp | 32 +++ src/common/pixelformat.h | 5 + src/modules/image/ImageData.cpp | 352 ++++++++++++++++++++++- src/modules/image/ImageData.h | 38 ++- src/modules/image/wrap_ImageData.cpp | 407 ++++----------------------- 5 files changed, 461 insertions(+), 373 deletions(-) diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index 44f365245..8c8aa5964 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -176,4 +176,36 @@ size_t getPixelFormatSize(PixelFormat format) } } +int getPixelFormatColorComponents(PixelFormat format) +{ + switch (format) + { + case PIXELFORMAT_R8: + case PIXELFORMAT_R16: + case PIXELFORMAT_R16F: + case PIXELFORMAT_R32F: + return 1; + case PIXELFORMAT_RG8: + case PIXELFORMAT_RG16: + case PIXELFORMAT_RG16F: + case PIXELFORMAT_RG32F: + case PIXELFORMAT_LA8: + return 2; + case PIXELFORMAT_RGB565: + case PIXELFORMAT_RG11B10F: + return 3; + case PIXELFORMAT_RGBA8: + case PIXELFORMAT_sRGBA8: + case PIXELFORMAT_RGBA16: + case PIXELFORMAT_RGBA16F: + case PIXELFORMAT_RGBA32F: + case PIXELFORMAT_RGBA4: + case PIXELFORMAT_RGB5A1: + case PIXELFORMAT_RGB10A2: + return 4; + default: + return 0; + } +} + } // love diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index e10b83608..72ff472ae 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -135,4 +135,9 @@ bool isPixelFormatStencil(PixelFormat format); **/ size_t getPixelFormatSize(PixelFormat format); +/** + * Gets the number of color components in the given pixel format. + **/ +int getPixelFormatColorComponents(PixelFormat format); + } // love diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index 338ade2e8..70fa791a6 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -98,6 +98,9 @@ void ImageData::create(int width, int height, PixelFormat format, void *data) decodeHandler = nullptr; this->format = format; + + pixelSetFunction = getPixelSetFunction(format); + pixelGetFunction = getPixelGetFunction(format); } void ImageData::decode(Data *data) @@ -153,6 +156,9 @@ void ImageData::decode(Data *data) this->format = decodedimage.format; decodeHandler = decoder; + + pixelSetFunction = getPixelSetFunction(format); + pixelGetFunction = getPixelGetFunction(format); } love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encodedFormat, const char *filename, bool writefile) const @@ -253,27 +259,313 @@ bool ImageData::inside(int x, int y) const return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); } -void ImageData::setPixel(int x, int y, const Pixel &p) +static float clamp01(float x) +{ + return std::min(std::max(x, 0.0f), 1.0f); +} + +static void setPixelR8(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f); +} + +static void setPixelRG8(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f); + p->rgba8[1] = (uint8) (clamp01(c.g) * 255.0f + 0.5f); +} + +static void setPixelRGBA8(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba8[0] = (uint8) (clamp01(c.r) * 255.0f + 0.5f); + p->rgba8[1] = (uint8) (clamp01(c.g) * 255.0f + 0.5f); + p->rgba8[2] = (uint8) (clamp01(c.b) * 255.0f + 0.5f); + p->rgba8[3] = (uint8) (clamp01(c.a) * 255.0f + 0.5f); +} + +static void setPixelR16(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f); +} + +static void setPixelRG16(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f); + p->rgba16[1] = (uint16) (clamp01(c.g) * 65535.0f + 0.5f); +} + +static void setPixelRGBA16(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16[0] = (uint16) (clamp01(c.r) * 65535.0f + 0.5f); + p->rgba16[1] = (uint16) (clamp01(c.b) * 65535.0f + 0.5f); + p->rgba16[2] = (uint16) (clamp01(c.g) * 65535.0f + 0.5f); + p->rgba16[3] = (uint16) (clamp01(c.a) * 65535.0f + 0.5f); +} + +static void setPixelR16F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16f[0] = float32to16(c.r); +} + +static void setPixelRG16F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16f[0] = float32to16(c.r); + p->rgba16f[1] = float32to16(c.g); +} + +static void setPixelRGBA16F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba16f[0] = float32to16(c.r); + p->rgba16f[1] = float32to16(c.g); + p->rgba16f[2] = float32to16(c.b); + p->rgba16f[3] = float32to16(c.a); +} + +static void setPixelR32F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba32f[0] = c.r; +} + +static void setPixelRG32F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba32f[0] = c.r; + p->rgba32f[1] = c.g; +} + +static void setPixelRGBA32F(const Colorf &c, ImageData::Pixel *p) +{ + p->rgba32f[0] = c.r; + p->rgba32f[1] = c.g; + p->rgba32f[2] = c.b; + p->rgba32f[3] = c.a; +} + +static void setPixelRGBA4(const Colorf &c, ImageData::Pixel *p) +{ + // LSB->MSB: [a, b, g, r] + uint16 r = (uint16) (clamp01(c.r) * 0xF + 0.5); + uint16 g = (uint16) (clamp01(c.g) * 0xF + 0.5); + uint16 b = (uint16) (clamp01(c.b) * 0xF + 0.5); + uint16 a = (uint16) (clamp01(c.a) * 0xF + 0.5); + p->packed16 = (r << 12) | (g << 8) | (b << 4) | (a << 0); +} + +static void setPixelRGB5A1(const Colorf &c, ImageData::Pixel *p) +{ + // LSB->MSB: [a, b, g, r] + uint16 r = (uint16) (clamp01(c.r) * 0x1F + 0.5); + uint16 g = (uint16) (clamp01(c.g) * 0x1F + 0.5); + uint16 b = (uint16) (clamp01(c.b) * 0x1F + 0.5); + uint16 a = (uint16) (clamp01(c.a) * 0x1 + 0.5); + p->packed16 = (r << 11) | (g << 6) | (b << 1) | (a << 0); +} + +static void setPixelRGB565(const Colorf &c, ImageData::Pixel *p) +{ + // LSB->MSB: [b, g, r] + uint16 r = (uint16) (clamp01(c.r) * 0x1F + 0.5); + uint16 g = (uint16) (clamp01(c.g) * 0x3F + 0.5); + uint16 b = (uint16) (clamp01(c.b) * 0x1F + 0.5); + p->packed16 = (r << 11) | (g << 5) | (b << 0); +} + +static void setPixelRGB10A2(const Colorf &c, ImageData::Pixel *p) +{ + // LSB->MSB: [r, g, b, a] + uint32 r = (uint32) (clamp01(c.r) * 0x3FF + 0.5); + uint32 g = (uint32) (clamp01(c.g) * 0x3FF + 0.5); + uint32 b = (uint32) (clamp01(c.b) * 0x3FF + 0.5); + uint32 a = (uint32) (clamp01(c.a) * 0x3 + 0.5); + p->packed32 = (r << 0) | (g << 10) | (b << 20) | (a << 30); +} + +static void setPixelRG11B10F(const Colorf &c, ImageData::Pixel *p) +{ + // LSB->MSB: [r, g, b] + float11 r = float32to11(c.r); + float11 g = float32to11(c.g); + float10 b = float32to10(c.b); + p->packed32 = (r << 0) | (g << 11) | (b << 22); +} + +static void getPixelR8(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba8[0] / 255.0f; + c.g = 0.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRG8(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba8[0] / 255.0f; + c.g = p->rgba8[1] / 255.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRGBA8(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba8[0] / 255.0f; + c.g = p->rgba8[1] / 255.0f; + c.b = p->rgba8[2] / 255.0f; + c.a = p->rgba8[3] / 255.0f; +} + +static void getPixelR16(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba16[0] / 65535.0f; + c.g = 0.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRG16(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba16[0] / 65535.0f; + c.g = p->rgba16[1] / 65535.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRGBA16(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba16[0] / 65535.0f; + c.g = p->rgba16[1] / 65535.0f; + c.b = p->rgba16[2] / 65535.0f; + c.a = p->rgba16[3] / 65535.0f; +} + +static void getPixelR16F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = float16to32(p->rgba16f[0]); + c.g = 0.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRG16F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = float16to32(p->rgba16f[0]); + c.g = float16to32(p->rgba16f[1]); + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRGBA16F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = float16to32(p->rgba16f[0]); + c.g = float16to32(p->rgba16f[1]); + c.b = float16to32(p->rgba16f[2]); + c.a = float16to32(p->rgba16f[3]); +} + +static void getPixelR32F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba32f[0]; + c.g = 0.0f; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRG32F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba32f[0]; + c.g = p->rgba32f[1]; + c.b = 0.0f; + c.a = 1.0f; +} + +static void getPixelRGBA32F(const ImageData::Pixel *p, Colorf &c) +{ + c.r = p->rgba32f[0]; + c.g = p->rgba32f[1]; + c.b = p->rgba32f[2]; + c.a = p->rgba32f[3]; +} + +static void getPixelRGBA4(const ImageData::Pixel *p, Colorf &c) +{ + // LSB->MSB: [a, b, g, r] + c.r = ((p->packed16 >> 12) & 0xF) / (float)0xF; + c.g = ((p->packed16 >> 8) & 0xF) / (float)0xF; + c.b = ((p->packed16 >> 4) & 0xF) / (float)0xF; + c.a = ((p->packed16 >> 0) & 0xF) / (float)0xF; +} + +static void getPixelRGB5A1(const ImageData::Pixel *p, Colorf &c) +{ + // LSB->MSB: [a, b, g, r] + c.r = ((p->packed16 >> 11) & 0x1F) / (float)0x1F; + c.g = ((p->packed16 >> 6) & 0x1F) / (float)0x1F; + c.b = ((p->packed16 >> 1) & 0x1F) / (float)0x1F; + c.a = ((p->packed16 >> 0) & 0x1) / (float)0x1; +} + +static void getPixelRGB565(const ImageData::Pixel *p, Colorf &c) +{ + // LSB->MSB: [b, g, r] + c.r = ((p->packed16 >> 11) & 0x1F) / (float)0x1F; + c.g = ((p->packed16 >> 5) & 0x3F) / (float)0x3F; + c.b = ((p->packed16 >> 0) & 0x1F) / (float)0x1F; + c.a = 1.0f; +} + +static void getPixelRGB10A2(const ImageData::Pixel *p, Colorf &c) +{ + // LSB->MSB: [r, g, b, a] + c.r = ((p->packed32 >> 0) & 0x3FF) / (float)0x3FF; + c.g = ((p->packed32 >> 10) & 0x3FF) / (float)0x3FF; + c.b = ((p->packed32 >> 20) & 0x3FF) / (float)0x3FF; + c.a = ((p->packed32 >> 30) & 0x3) / (float)0x3; +} + +static void getPixelRG11B10F(const ImageData::Pixel *p, Colorf &c) +{ + // LSB->MSB: [r, g, b] + c.r = float11to32((float11) ((p->packed32 >> 0) & 0x7FF)); + c.g = float11to32((float11) ((p->packed32 >> 11) & 0x7FF)); + c.b = float10to32((float10) ((p->packed32 >> 22) & 0x3FF)); + c.a = 1.0f; +} + +void ImageData::setPixel(int x, int y, const Colorf &c) { 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); + Pixel *p = (Pixel *) (data + ((y * width + x) * pixelsize)); + + if (pixelSetFunction == nullptr) + throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format); Lock lock(mutex); - memcpy(pixeldata, &p, pixelsize); + + pixelSetFunction(c, p); } -void ImageData::getPixel(int x, int y, Pixel &p) const +void ImageData::getPixel(int x, int y, Colorf &c) const { if (!inside(x, y)) throw love::Exception("Attempt to get out-of-range pixel!"); size_t pixelsize = getPixelSize(); + const Pixel *p = (const Pixel *) (data + ((y * width + x) * pixelsize)); + + if (pixelGetFunction == nullptr) + throw love::Exception("Unhandled pixel format %d in ImageData::setPixel", format); Lock lock(mutex); - memcpy(&p, data + ((y * width + x) * pixelsize), pixelsize); + + pixelGetFunction(p, c); +} + +Colorf ImageData::getPixel(int x, int y) const +{ + Colorf c; + getPixel(x, y, c); + return c; } union Row @@ -521,6 +813,56 @@ bool ImageData::canPaste(PixelFormat src, PixelFormat dst) return true; } +ImageData::PixelSetFunction ImageData::getPixelSetFunction(PixelFormat format) +{ + switch (format) + { + case PIXELFORMAT_R8: return setPixelR8; + case PIXELFORMAT_RG8: return setPixelRG8; + case PIXELFORMAT_RGBA8: return setPixelRGBA8; + case PIXELFORMAT_R16: return setPixelR16; + case PIXELFORMAT_RG16: return setPixelRG16; + case PIXELFORMAT_RGBA16: return setPixelRGBA16; + case PIXELFORMAT_R16F: return setPixelR16F; + case PIXELFORMAT_RG16F: return setPixelRG16F; + case PIXELFORMAT_RGBA16F: return setPixelRGBA16F; + case PIXELFORMAT_R32F: return setPixelR32F; + case PIXELFORMAT_RG32F: return setPixelRG32F; + case PIXELFORMAT_RGBA32F: return setPixelRGBA32F; + case PIXELFORMAT_RGBA4: return setPixelRGBA4; + case PIXELFORMAT_RGB5A1: return setPixelRGB5A1; + case PIXELFORMAT_RGB565: return setPixelRGB565; + case PIXELFORMAT_RGB10A2: return setPixelRGB10A2; + case PIXELFORMAT_RG11B10F: return setPixelRG11B10F; + default: return nullptr; + } +} + +ImageData::PixelGetFunction ImageData::getPixelGetFunction(PixelFormat format) +{ + switch (format) + { + case PIXELFORMAT_R8: return getPixelR8; + case PIXELFORMAT_RG8: return getPixelRG8; + case PIXELFORMAT_RGBA8: return getPixelRGBA8; + case PIXELFORMAT_R16: return getPixelR16; + case PIXELFORMAT_RG16: return getPixelRG16; + case PIXELFORMAT_RGBA16: return getPixelRGBA16; + case PIXELFORMAT_R16F: return getPixelR16F; + case PIXELFORMAT_RG16F: return getPixelRG16F; + case PIXELFORMAT_RGBA16F: return getPixelRGBA16F; + case PIXELFORMAT_R32F: return getPixelR32F; + case PIXELFORMAT_RG32F: return getPixelRG32F; + case PIXELFORMAT_RGBA32F: return getPixelRGBA32F; + case PIXELFORMAT_RGBA4: return getPixelRGBA4; + case PIXELFORMAT_RGB5A1: return getPixelRGB5A1; + case PIXELFORMAT_RGB565: return getPixelRGB565; + case PIXELFORMAT_RGB10A2: return getPixelRGB10A2; + case PIXELFORMAT_RG11B10F: return getPixelRG11B10F; + default: return nullptr; + } +} + bool ImageData::getConstant(const char *in, FormatHandler::EncodedFormat &out) { return encodedFormats.find(in, out); diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index 2639f3d3a..a3c76627e 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -26,6 +26,7 @@ #include "common/int.h" #include "common/pixelformat.h" #include "common/floattypes.h" +#include "common/Color.h" #include "filesystem/FileData.h" #include "thread/threads.h" #include "ImageDataBase.h" @@ -38,16 +39,6 @@ namespace love namespace image { -union Pixel -{ - uint8 rgba8[4]; - uint16 rgba16[4]; - float16 rgba16f[4]; - float rgba32f[4]; - uint16 packed16; - uint32 packed32; -}; - /** * Represents raw pixel data. **/ @@ -55,6 +46,19 @@ class ImageData : public ImageDataBase { public: + union Pixel + { + uint8 rgba8[4]; + uint16 rgba16[4]; + float16 rgba16f[4]; + float rgba32f[4]; + uint16 packed16; + uint32 packed32; + }; + + typedef void (*PixelSetFunction)(const Colorf &c, Pixel *p); + typedef void (*PixelGetFunction)(const Pixel *p, Colorf &c); + static love::Type type; ImageData(Data *data); @@ -88,7 +92,7 @@ public: * @param y The location along the y-axis. * @param p The color to use for the given location. **/ - void setPixel(int x, int y, const Pixel &p); + void setPixel(int x, int y, const Colorf &p); /** * Gets the pixel at location (x,y). @@ -96,7 +100,8 @@ public: * @param y The location along the y-axis. * @return The color for the given location. **/ - void getPixel(int x, int y, Pixel &p) const; + void getPixel(int x, int y, Colorf &c) const; + Colorf getPixel(int x, int y) const; /** * Encodes raw pixel data into a given format. @@ -115,9 +120,15 @@ public: size_t getPixelSize() const; + PixelSetFunction getPixelSetFunction() const { return pixelSetFunction; } + 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); + static bool getConstant(const char *in, FormatHandler::EncodedFormat &out); static bool getConstant(FormatHandler::EncodedFormat in, const char *&out); static std::vector getConstants(FormatHandler::EncodedFormat); @@ -139,6 +150,9 @@ private: // this so we can properly delete memory allocated by the decoder. StrongRef decodeHandler; + PixelSetFunction pixelSetFunction; + PixelGetFunction pixelGetFunction; + static StringMap::Entry encodedFormatEntries[]; static StringMap encodedFormats; diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index e76ebdb2b..dcbe96882 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -88,320 +88,20 @@ int w_ImageData_getDimensions(lua_State *L) return 2; } -template -static void luax_checkpixel_unorm8(lua_State *L, int startidx, Pixel &p) -{ - for (int i = 0; i < std::min(components, 3); i++) - p.rgba8[i] = (uint8) ((luax_checknumberclamped01(L, startidx + i) * 255.0) + 0.5); - if (components > 3) - p.rgba8[3] = (uint8) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 255.0) + 0.5); -} - -template -static void luax_checkpixel_unorm16(lua_State *L, int startidx, Pixel &p) -{ - for (int i = 0; i < std::min(components, 3); i++) - p.rgba16[i] = (uint16) ((luax_checknumberclamped01(L, startidx + i) * 65535.0) + 0.5); - if (components > 3) - p.rgba16[3] = (uint16) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 65535.0) + 0.5); -} - -template -static void luax_checkpixel_float16(lua_State *L, int startidx, Pixel &p) -{ - for (int i = 0; i < std::min(components, 3); i++) - p.rgba16f[i] = float32to16((float) luaL_checknumber(L, startidx + i)); - if (components > 3) - p.rgba16f[3] = float32to16((float) luaL_optnumber(L, startidx + 3, 1.0)); -} - -template -static void luax_checkpixel_float32(lua_State *L, int startidx, Pixel &p) -{ - for (int i = 0; i < std::min(components, 3); i++) - p.rgba32f[i] = (float) luaL_checknumber(L, startidx + i); - if (components > 3) - p.rgba32f[3] = (float) luaL_optnumber(L, startidx + 3, 1.0); -} - -static void luax_checkpixel_r8(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm8<1>(L, startidx, p); -} - -static void luax_checkpixel_rg8(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm8<2>(L, startidx, p); -} - -static void luax_checkpixel_rgba8(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm8<4>(L, startidx, p); -} - -static void luax_checkpixel_r16(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm16<1>(L, startidx, p); -} - -static void luax_checkpixel_rg16(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm16<2>(L, startidx, p); -} - -static void luax_checkpixel_rgba16(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_unorm16<4>(L, startidx, p); -} - -static void luax_checkpixel_r16f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float16<1>(L, startidx, p); -} - -static void luax_checkpixel_rg16f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float16<2>(L, startidx, p); -} - -static void luax_checkpixel_rgba16f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float16<4>(L, startidx, p); -} - -static void luax_checkpixel_r32f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float32<1>(L, startidx, p); -} - -static void luax_checkpixel_rg32f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float32<2>(L, startidx, p); -} - -static void luax_checkpixel_rgba32f(lua_State *L, int startidx, Pixel &p) -{ - luax_checkpixel_float32<4>(L, startidx, p); -} - -static void luax_checkpixel_rgba4(lua_State *L, int startidx, Pixel &p) -{ - // LSB->MSB: [a, b, g, r] - uint16 r = (uint16) ((luax_checknumberclamped01(L, startidx + 0) * 0xF) + 0.5); - uint16 g = (uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0xF) + 0.5); - uint16 b = (uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0xF) + 0.5); - uint16 a = (uint16) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0xF) + 0.5); - p.packed16 = (r << 12) | (g << 8) | (b << 4) | (a << 0); -} - -static void luax_checkpixel_rgb5a1(lua_State *L, int startidx, Pixel &p) -{ - // LSB->MSB: [a, b, g, r] - uint16 r = (uint16) ((luax_checknumberclamped01(L, startidx + 0) * 0x1F) + 0.5); - uint16 g = (uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0x1F) + 0.5); - uint16 b = (uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0x1F) + 0.5); - uint16 a = (uint16) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0x1) + 0.5); - p.packed16 = (r << 11) | (g << 6) | (b << 1) | (a << 0); -} - -static void luax_checkpixel_rgb565(lua_State *L, int startidx, Pixel &p) -{ - // LSB->MSB: [b, g, r] - uint16 r = (uint16) ((luax_checknumberclamped01(L, startidx + 0) * 0x1F) + 0.5); - uint16 g = (uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0x3F) + 0.5); - uint16 b = (uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0x1F) + 0.5); - p.packed16 = (r << 11) | (g << 5) | (b << 0); -} - -static void luax_checkpixel_rgb10a2(lua_State *L, int startidx, Pixel &p) -{ - // LSB->MSB: [r, g, b, a] - uint32 r = (uint32) ((luax_checknumberclamped01(L, startidx + 0) * 0x3FF) + 0.5); - uint32 g = (uint32) ((luax_checknumberclamped01(L, startidx + 1) * 0x3FF) + 0.5); - uint32 b = (uint32) ((luax_checknumberclamped01(L, startidx + 2) * 0x3FF) + 0.5); - uint32 a = (uint32) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0x3) + 0.5); - p.packed32 = (r << 0) | (g << 10) | (b << 20) | (a << 30); -} - -static void luax_checkpixel_rg11b10f(lua_State *L, int startidx, Pixel &p) -{ - // LSB->MSB: [r, g, b] - float11 r = float32to11((float) luaL_checknumber(L, startidx + 0)); - float11 g = float32to11((float) luaL_checknumber(L, startidx + 1)); - float10 b = float32to10((float) luaL_checknumber(L, startidx + 2)); - p.packed32 = (r << 0) | (g << 11) | (b << 22); -} - -static lua_Number fillValues[] = {0.0, 0.0, 0.0, 1.0}; - -template -static int luax_pushpixel_unorm8(lua_State *L, const Pixel &p) -{ - for (int i = 0; i < components; i++) - lua_pushnumber(L, (lua_Number) p.rgba8[i] / 255.0); - for (int i = components; i < 4; i++) - lua_pushnumber(L, fillValues[i]); - return 4; -} - -template -static int luax_pushpixel_unorm16(lua_State *L, const Pixel &p) -{ - for (int i = 0; i < components; i++) - lua_pushnumber(L, (lua_Number) p.rgba16[i] / 65535.0); - for (int i = components; i < 4; i++) - lua_pushnumber(L, fillValues[i]); - return 4; -} - -template -static int luax_pushpixel_float16(lua_State *L, const Pixel &p) -{ - for (int i = 0; i < components; i++) - lua_pushnumber(L, (lua_Number) float16to32(p.rgba16f[i])); - for (int i = components; i < 4; i++) - lua_pushnumber(L, fillValues[i]); - return 4; -} - -template -static int luax_pushpixel_float32(lua_State *L, const Pixel &p) -{ - for (int i = 0; i < components; i++) - lua_pushnumber(L, (lua_Number) p.rgba32f[i]); - for (int i = components; i < 4; i++) - lua_pushnumber(L, fillValues[i]); - return 4; -} - -static int luax_pushpixel_r8(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm8<1>(L, p); -} - -static int luax_pushpixel_rg8(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm8<2>(L, p); -} - -static int luax_pushpixel_rgba8(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm8<4>(L, p); -} - -static int luax_pushpixel_r16(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm16<1>(L, p); -} - -static int luax_pushpixel_rg16(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm16<2>(L, p); -} - -static int luax_pushpixel_rgba16(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_unorm16<4>(L, p); -} - -static int luax_pushpixel_r16f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float16<1>(L, p); -} - -static int luax_pushpixel_rg16f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float16<2>(L, p); -} - -static int luax_pushpixel_rgba16f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float16<4>(L, p); -} - -static int luax_pushpixel_r32f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float32<1>(L, p); -} - -static int luax_pushpixel_rg32f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float32<2>(L, p); -} - -static int luax_pushpixel_rgba32f(lua_State *L, const Pixel &p) -{ - return luax_pushpixel_float32<4>(L, p); -} - -static int luax_pushpixel_rgba4(lua_State *L, const Pixel &p) -{ - // LSB->MSB: [a, b, g, r] - lua_pushnumber(L, ((p.packed16 >> 12) & 0xF) / (double)0xF); - lua_pushnumber(L, ((p.packed16 >> 8) & 0xF) / (double)0xF); - lua_pushnumber(L, ((p.packed16 >> 4) & 0xF) / (double)0xF); - lua_pushnumber(L, ((p.packed16 >> 0) & 0xF) / (double)0xF); - return 4; -} - -static int luax_pushpixel_rgb5a1(lua_State *L, const Pixel &p) -{ - // LSB->MSB: [a, b, g, r] - lua_pushnumber(L, ((p.packed16 >> 11) & 0x1F) / (double)0x1F); - lua_pushnumber(L, ((p.packed16 >> 6) & 0x1F) / (double)0x1F); - lua_pushnumber(L, ((p.packed16 >> 1) & 0x1F) / (double)0x1F); - lua_pushnumber(L, ((p.packed16 >> 0) & 0x1) / (double)0x1); - return 4; -} - -static int luax_pushpixel_rgb565(lua_State *L, const Pixel &p) -{ - // LSB->MSB: [b, g, r] - lua_pushnumber(L, ((p.packed16 >> 11) & 0x1F) / (double)0x1F); - lua_pushnumber(L, ((p.packed16 >> 5) & 0x3F) / (double)0x3F); - lua_pushnumber(L, ((p.packed16 >> 0) & 0x1F) / (double)0x1F); - lua_pushnumber(L, 1.0); - return 4; -} - -static int luax_pushpixel_rgb10a2(lua_State *L, const Pixel &p) -{ - // LSB->MSB: [r, g, b, a] - lua_pushnumber(L, ((p.packed32 >> 0) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed32 >> 10) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed32 >> 20) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed32 >> 30) & 0x3) / (double)0x3); - return 4; -} - -static int luax_pushpixel_rg11b10f(lua_State *L, const Pixel &p) -{ - // LSB->MSB: [r, g, b] - lua_pushnumber(L, float11to32((float11) ((p.packed32 >> 0) & 0x7FF))); - lua_pushnumber(L, float11to32((float11) ((p.packed32 >> 11) & 0x7FF))); - lua_pushnumber(L, float10to32((float10) ((p.packed32 >> 22) & 0x3FF))); - lua_pushnumber(L, 1.0); - return 4; -} - -typedef void(*checkpixel)(lua_State *L, int startidx, Pixel &p); -typedef int(*pushpixel)(lua_State *L, const Pixel &p); - -static checkpixel checkFormats[PIXELFORMAT_MAX_ENUM] = {}; -static pushpixel pushFormats[PIXELFORMAT_MAX_ENUM] = {}; - int w_ImageData_getPixel(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); int x = (int) luaL_checkinteger(L, 2); int y = (int) luaL_checkinteger(L, 3); - PixelFormat format = t->getFormat(); + Colorf c; + luax_catchexcept(L, [&](){ t->getPixel(x, y, c); }); - Pixel p; - luax_catchexcept(L, [&](){ t->getPixel(x, y, p); }); - - return pushFormats[format](L, p); + lua_pushnumber(L, c.r); + lua_pushnumber(L, c.g); + lua_pushnumber(L, c.b); + lua_pushnumber(L, c.a); + return 4; } int w_ImageData_setPixel(lua_State *L) @@ -410,23 +110,37 @@ int w_ImageData_setPixel(lua_State *L) int x = (int) luaL_checkinteger(L, 2); int y = (int) luaL_checkinteger(L, 3); - PixelFormat format = t->getFormat(); + int components = getPixelFormatColorComponents(t->getFormat()); - Pixel p; + Colorf c; if (lua_istable(L, 4)) { - for (int i = 1; i <= 4; i++) - lua_rawgeti(L, 4, i); + for (int i = 1; i <= components; i++) + lua_rawgeti(L, components, i); - checkFormats[format](L, -4, p); + c.r = (float) luaL_checknumber(L, -components); + if (components > 1) + c.g = (float) luaL_checknumber(L, (-components) + 1); + if (components > 2) + c.b = (float) luaL_checknumber(L, (-components) + 2); + if (components > 3) + c.a = (float) luaL_optnumber(L, (-components) + 3, 1.0); - lua_pop(L, 4); + lua_pop(L, components); } else - checkFormats[format](L, 4, p); + { + c.r = (float) luaL_checknumber(L, 4); + if (components > 1) + c.g = (float) luaL_checknumber(L, 5); + if (components > 2) + c.b = (float) luaL_checknumber(L, 6); + if (components > 3) + c.a = (float) luaL_optnumber(L, 7, 1.0); + } - luax_catchexcept(L, [&](){ t->setPixel(x, y, p); }); + luax_catchexcept(L, [&](){ t->setPixel(x, y, c); }); return 0; } @@ -449,9 +163,10 @@ int w_ImageData__mapPixelUnsafe(lua_State *L) int iw = t->getWidth(); PixelFormat format = t->getFormat(); + int components = getPixelFormatColorComponents(format); - auto checkpixel = checkFormats[format]; - auto pushpixel = pushFormats[format]; + auto pixelsetfunction = t->getPixelSetFunction(); + auto pixelgetfunction = t->getPixelGetFunction(); uint8 *data = (uint8 *) t->getData(); size_t pixelsize = t->getPixelSize(); @@ -460,17 +175,33 @@ int w_ImageData__mapPixelUnsafe(lua_State *L) { for (int x = sx; x < sx+w; x++) { - Pixel *pixeldata = (Pixel *) (data + (y * iw + x) * pixelsize); + auto pixeldata = (ImageData::Pixel *) (data + (y * iw + x) * pixelsize); + + Colorf c; + pixelgetfunction(pixeldata, c); lua_pushvalue(L, 2); // ImageData + lua_pushnumber(L, x); lua_pushnumber(L, y); - pushpixel(L, *pixeldata); + lua_pushnumber(L, c.r); + lua_pushnumber(L, c.g); + lua_pushnumber(L, c.b); + lua_pushnumber(L, c.a); lua_call(L, 6, 4); - checkpixel(L, -4, *pixeldata); + c.r = (float) luaL_checknumber(L, -4); + if (components > 1) + c.g = (float) luaL_checknumber(L, -3); + if (components > 2) + c.b = (float) luaL_checknumber(L, -2); + if (components > 3) + c.a = (float) luaL_optnumber(L, -1, 1.0); + + pixelsetfunction(c, pixeldata); + lua_pop(L, 4); // Pop return values. } } @@ -600,42 +331,6 @@ static const luaL_Reg w_ImageData_functions[] = extern "C" int luaopen_imagedata(lua_State *L) { - checkFormats[PIXELFORMAT_R8] = luax_checkpixel_r8; - checkFormats[PIXELFORMAT_RG8] = luax_checkpixel_rg8; - checkFormats[PIXELFORMAT_RGBA8] = luax_checkpixel_rgba8; - checkFormats[PIXELFORMAT_R16] = luax_checkpixel_r16; - checkFormats[PIXELFORMAT_RG16] = luax_checkpixel_rg16; - checkFormats[PIXELFORMAT_RGBA16] = luax_checkpixel_rgba16; - checkFormats[PIXELFORMAT_R16F] = luax_checkpixel_r16f; - checkFormats[PIXELFORMAT_RG16F] = luax_checkpixel_rg16f; - checkFormats[PIXELFORMAT_RGBA16F] = luax_checkpixel_rgba16f; - checkFormats[PIXELFORMAT_R32F] = luax_checkpixel_r32f; - checkFormats[PIXELFORMAT_RG32F] = luax_checkpixel_rg32f; - checkFormats[PIXELFORMAT_RGBA32F] = luax_checkpixel_rgba32f; - checkFormats[PIXELFORMAT_RGBA4] = luax_checkpixel_rgba4; - checkFormats[PIXELFORMAT_RGB5A1] = luax_checkpixel_rgb5a1; - checkFormats[PIXELFORMAT_RGB565] = luax_checkpixel_rgb565; - checkFormats[PIXELFORMAT_RGB10A2] = luax_checkpixel_rgb10a2; - checkFormats[PIXELFORMAT_RG11B10F] = luax_checkpixel_rg11b10f; - - pushFormats[PIXELFORMAT_R8] = luax_pushpixel_r8; - pushFormats[PIXELFORMAT_RG8] = luax_pushpixel_rg8; - pushFormats[PIXELFORMAT_RGBA8] = luax_pushpixel_rgba8; - pushFormats[PIXELFORMAT_R16] = luax_pushpixel_r16; - pushFormats[PIXELFORMAT_RG16] = luax_pushpixel_rg16; - pushFormats[PIXELFORMAT_RGBA16] = luax_pushpixel_rgba16; - pushFormats[PIXELFORMAT_R16F] = luax_pushpixel_r16f; - pushFormats[PIXELFORMAT_RG16F] = luax_pushpixel_rg16f; - pushFormats[PIXELFORMAT_RGBA16F] = luax_pushpixel_rgba16f; - pushFormats[PIXELFORMAT_R32F] = luax_pushpixel_r32f; - pushFormats[PIXELFORMAT_RG32F] = luax_pushpixel_rg32f; - pushFormats[PIXELFORMAT_RGBA32F] = luax_pushpixel_rgba32f; - pushFormats[PIXELFORMAT_RGBA4] = luax_pushpixel_rgba4; - pushFormats[PIXELFORMAT_RGB5A1] = luax_pushpixel_rgb5a1; - pushFormats[PIXELFORMAT_RGB565] = luax_pushpixel_rgb565; - pushFormats[PIXELFORMAT_RGB10A2] = luax_pushpixel_rgb10a2; - pushFormats[PIXELFORMAT_RG11B10F] = luax_pushpixel_rg11b10f; - int ret = luax_register_type(L, &ImageData::type, data::w_Data_functions, w_ImageData_functions, nullptr); love::data::luax_rundatawrapper(L, ImageData::type);