ImageData:mapPixel can now take optional x,y,w,h parameters to constrain it to a rectangle in the ImageData

This commit is contained in:
Alex Szpakowski
2013-07-11 01:10:19 -03:00
parent 91e4feeca0
commit bcc85f884e
2 changed files with 49 additions and 20 deletions
+48 -19
View File
@@ -115,36 +115,55 @@ int w_ImageData_setPixel(lua_State *L)
}
// Gets the result of luaL_where as a string.
static std::string luax_getwhere(lua_State *L, int lvl)
static std::string luax_getwhere(lua_State *L, int level)
{
std::string where;
luaL_where(L, level);
luaL_where(L, lvl);
const char *str = lua_tostring(L, -1);
std::string where;
if (str)
where = str;
lua_pop(L, 1);
return where;
}
// Generates a Lua error with a nice error string when a return value of a
// called function is not a number.
static int luax_retnumbererror(lua_State *L, int level, int retnum, int ttype)
{
if (ttype == LUA_TNUMBER)
return 0;
const char *where = luax_getwhere(L, level).c_str();
const char *ttypename = lua_typename(L, ttype);
return luaL_error(L, "%sbad return value #%d (number expected, got %s)",
where, retnum, ttypename);
}
// ImageData:mapPixel. Not thread-safe! See the wrapper function below.
static int w_ImageData_mapPixelUnsafe(lua_State *L)
{
ImageData *t = luax_checkimagedata(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
int w = t->getWidth();
int h = t->getHeight();
// No optints because we assume they're done in the wrapper function.
int sx = (int) lua_tonumber(L, 3);
int sy = (int) lua_tonumber(L, 4);
int w = (int) lua_tonumber(L, 5);
int h = (int) lua_tonumber(L, 6);
if (!(t->inside(sx, sy) && t->inside(sx+w-1, sy+h-1)))
return luaL_error(L, "Invalid rectangle dimensions.");
// Default pixel component values (r, g, b, a.)
const unsigned char pixel_defaults[4] = {0, 0, 0, 255};
for (int y = 0; y < h; y++)
// Cache-friendlier loop. :)
for (int y = sy; y < sy+h; y++)
{
for (int x = 0; x < w; x++)
for (int x = sx; x < sx+w; x++)
{
lua_pushvalue(L, 2);
lua_pushnumber(L, x);
@@ -168,15 +187,16 @@ static int w_ImageData_mapPixelUnsafe(lua_State *L)
switch (ttype)
{
case LUA_TNUMBER:
parray[i] = lua_tointeger(L, -4 + i);
parray[i] = (unsigned char) lua_tonumber(L, -4 + i);
break;
case LUA_TNONE:
case LUA_TNIL:
parray[i] = pixel_defaults[i];
break;
default:
return luaL_error(L, "%sbad return value #%d (number expected, got %s)",
luax_getwhere(L, 2).c_str(), i+1, lua_typename(L, ttype));
// Level 2 because this is function will be wrapped.
return luax_retnumbererror(L, 2, i + 1, ttype);
}
}
@@ -194,18 +214,27 @@ int w_ImageData_mapPixel(lua_State *L)
{
ImageData *t = luax_checkimagedata(L, 1);
luaL_checktype(L, 2, LUA_TFUNCTION);
love::thread::Mutex *mutex = t->getMutex();
int sx = luaL_optint(L, 3, 0);
int sy = luaL_optint(L, 4, 0);
int w = luaL_optint(L, 5, t->getWidth());
int h = luaL_optint(L, 6, t->getHeight());
lua_pushcfunction(L, w_ImageData_mapPixelUnsafe);
lua_pushvalue(L, 1);
lua_pushvalue(L, 2);
lua_pushinteger(L, sx);
lua_pushinteger(L, sy);
lua_pushinteger(L, w);
lua_pushinteger(L, h);
// Manually lock this ImageData's mutex during the entire mapPixel.
// Using the lock methods because lua_error won't trigger object destructors.
mutex->lock();
int ret = lua_pcall(L, 2, 0, 0);
mutex->unlock();
int ret = 0;
// Lock this ImageData's mutex during the entire mapPixel. We pcall instead
// of call because lua_error longjmp's without calling object destructors.
{
love::thread::Lock lock(t->getMutex());
ret = lua_pcall(L, 6, 0, 0);
}
if (ret != 0)
return lua_error(L);