Browse Source

Added love.math.gammaToLinear and love.math.linearToGamma for converting RGB color values from the sRGB color-space to linear and vice-versa.

Alex Szpakowski 11 years ago
parent
commit
e54d771be4

+ 30 - 0
src/modules/math/MathModule.cpp

@@ -193,5 +193,35 @@ bool Math::isConvex(const std::vector<Vertex> &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

+ 10 - 0
src/modules/math/MathModule.h

@@ -136,6 +136,16 @@ public:
 	 **/
 	bool isConvex(const std::vector<Vertex> &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).
 	 *

+ 66 - 0
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 }
 };

+ 2 - 0
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);