From 372a55c6ac50fd8898f7d5358c913f45eb58c869 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 28 Apr 2019 12:09:16 -0300 Subject: [PATCH] ImageData supports more formats: r8, rg8, r16, rg16, r16f, rg16f, r32f, rg32f. Format conversion via ImageData:paste is not supported for those (yet). --- src/modules/image/ImageData.cpp | 160 ++++++++++++---------- src/modules/image/ImageData.h | 24 ---- src/modules/image/wrap_ImageData.cpp | 192 +++++++++++++++++++++++---- src/modules/image/wrap_ImageData.lua | 112 +++++++++++++--- 4 files changed, 348 insertions(+), 140 deletions(-) diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index e3b01ce2a..06d44e44c 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -284,6 +284,86 @@ void ImageData::getPixel(int x, int y, Pixel &p) const memcpy(&p, data + ((y * width + x) * pixelsize), pixelsize); } +union Row +{ + uint8 *u8; + uint16 *u16; + half *f16; + float *f32; +}; + +static void pasteRGBA8toRGBA16(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u16[i] = (uint16) src.u8[i] << 8u; +} + +static void pasteRGBA8toRGBA16F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f16[i] = floatToHalf(src.u8[i] / 255.0f); +} + +static void pasteRGBA8toRGBA32F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f32[i] = src.u8[i] / 255.0f; +} + +static void pasteRGBA16toRGBA8(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u8[i] = src.u16[i] >> 8u; +} + +static void pasteRGBA16toRGBA16F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f16[i] = floatToHalf(src.u16[i] / 65535.0f); +} + +static void pasteRGBA16toRGBA32F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f32[i] = src.u16[i] / 65535.0f; +} + +static void pasteRGBA16FtoRGBA8(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u8[i] = (uint8) (halfToFloat(src.f16[i]) * 255.0f); +} + +static void pasteRGBA16FtoRGBA16(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u16[i] = (uint16) (halfToFloat(src.f16[i]) * 65535.0f); +} + +static void pasteRGBA16FtoRGBA32F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f32[i] = halfToFloat(src.f16[i]); +} + +static void pasteRGBA32FtoRGBA8(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u8[i] = (uint8) (src.f32[i] * 255.0f); +} + +static void pasteRGBA32FtoRGBA16(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.u16[i] = (uint16) (src.f32[i] * 65535.0f); +} + +static void pasteRGBA32FtoRGBA16F(Row src, Row dst, int w) +{ + for (int i = 0; i < w * 4; i++) + dst.f16[i] = (uint16) floatToHalf(src.f32[i]); +} + void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh) { PixelFormat dstformat = getFormat(); @@ -396,78 +476,6 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in } } -void ImageData::pasteRGBA8toRGBA16(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u16[i] = (uint16) src.u8[i] << 8u; -} - -void ImageData::pasteRGBA8toRGBA16F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f16[i] = floatToHalf(src.u8[i] / 255.0f); -} - -void ImageData::pasteRGBA8toRGBA32F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f32[i] = src.u8[i] / 255.0f; -} - -void ImageData::pasteRGBA16toRGBA8(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u8[i] = src.u16[i] >> 8u; -} - -void ImageData::pasteRGBA16toRGBA16F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f16[i] = floatToHalf(src.u16[i] / 65535.0f); -} - -void ImageData::pasteRGBA16toRGBA32F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f32[i] = src.u16[i] / 65535.0f; -} - -void ImageData::pasteRGBA16FtoRGBA8(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u8[i] = (uint8) (halfToFloat(src.f16[i]) * 255.0f); -} - -void ImageData::pasteRGBA16FtoRGBA16(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u16[i] = (uint16) (halfToFloat(src.f16[i]) * 65535.0f); -} - -void ImageData::pasteRGBA16FtoRGBA32F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f32[i] = halfToFloat(src.f16[i]); -} - -void ImageData::pasteRGBA32FtoRGBA8(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u8[i] = (uint8) (src.f32[i] * 255.0f); -} - -void ImageData::pasteRGBA32FtoRGBA16(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.u16[i] = (uint16) (src.f32[i] * 65535.0f); -} - -void ImageData::pasteRGBA32FtoRGBA16F(Row src, Row dst, int w) -{ - for (int i = 0; i < w * 4; i++) - dst.f16[i] = (uint16) floatToHalf(src.f32[i]); -} - love::thread::Mutex *ImageData::getMutex() const { return mutex; @@ -482,9 +490,17 @@ bool ImageData::validPixelFormat(PixelFormat format) { switch (format) { + case PIXELFORMAT_R8: + case PIXELFORMAT_RG8: case PIXELFORMAT_RGBA8: + case PIXELFORMAT_R16: + case PIXELFORMAT_RG16: case PIXELFORMAT_RGBA16: + case PIXELFORMAT_R16F: + case PIXELFORMAT_RG16F: case PIXELFORMAT_RGBA16F: + case PIXELFORMAT_R32F: + case PIXELFORMAT_RG32F: case PIXELFORMAT_RGBA32F: return true; default: diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index 78c970cad..a7bc9042b 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -121,14 +121,6 @@ public: private: - union Row - { - uint8 *u8; - uint16 *u16; - half *f16; - float *f32; - }; - // Create imagedata. Initialize with data if not null. void create(int width, int height, PixelFormat format, void *data = nullptr); @@ -144,22 +136,6 @@ private: // this so we can properly delete memory allocated by the decoder. StrongRef decodeHandler; - static void pasteRGBA8toRGBA16(Row src, Row dst, int w); - static void pasteRGBA8toRGBA16F(Row src, Row dst, int w); - static void pasteRGBA8toRGBA32F(Row src, Row dst, int w); - - static void pasteRGBA16toRGBA8(Row src, Row dst, int w); - static void pasteRGBA16toRGBA16F(Row src, Row dst, int w); - static void pasteRGBA16toRGBA32F(Row src, Row dst, int w); - - static void pasteRGBA16FtoRGBA8(Row src, Row dst, int w); - static void pasteRGBA16FtoRGBA16(Row src, Row dst, int w); - static void pasteRGBA16FtoRGBA32F(Row src, Row dst, int w); - - static void pasteRGBA32FtoRGBA8(Row src, Row dst, int w); - static void pasteRGBA32FtoRGBA16(Row src, Row dst, int w); - static void pasteRGBA32FtoRGBA16F(Row src, Row dst, int w); - static StringMap::Entry encodedFormatEntries[]; static StringMap encodedFormats; diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index 68fefbd0b..ddf493f95 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -88,64 +88,192 @@ 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); + if (components > 3) + p.rgba8[3] = (uint8) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 255.0); +} + +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); + if (components > 3) + p.rgba16[3] = (uint16) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 65535.0); +} + +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] = floatToHalf((float) luaL_checknumber(L, startidx + i)); + if (components > 3) + p.rgba16f[3] = floatToHalf((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) { - for (int i = 0; i < 3; i++) - p.rgba8[i] = (uint8) (luax_checknumberclamped01(L, startidx + i) * 255.0); + luax_checkpixel_unorm8<4>(L, startidx, p); +} - p.rgba8[3] = (uint8) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 255.0); +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) { - for (int i = 0; i < 3; i++) - p.rgba16[i] = (uint16) (luax_checknumberclamped01(L, startidx + i) * 65535.0); + luax_checkpixel_unorm16<4>(L, startidx, p); +} - p.rgba16[3] = (uint16) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 65535.0); +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) { - for (int i = 0; i < 3; i++) - p.rgba16f[i] = floatToHalf((float) luaL_checknumber(L, startidx + i)); + luax_checkpixel_float16<4>(L, startidx, p); +} - p.rgba16f[3] = floatToHalf((float) luaL_optnumber(L, startidx + 3, 1.0)); +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) { - for (int i = 0; i < 3; i++) - p.rgba32f[i] = (float) luaL_checknumber(L, startidx + i); + luax_checkpixel_float32<4>(L, startidx, p); +} - p.rgba32f[3] = (float) luaL_optnumber(L, startidx + 3, 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); + return components; +} + +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); + return components; +} + +template +static int luax_pushpixel_float16(lua_State *L, const Pixel &p) +{ + for (int i = 0; i < components; i++) + lua_pushnumber(L, (lua_Number) halfToFloat(p.rgba16f[i])); + return components; +} + +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]); + return components; +} + +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) { - for (int i = 0; i < 4; i++) - lua_pushnumber(L, (lua_Number) p.rgba8[i] / 255.0); - return 4; + 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) { - for (int i = 0; i < 4; i++) - lua_pushnumber(L, (lua_Number) p.rgba16[i] / 65535.0); - return 4; + 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) { - for (int i = 0; i < 4; i++) - lua_pushnumber(L, (lua_Number) halfToFloat(p.rgba16f[i])); - return 4; + 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) { - for (int i = 0; i < 4; i++) - lua_pushnumber(L, (lua_Number) p.rgba32f[i]); - return 4; + return luax_pushpixel_float32<4>(L, p); } typedef void(*checkpixel)(lua_State *L, int startidx, Pixel &p); @@ -354,14 +482,30 @@ 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; + 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; int ret = luax_register_type(L, &ImageData::type, data::w_Data_functions, w_ImageData_functions, nullptr); diff --git a/src/modules/image/wrap_ImageData.lua b/src/modules/image/wrap_ImageData.lua index d5c47464b..63ff3c6de 100644 --- a/src/modules/image/wrap_ImageData.lua +++ b/src/modules/image/wrap_ImageData.lua @@ -86,32 +86,47 @@ typedef struct FFI_ImageData half (*floatToHalf)(float f); } FFI_ImageData; -typedef struct ImageData_Pixel_RGBA8 -{ - uint8_t r, g, b, a; -} ImageData_Pixel_RGBA8; +struct ImageData_Pixel_R8 { uint8_t r; }; +struct ImageData_Pixel_RG8 { uint8_t r, g; }; +struct ImageData_Pixel_RGBA8 { uint8_t r, g, b, a; }; -typedef struct ImageData_Pixel_RGBA16 -{ - uint16_t r, g, b, a; -} ImageData_Pixel_RGBA16; +struct ImageData_Pixel_R16 { uint16_t r; }; +struct ImageData_Pixel_RG16 { uint16_t r, g; }; +struct ImageData_Pixel_RGBA16 { uint16_t r, g, b, a; }; -typedef struct ImageData_Pixel_RGBA16F -{ - half r, g, b, a; -} ImageData_Pixel_RGBA16F; +struct ImageData_Pixel_R16F { half r; }; +struct ImageData_Pixel_RG16F { half r, g; }; +struct ImageData_Pixel_RGBA16F { half r, g, b, a; }; -typedef struct ImageData_Pixel_RGBA32F -{ - float r, g, b, a; -} ImageData_Pixel_RGBA32F; +struct ImageData_Pixel_R32F { float r; }; +struct ImageData_Pixel_RG32F { float r, g; }; +struct ImageData_Pixel_RGBA32F { float r, g, b, a; }; ]]) local ffifuncs = ffi.cast("FFI_ImageData *", ffifuncspointer) local conversions = { + r8 = { + pointer = ffi.typeof("struct ImageData_Pixel_R8 *"), + tolua = function(self) + return tonumber(self.r) / 255, 0, 0, 1 + end, + fromlua = function(self, r) + self.r = clamp01(r) * 255 + end, + }, + rg8 = { + pointer = ffi.typeof("struct ImageData_Pixel_RG8 *"), + tolua = function(self) + return tonumber(self.r) / 255, tonumber(self.g) / 255, 0, 1 + end, + fromlua = function(self, r, g) + self.r = clamp01(r) * 255 + self.g = clamp01(g) * 255 + end, + }, rgba8 = { - pointer = ffi.typeof("ImageData_Pixel_RGBA8 *"), + pointer = ffi.typeof("struct ImageData_Pixel_RGBA8 *"), tolua = function(self) return tonumber(self.r) / 255, tonumber(self.g) / 255, tonumber(self.b) / 255, tonumber(self.a) / 255 end, @@ -122,8 +137,27 @@ local conversions = { self.a = a == nil and 255 or clamp01(a) * 255 end, }, + r16 = { + pointer = ffi.typeof("struct ImageData_Pixel_R16 *"), + tolua = function(self) + return tonumber(self.r) / 65535, 0, 0, 1 + end, + fromlua = function(self, r) + self.r = clamp01(r) * 65535 + end, + }, + rg16 = { + pointer = ffi.typeof("struct ImageData_Pixel_RG16 *"), + tolua = function(self) + return tonumber(self.r) / 65535, tonumber(self.g) / 65535, 0, 1 + end, + fromlua = function(self, r, g) + self.r = clamp01(r) * 65535 + self.g = clamp01(g) * 65535 + end, + }, rgba16 = { - pointer = ffi.typeof("ImageData_Pixel_RGBA16 *"), + pointer = ffi.typeof("struct ImageData_Pixel_RGBA16 *"), tolua = function(self) return tonumber(self.r) / 65535, tonumber(self.g) / 65535, tonumber(self.b) / 65535, tonumber(self.a) / 65535 end, @@ -134,8 +168,27 @@ local conversions = { self.a = a == nil and 65535 or clamp01(a) * 65535 end, }, + r16f = { + pointer = ffi.typeof("struct ImageData_Pixel_R16F *"), + tolua = function(self) + return tonumber(ffifuncs.halfToFloat(self.r)), 0, 0, 1 + end, + fromlua = function(self, r) + self.r = ffifuncs.floatToHalf(r) + end, + }, + rg16f = { + pointer = ffi.typeof("struct ImageData_Pixel_RG16F *"), + tolua = function(self) + return tonumber(ffifuncs.halfToFloat(self.r)), tonumber(ffifuncs.halfToFloat(self.g)), 0, 1 + end, + fromlua = function(self, r, g, b, a) + self.r = ffifuncs.floatToHalf(r) + self.g = ffifuncs.floatToHalf(g) + end, + }, rgba16f = { - pointer = ffi.typeof("ImageData_Pixel_RGBA16F *"), + pointer = ffi.typeof("struct ImageData_Pixel_RGBA16F *"), tolua = function(self) return tonumber(ffifuncs.halfToFloat(self.r)), tonumber(ffifuncs.halfToFloat(self.g)), @@ -149,8 +202,27 @@ local conversions = { self.a = ffifuncs.floatToHalf(a == nil and 1.0 or a) end, }, + r32f = { + pointer = ffi.typeof("struct ImageData_Pixel_R32F *"), + tolua = function(self) + return tonumber(self.r), 0, 0, 1 + end, + fromlua = function(self, r, g, b, a) + self.r = r + end, + }, + rg32f = { + pointer = ffi.typeof("struct ImageData_Pixel_RG32F *"), + tolua = function(self) + return tonumber(self.r), tonumber(self.g), 0, 1 + end, + fromlua = function(self, r, g, b, a) + self.r = r + self.g = g + end, + }, rgba32f = { - pointer = ffi.typeof("ImageData_Pixel_RGBA32F *"), + pointer = ffi.typeof("struct ImageData_Pixel_RGBA32F *"), tolua = function(self) return tonumber(self.r), tonumber(self.g), tonumber(self.b), tonumber(self.a) end,