diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index 9ffefe839..ed096ebd7 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -193,5 +193,35 @@ bool Math::isConvex(const std::vector &polygon) return true; } +/** + * http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation + **/ +float Math::gammaToLinear(float c) const +{ + if (c > 1.0) + return 1.0; + else if (c < 0.0) + return 0.0; + else if (c <= 0.04045) + return c / 12.92; + else + return powf((c + 0.055) / 1.055, 2.4); +} + +/** + * http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29 + **/ +float Math::linearToGamma(float c) const +{ + if (c > 1.0) + return 1.0; + else if (c < 0.0) + return 0.0; + else if (c < 0.0031308) + return c * 12.92; + else + return 1.055 * powf(c, 0.41666) - 0.055; +} + } // math } // love diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 70f420515..0765a0e9c 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -136,6 +136,16 @@ public: **/ bool isConvex(const std::vector &polygon); + /** + * Converts a value from the sRGB (gamma) colorspace to linear RGB. + **/ + float gammaToLinear(float c) const; + + /** + * Converts a value from linear RGB to the sRGB (gamma) colorspace. + **/ + float linearToGamma(float c) const; + /** * Calculate Simplex noise for the specified coordinate(s). * diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 95cf37940..773ecf040 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -238,6 +238,70 @@ int w_isConvex(lua_State *L) return 1; } +static int getGammaArgs(lua_State *L, float color[4]) +{ + int numcomponents = 0; + + if (lua_istable(L, 1)) + { + int n = lua_objlen(L, 1); + for (int i = 1; i <= n && i <= 4; i++) + { + lua_rawgeti(L, 1, i); + color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0; + numcomponents++; + } + + lua_pop(L, numcomponents); + } + else + { + int n = lua_gettop(L); + for (int i = 1; i <= n && i <= 4; i++) + { + color[i - 1] = (float) luaL_checknumber(L, i) / 255.0; + numcomponents++; + } + } + + if (numcomponents == 0) + luaL_checknumber(L, 1); + + return numcomponents; +} + +int w_gammaToLinear(lua_State *L) +{ + float color[4]; + int numcomponents = getGammaArgs(L, color); + + for (int i = 0; i < numcomponents; i++) + { + // Alpha should always be linear. + if (i < 3) + color[i] = Math::instance.gammaToLinear(color[i]); + lua_pushnumber(L, color[i] * 255); + } + + return numcomponents; +} + +int w_linearToGamma(lua_State *L) +{ + float color[4]; + int numcomponents = getGammaArgs(L, color); + + for (int i = 0; i < numcomponents; i++) + { + // Alpha should always be linear. + if (i < 3) + color[i] = Math::instance.linearToGamma(color[i]); + lua_pushnumber(L, color[i] * 255); + } + + return numcomponents; +} + int w_noise(lua_State *L) { float w, x, y, z; @@ -285,6 +349,8 @@ static const luaL_Reg functions[] = { "newBezierCurve", w_newBezierCurve }, { "triangulate", w_triangulate }, { "isConvex", w_isConvex }, + { "gammaToLinear", w_gammaToLinear }, + { "linearToGamma", w_linearToGamma }, { "noise", w_noise }, { 0, 0 } }; diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 8693535dc..f4c73fcbb 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -38,6 +38,8 @@ int w_newRandomGenerator(lua_State *L); int w_newBezierCurve(lua_State *L); int w_triangulate(lua_State *L); int w_isConvex(lua_State *L); +int w_gammaToLinear(lua_State *L); +int w_linearToGamma(lua_State *L); int w_noise(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);