diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aafd11e6..5eaaf1a9d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,8 +279,8 @@ set(LOVE_SRC_COMMON src/common/EnumMap.h src/common/Exception.cpp src/common/Exception.h - src/common/halffloat.cpp - src/common/halffloat.h + src/common/floattypes.cpp + src/common/floattypes.h src/common/int.h src/common/math.h src/common/Matrix.cpp diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 266df0620..409f8005e 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -64,6 +64,9 @@ 217DFC101D9F6D490055D849 /* url.lua.h in Headers */ = {isa = PBXBuildFile; fileRef = 217DFBD41D9F6D490055D849 /* url.lua.h */; }; 217DFC111D9F6D490055D849 /* usocket.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBD51D9F6D490055D849 /* usocket.c */; }; 217DFC121D9F6D490055D849 /* usocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217DFBD61D9F6D490055D849 /* usocket.h */; }; + FA0A3A5F23366CE9001C269E /* floattypes.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0A3A5D23366CE9001C269E /* floattypes.h */; }; + FA0A3A6023366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; + FA0A3A6123366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; FA0B791B1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791C1A958E3B000E1D17 /* b64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B78F71A958E3B000E1D17 /* b64.cpp */; }; FA0B791D1A958E3B000E1D17 /* b64.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B78F81A958E3B000E1D17 /* b64.h */; }; @@ -937,9 +940,6 @@ FA8951A21AA2EDF300EC385A /* wrap_Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */; }; FA8951A31AA2EDF300EC385A /* wrap_Event.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */; }; FA8951A41AA2EDF300EC385A /* wrap_Event.h in Headers */ = {isa = PBXBuildFile; fileRef = FA8951A11AA2EDF300EC385A /* wrap_Event.h */; }; - FA91591E1CF1ED7500A7053F /* halffloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91591C1CF1ED7500A7053F /* halffloat.cpp */; }; - FA91591F1CF1ED7500A7053F /* halffloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91591C1CF1ED7500A7053F /* halffloat.cpp */; }; - FA9159201CF1ED7500A7053F /* halffloat.h in Headers */ = {isa = PBXBuildFile; fileRef = FA91591D1CF1ED7500A7053F /* halffloat.h */; }; FA91DA8B1F377C3900C80E33 /* deprecation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91DA891F377C3900C80E33 /* deprecation.cpp */; }; FA91DA8C1F377C3900C80E33 /* deprecation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91DA891F377C3900C80E33 /* deprecation.cpp */; }; FA91DA8D1F377C3900C80E33 /* deprecation.h in Headers */ = {isa = PBXBuildFile; fileRef = FA91DA8A1F377C3900C80E33 /* deprecation.h */; }; @@ -1281,6 +1281,8 @@ 217DFBD61D9F6D490055D849 /* usocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usocket.h; sourceTree = ""; }; 503971A86B7167A91B670FBA /* boot.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = ""; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; + FA0A3A5D23366CE9001C269E /* floattypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = floattypes.h; sourceTree = ""; }; + FA0A3A5E23366CE9001C269E /* floattypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = floattypes.cpp; sourceTree = ""; }; FA0B78DD1A958B90000E1D17 /* liblove.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblove.a; sourceTree = BUILT_PRODUCTS_DIR; }; FA0B78F71A958E3B000E1D17 /* b64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = b64.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; FA0B78F81A958E3B000E1D17 /* b64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = b64.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -1876,8 +1878,6 @@ FA7DA04C1C16874A0056B200 /* wrap_Math.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_Math.lua; sourceTree = ""; }; FA8951A01AA2EDF300EC385A /* wrap_Event.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Event.cpp; sourceTree = ""; }; FA8951A11AA2EDF300EC385A /* wrap_Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Event.h; sourceTree = ""; }; - FA91591C1CF1ED7500A7053F /* halffloat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = halffloat.cpp; sourceTree = ""; }; - FA91591D1CF1ED7500A7053F /* halffloat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = halffloat.h; sourceTree = ""; }; FA91DA891F377C3900C80E33 /* deprecation.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = deprecation.cpp; sourceTree = ""; }; FA91DA8A1F377C3900C80E33 /* deprecation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = deprecation.h; sourceTree = ""; }; FA93C4501F315B960087CCD4 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = ""; }; @@ -2164,8 +2164,8 @@ FA0B78FD1A958E3B000E1D17 /* EnumMap.h */, FA0B78FE1A958E3B000E1D17 /* Exception.cpp */, FA0B78FF1A958E3B000E1D17 /* Exception.h */, - FA91591C1CF1ED7500A7053F /* halffloat.cpp */, - FA91591D1CF1ED7500A7053F /* halffloat.h */, + FA0A3A5E23366CE9001C269E /* floattypes.cpp */, + FA0A3A5D23366CE9001C269E /* floattypes.h */, FA0B79001A958E3B000E1D17 /* int.h */, FA0B7EF01A959D2C000E1D17 /* ios.h */, FA0B7EF11A959D2C000E1D17 /* ios.mm */, @@ -3795,7 +3795,6 @@ 217DFBEE1D9F6D490055D849 /* luasocket.h in Headers */, FACA02F31F5E396B0084B28F /* HashFunction.h in Headers */, FA0B7ED01A95902C000E1D17 /* wrap_LuaThread.h in Headers */, - FA9159201CF1ED7500A7053F /* halffloat.h in Headers */, FA0B7CE41A95902C000E1D17 /* wrap_Audio.h in Headers */, FA0B7A7F1A958EA3000E1D17 /* b2ContactSolver.h in Headers */, FADF540F1E3D7CDD00012CC0 /* wrap_Video.h in Headers */, @@ -3926,6 +3925,7 @@ FA0B7CD81A95902C000E1D17 /* Audio.h in Headers */, FA0B7CF61A95902C000E1D17 /* File.h in Headers */, FA0B7E961A95902C000E1D17 /* Mpg123Decoder.h in Headers */, + FA0A3A5F23366CE9001C269E /* floattypes.h in Headers */, FADF54091E3D78F700012CC0 /* Video.h in Headers */, FAA54ACB1F91660400A8FA7B /* TheoraVideoStream.h in Headers */, FA0B7DD51A95902C000E1D17 /* BezierCurve.h in Headers */, @@ -4271,7 +4271,6 @@ FA0B7EA41A95902C000E1D17 /* SoundData.cpp in Sources */, FA0B7D041A95902C000E1D17 /* wrap_DroppedFile.cpp in Sources */, FAF1406A1E20934C00F898D2 /* glslang_tab.cpp in Sources */, - FA91591F1CF1ED7500A7053F /* halffloat.cpp in Sources */, FA8951A31AA2EDF300EC385A /* wrap_Event.cpp in Sources */, FADF540E1E3D7CDD00012CC0 /* wrap_Video.cpp in Sources */, FA0B7A361A958EA3000E1D17 /* b2Distance.cpp in Sources */, @@ -4404,6 +4403,7 @@ FA0B7E791A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */, FA0B7DDD1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */, FA0B7A2A1A958EA3000E1D17 /* b2BroadPhase.cpp in Sources */, + FA0A3A6123366CE9001C269E /* floattypes.cpp in Sources */, FA0B7A811A958EA3000E1D17 /* b2EdgeAndCircleContact.cpp in Sources */, FAF188A01E9DBC4B008C1479 /* depthstencil.cpp in Sources */, FA0B7D071A95902C000E1D17 /* wrap_File.cpp in Sources */, @@ -4794,6 +4794,7 @@ FAF140711E20934C00F898D2 /* Intermediate.cpp in Sources */, FAC7CD7D1FE35E95006A60C7 /* physfs_platform_winrt.cpp in Sources */, FA0B7E541A95902C000E1D17 /* wrap_GearJoint.cpp in Sources */, + FA0A3A6023366CE9001C269E /* floattypes.cpp in Sources */, FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */, FA0B7E781A95902C000E1D17 /* wrap_WheelJoint.cpp in Sources */, FA0B7DDC1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */, @@ -4907,7 +4908,6 @@ FAC756F51E4F99B400B91289 /* Effect.cpp in Sources */, FA620A3A1AA305F6005DB4C2 /* types.cpp in Sources */, FA0B7DD31A95902C000E1D17 /* BezierCurve.cpp in Sources */, - FA91591E1CF1ED7500A7053F /* halffloat.cpp in Sources */, FA0B7E7B1A95902C000E1D17 /* wrap_World.cpp in Sources */, FA0B7B281A958EA3000E1D17 /* simplexnoise1234.cpp in Sources */, FA0B7D421A95902C000E1D17 /* OpenGL.cpp in Sources */, diff --git a/src/common/halffloat.cpp b/src/common/floattypes.cpp similarity index 52% rename from src/common/halffloat.cpp rename to src/common/floattypes.cpp index 0ab8b19f4..3a57de112 100644 --- a/src/common/halffloat.cpp +++ b/src/common/floattypes.cpp @@ -18,14 +18,17 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "halffloat.h" +#include "floattypes.h" + +#include +#include namespace love { // Code from ftp://www.fox-toolkit.org/pub/fasthalffloatconversion.pdf -static bool initialized = false; +static bool halfInitialized = false; // tables for half -> float conversions static uint32 mantissatable[2048]; @@ -54,15 +57,15 @@ static uint32 convertMantissa(uint32 i) return m | e; // Return combined number } -void halfInit() +void float16Init() { - if (initialized) + if (halfInitialized) return; - initialized = true; + halfInitialized = true; - // tables for half -> float conversions. + // tables for float16 -> float32 conversions. mantissatable[0] = 0; @@ -93,7 +96,7 @@ void halfInit() } - // tables for float -> half conversions. + // tables for float32 -> float16 conversions. for (uint32 i = 0; i < 256; i++) { @@ -137,20 +140,115 @@ void halfInit() } } -float halfToFloat(half h) +static inline uint32 asuint32(float f) { - union { float f; uint32 i; } conv; + union { float f; uint32 u; } conv; + conv.f = f; + return conv.u; +} - conv.i = mantissatable[offsettable[h >> 10] + (h & 0x3FF)] + exponenttable[h >> 10]; +static inline float asfloat32(uint32 u) +{ + union { float f; uint32 u; } conv; + conv.u = u; return conv.f; } -half floatToHalf(float f) +float float16to32(float16 f) { - union { float f; uint32 i; } conv; - conv.f = f; + return asfloat32(mantissatable[offsettable[f >> 10] + (f & 0x3FF)] + exponenttable[f >> 10]); +} - return basetable[(conv.i >> 23) & 0x1FF] + ((conv.i & 0x007FFFFF) >> shifttable[(conv.i >> 23) & 0x1FF]); +float16 float32to16(float f) +{ + uint32 u = asuint32(f); + return basetable[(u >> 23) & 0x1FF] + ((u & 0x007FFFFF) >> shifttable[(u >> 23) & 0x1FF]); +} + +// Adapted from https://stackoverflow.com/questions/41532085/how-to-pack-unpack-11-and-10-bit-floats-in-javascript-for-webgl2 + +float float11to32(float11 f) +{ + uint16 exponent = f >> 6; + uint16 mantissa = f & 0x3F; + + if (exponent == 0) + return mantissa == 0 ? 0 : powf(2.0f, -14.0f) * (mantissa / 64.0f); + + if (exponent < 31) + return powf(2.0f, exponent - 15) * (1.0f + mantissa / 64.0f); + + return mantissa == 0 ? std::numeric_limits::infinity() : std::numeric_limits::quiet_NaN(); +} + +float11 float32to11(float f) +{ + const uint16 EXPONENT_BITS = 0x1F; + const uint16 EXPONENT_SHIFT = 6; + const uint16 EXPONENT_BIAS = 15; + const uint16 MANTISSA_BITS = 0x3F; + const uint16 MANTISSA_SHIFT = (23 - EXPONENT_SHIFT); + const uint16 MAX_EXPONENT = (EXPONENT_BITS << EXPONENT_SHIFT); + + uint32 u = asuint32(f); + + if (u & 0x80000000) + return 0; // Negative values go to 0. + + // Map exponent to the range [-127,128] + int32 exponent = (int32)((u >> 23) & 0xFF) - 127; + uint32 mantissa = u & 0x007FFFFF; + + if (exponent > 15) // Infinity or NaN + return MAX_EXPONENT | (exponent == 128 ? (mantissa & MANTISSA_BITS) : 0); + else if (exponent <= -15) + return 0; + + exponent += EXPONENT_BIAS; + + return ((uint16)exponent << EXPONENT_SHIFT) | (mantissa >> MANTISSA_SHIFT); +} + +float float10to32(float10 f) +{ + uint16 exponent = f >> 5; + uint16 mantissa = f & 0x1F; + + if (exponent == 0) + return mantissa == 0 ? 0 : powf(2.0f, -14.0f) * (mantissa / 32.0f); + + if (exponent < 31) + return powf(2.0f, exponent - 15) * (1.0f + mantissa / 32.0f); + + return mantissa == 0 ? std::numeric_limits::infinity() : std::numeric_limits::quiet_NaN(); +} + +float10 float32to10(float f) +{ + const uint16 EXPONENT_BITS = 0x1F; + const uint16 EXPONENT_SHIFT = 5; + const uint16 EXPONENT_BIAS = 15; + const uint16 MANTISSA_BITS = 0x1F; + const uint16 MANTISSA_SHIFT = (23 - EXPONENT_SHIFT); + const uint16 MAX_EXPONENT = (EXPONENT_BITS << EXPONENT_SHIFT); + + uint32 u = asuint32(f); + + if (u & 0x80000000) + return 0; // Negative values go to 0. + + // Map exponent to the range [-127,128] + int32 exponent = (int32)((u >> 23) & 0xFF) - 127; + uint32 mantissa = u & 0x007FFFFF; + + if (exponent > 15) // Infinity or NaN + return MAX_EXPONENT | (exponent == 128 ? (mantissa & MANTISSA_BITS) : 0); + else if (exponent <= -15) + return 0; + + exponent += EXPONENT_BIAS; + + return ((uint16)exponent << EXPONENT_SHIFT) | (mantissa >> MANTISSA_SHIFT); } } // love diff --git a/src/common/halffloat.h b/src/common/floattypes.h similarity index 77% rename from src/common/halffloat.h rename to src/common/floattypes.h index e6bcc5599..219c5374e 100644 --- a/src/common/halffloat.h +++ b/src/common/floattypes.h @@ -18,21 +18,26 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#ifndef LOVE_HALF_FLOAT_H -#define LOVE_HALF_FLOAT_H +#pragma once #include "int.h" namespace love { -typedef uint16 half; +typedef uint16 float16; +typedef uint16 float11; +typedef uint16 float10; -void halfInit(); +void float16Init(); -float halfToFloat(half h); -half floatToHalf(float f); +float float16to32(float16 f); +float16 float32to16(float f); + +float float11to32(float11 f); +float11 float32to11(float f); + +float float10to32(float10 f); +float10 float32to10(float f); } // love - -#endif // LOVE_HALF_FLOAT_H diff --git a/src/modules/image/Image.cpp b/src/modules/image/Image.cpp index 0d522ae09..f0c762edc 100644 --- a/src/modules/image/Image.cpp +++ b/src/modules/image/Image.cpp @@ -43,7 +43,7 @@ Image::Image() { using namespace magpie; - halfInit(); // Makes sure half-float conversions can be used. + float16Init(); // Makes sure half-float conversions can be used. formatHandlers = { new PNGHandler, diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index d67576fbd..338ade2e8 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -280,7 +280,7 @@ union Row { uint8 *u8; uint16 *u16; - half *f16; + float16 *f16; float *f32; }; @@ -293,7 +293,7 @@ static void pasteRGBA8toRGBA16(Row src, Row dst, int w) 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); + dst.f16[i] = float32to16(src.u8[i] / 255.0f); } static void pasteRGBA8toRGBA32F(Row src, Row dst, int w) @@ -311,7 +311,7 @@ static void pasteRGBA16toRGBA8(Row src, Row dst, int w) 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); + dst.f16[i] = float32to16(src.u16[i] / 65535.0f); } static void pasteRGBA16toRGBA32F(Row src, Row dst, int w) @@ -323,19 +323,19 @@ static void pasteRGBA16toRGBA32F(Row src, Row dst, int w) 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); + dst.u8[i] = (uint8) (float16to32(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); + dst.u16[i] = (uint16) (float16to32(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]); + dst.f32[i] = float16to32(src.f16[i]); } static void pasteRGBA32FtoRGBA8(Row src, Row dst, int w) @@ -353,7 +353,7 @@ static void pasteRGBA32FtoRGBA16(Row src, Row dst, int w) 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]); + dst.f16[i] = (uint16) float32to16(src.f32[i]); } void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, int sh) @@ -498,6 +498,7 @@ bool ImageData::validPixelFormat(PixelFormat format) case PIXELFORMAT_RGB5A1: case PIXELFORMAT_RGB565: case PIXELFORMAT_RGB10A2: + case PIXELFORMAT_RG11B10F: return true; default: return false; diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index b6d99644e..2639f3d3a 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -25,7 +25,7 @@ #include "common/StringMap.h" #include "common/int.h" #include "common/pixelformat.h" -#include "common/halffloat.h" +#include "common/floattypes.h" #include "filesystem/FileData.h" #include "thread/threads.h" #include "ImageDataBase.h" @@ -40,12 +40,12 @@ namespace image union Pixel { - uint8 rgba8[4]; - uint16 rgba16[4]; - half rgba16f[4]; - float rgba32f[4]; - uint16 packed16; - uint32 packed32; + uint8 rgba8[4]; + uint16 rgba16[4]; + float16 rgba16f[4]; + float rgba32f[4]; + uint16 packed16; + uint32 packed32; }; /** diff --git a/src/modules/image/magpie/EXRHandler.cpp b/src/modules/image/magpie/EXRHandler.cpp index daeca51ea..d2aa7a5df 100644 --- a/src/modules/image/magpie/EXRHandler.cpp +++ b/src/modules/image/magpie/EXRHandler.cpp @@ -20,7 +20,7 @@ // LOVE #include "EXRHandler.h" -#include "common/halffloat.h" +#include "common/floattypes.h" #include "common/Exception.h" // zlib (for tinyexr) @@ -157,12 +157,12 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data) { img.format = PIXELFORMAT_RGBA16F; - half *rgba[4] = {nullptr}; + float16 *rgba[4] = {nullptr}; getEXRChannels(exrHeader, exrImage, rgba); try { - img.data = (unsigned char *) loadEXRChannels(img.width, img.height, rgba, floatToHalf(1.0f)); + img.data = (unsigned char *) loadEXRChannels(img.width, img.height, rgba, float32to16(1.0f)); } catch (love::Exception &) { diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index c17e0e38a..e76ebdb2b 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -110,9 +110,9 @@ 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)); + p.rgba16f[i] = float32to16((float) luaL_checknumber(L, startidx + i)); if (components > 3) - p.rgba16f[3] = floatToHalf((float) luaL_optnumber(L, startidx + 3, 1.0)); + p.rgba16f[3] = float32to16((float) luaL_optnumber(L, startidx + 3, 1.0)); } template @@ -187,40 +187,49 @@ static void luax_checkpixel_rgba32f(lua_State *L, int startidx, Pixel &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)) << 12; - uint16 g = ((uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0xF) + 0.5)) << 8; - uint16 b = ((uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0xF) + 0.5)) << 4; - uint16 a = ((uint16) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0xF) + 0.5)) << 0; - p.packed16 = r | g | b | a; + 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)) << 11; - uint16 g = ((uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0x1F) + 0.5)) << 6; - uint16 b = ((uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0x1F) + 0.5)) << 1; - uint16 a = ((uint16) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0x1) + 0.5)) << 0; - p.packed16 = r | g | b | a; + 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)) << 11; - uint16 g = ((uint16) ((luax_checknumberclamped01(L, startidx + 1) * 0x3F) + 0.5)) << 5; - uint16 b = ((uint16) ((luax_checknumberclamped01(L, startidx + 2) * 0x1F) + 0.5)) << 0; - p.packed16 = r | g | b; + 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)) << 0; - uint32 g = ((uint32) ((luax_checknumberclamped01(L, startidx + 1) * 0x3FF) + 0.5)) << 10; - uint32 b = ((uint32) ((luax_checknumberclamped01(L, startidx + 2) * 0x3FF) + 0.5)) << 20; - uint32 a = ((uint32) ((luax_optnumberclamped01(L, startidx + 3, 1.0) * 0x3) + 0.5)) << 30; - p.packed32 = 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}; @@ -249,7 +258,7 @@ 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])); + lua_pushnumber(L, (lua_Number) float16to32(p.rgba16f[i])); for (int i = components; i < 4; i++) lua_pushnumber(L, fillValues[i]); return 4; @@ -358,10 +367,20 @@ static int luax_pushpixel_rgb565(lua_State *L, const Pixel &p) static int luax_pushpixel_rgb10a2(lua_State *L, const Pixel &p) { // LSB->MSB: [r, g, b, a] - lua_pushnumber(L, ((p.packed16 >> 0) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed16 >> 10) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed16 >> 20) & 0x3FF) / (double)0x3FF); - lua_pushnumber(L, ((p.packed16 >> 30) & 0x3) / (double)0x3); + 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; } @@ -526,8 +545,14 @@ struct FFI_ImageData void (*lockMutex)(Proxy *p); void (*unlockMutex)(Proxy *p); - float (*halfToFloat)(half h); - half (*floatToHalf)(float f); + float (*float16to32)(float16 f); + float16 (*float32to16)(float f); + + float (*float11to32)(float11 f); + float11 (*float32to11)(float f); + + float (*float10to32)(float10 f); + float10 (*float32to10)(float f); }; static FFI_ImageData ffifuncs = @@ -546,8 +571,12 @@ static FFI_ImageData ffifuncs = i->getMutex()->unlock(); }, - halfToFloat, - floatToHalf, + float16to32, + float32to16, + float11to32, + float32to11, + float10to32, + float32to10, }; static const luaL_Reg w_ImageData_functions[] = @@ -571,39 +600,41 @@ 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_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_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); diff --git a/src/modules/image/wrap_ImageData.lua b/src/modules/image/wrap_ImageData.lua index a97b059cd..e671fa924 100644 --- a/src/modules/image/wrap_ImageData.lua +++ b/src/modules/image/wrap_ImageData.lua @@ -78,15 +78,23 @@ if not bitstatus then return end pcall(ffi.cdef, [[ typedef struct Proxy Proxy; -typedef uint16_t half; +typedef uint16_t float16; +typedef uint16_t float11; +typedef uint16_t float10; typedef struct FFI_ImageData { void (*lockMutex)(Proxy *p); void (*unlockMutex)(Proxy *p); - float (*halfToFloat)(half h); - half (*floatToHalf)(float f); + float (*float16to32)(float16 f); + float16 (*float32to16)(float f); + + float (*float11to32)(float11 f); + float11 (*float32to11)(float f); + + float (*float10to32)(float10 f); + float10 (*float32to10)(float f); } FFI_ImageData; struct ImageData_Pixel_R8 { uint8_t r; }; @@ -97,9 +105,9 @@ 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; }; -struct ImageData_Pixel_R16F { half r; }; -struct ImageData_Pixel_RG16F { half r, g; }; -struct ImageData_Pixel_RGBA16F { half r, g, b, a; }; +struct ImageData_Pixel_R16F { float16 r; }; +struct ImageData_Pixel_RG16F { float16 r, g; }; +struct ImageData_Pixel_RGBA16F { float16 r, g, b, a; }; struct ImageData_Pixel_R32F { float r; }; struct ImageData_Pixel_RG32F { float r, g; }; @@ -109,6 +117,7 @@ struct ImageData_Pixel_RGBA4 { uint16_t rgba; }; struct ImageData_Pixel_RGB5A1 { uint16_t rgba; }; struct ImageData_Pixel_RGB565 { uint16_t rgb; }; struct ImageData_Pixel_RGB10A2 { uint32_t rgba; }; +struct ImageData_Pixel_RG11B10F { uint32_t rgb; }; ]]) local ffifuncs = ffi.cast("FFI_ImageData **", ffifuncspointer_str)[0] @@ -179,35 +188,35 @@ local conversions = { r16f = { pointer = ffi.typeof("struct ImageData_Pixel_R16F *"), tolua = function(self) - return tonumber(ffifuncs.halfToFloat(self.r)), 0, 0, 1 + return tonumber(ffifuncs.float16to32(self.r)), 0, 0, 1 end, fromlua = function(self, r) - self.r = ffifuncs.floatToHalf(r) + self.r = ffifuncs.float32to16(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 + return tonumber(ffifuncs.float16to32(self.r)), tonumber(ffifuncs.float16to32(self.g)), 0, 1 end, fromlua = function(self, r, g, b, a) - self.r = ffifuncs.floatToHalf(r) - self.g = ffifuncs.floatToHalf(g) + self.r = ffifuncs.float32to16(r) + self.g = ffifuncs.float32to16(g) end, }, rgba16f = { pointer = ffi.typeof("struct ImageData_Pixel_RGBA16F *"), tolua = function(self) - return tonumber(ffifuncs.halfToFloat(self.r)), - tonumber(ffifuncs.halfToFloat(self.g)), - tonumber(ffifuncs.halfToFloat(self.b)), - tonumber(ffifuncs.halfToFloat(self.a)) + return tonumber(ffifuncs.float16to32(self.r)), + tonumber(ffifuncs.float16to32(self.g)), + tonumber(ffifuncs.float16to32(self.b)), + tonumber(ffifuncs.float16to32(self.a)) end, fromlua = function(self, r, g, b, a) - self.r = ffifuncs.floatToHalf(r) - self.g = ffifuncs.floatToHalf(g) - self.b = ffifuncs.floatToHalf(b) - self.a = ffifuncs.floatToHalf(a == nil and 1.0 or a) + self.r = ffifuncs.float32to16(r) + self.g = ffifuncs.float32to16(g) + self.b = ffifuncs.float32to16(b) + self.a = ffifuncs.float32to16(a == nil and 1.0 or a) end, }, r32f = { @@ -319,6 +328,24 @@ local conversions = { self.rgba = bit.bor(r, bit.lshift(g, 10), bit.lshift(b, 20), bit.lshift(a, 30)) end, }, + rg11b10f = { + -- LSB->MSB: [r, g, b] + pointer = ffi.typeof("struct ImageData_Pixel_RG11B10F *"), + tolua = function(self) + local rgb = self.rgb + local r = tonumber(ffifuncs.float11to32(bit.band(rgb, 0x7FF))) + local g = tonumber(ffifuncs.float11to32(bit.band(bit.rshift(rgb, 11), 0x7FF))) + local b = tonumber(ffifuncs.float10to32(bit.band(bit.rshift(rgb, 22), 0x3FF))) + return r, g, b, 1 + end, + fromlua = function(self, r, g, b, a) + self.rgb = bit.bor( + ffifuncs.float32to11(r), + bit.lshift(ffifuncs.float32to11(g), 11), + bit.lshift(ffifuncs.float32to10(b), 22) + ) + end, + }, } local _getWidth = ImageData.getWidth