Re-implement gradient selections

Uncomments and makes available selection.gradient in Lua. (The backend C
code for this still existed, it just wasn't used.)

The only valid way to specify a gradient is with a table. I considered
adding non-table versions, but decided that there are too many
independent variables that can be optional. A non-table version, without
named parameters, would be confusing to read, especially since most of
the arguments are ints.

Also adds an impossible in the (possibly unreachable) case that
selection_do_gradient gets called with a bad gradient type.
This commit is contained in:
copperwater
2020-02-29 11:06:30 -05:00
committed by Pasi Kallinen
parent 407f65aa8a
commit 0befdbfd02
3 changed files with 70 additions and 4 deletions

View File

@@ -2514,6 +2514,8 @@ E struct selectionvar *FDECL(selection_filter_mapchar, (struct selectionvar *,
E void FDECL(set_floodfillchk_match_under, (XCHAR_P));
E void FDECL(selection_do_ellipse, (struct selectionvar *,
int, int, int, int, int));
E void FDECL(selection_do_gradient, (struct selectionvar *, long, long,
long, long, long, long, long, long));
E void NDECL(update_croom);
E const char *FDECL(get_trapname_bytype, (int));
E void FDECL(l_register_des, (lua_State *));

View File

@@ -25,6 +25,7 @@ static int FDECL(l_selection_match, (lua_State *));
static int FDECL(l_selection_flood, (lua_State *));
static int FDECL(l_selection_circle, (lua_State *));
static int FDECL(l_selection_ellipse, (lua_State *));
static int FDECL(l_selection_gradient, (lua_State *));
static int FDECL(l_selection_iterate, (lua_State *));
static int FDECL(l_selection_gc, (lua_State *));
static int FDECL(l_selection_not, (lua_State *));
@@ -39,7 +40,6 @@ static int FDECL(l_selection_not, (lua_State *));
if ifdef'd out the prototype here and the
function body below.
*/
static int FDECL(l_selection_gradient, (lua_State *));
static int FDECL(l_selection_add, (lua_State *));
static int FDECL(l_selection_sub, (lua_State *));
static int FDECL(l_selection_ipairs, (lua_State *));
@@ -736,6 +736,70 @@ lua_State *L;
return 1;
}
/* Gradients are versatile enough, with so many independently optional
* arguments, that it doesn't seem helpful to provide a non-table form with
* non-obvious argument order. */
/* selection.gradient({ type = "radial", x = 3, y = 5, x2 = 10, y2 = 12,
* mindist = 4, maxdist = 10, limited = false }); */
static int
l_selection_gradient(L)
lua_State *L;
{
int argc = lua_gettop(L);
struct selectionvar *sel = (struct selectionvar *) 0;
/* if x2 and y2 aren't set, the gradient has a single center point of x,y;
* if they are set, the gradient is centered on a (x,y) to (x2,y2) line */
schar x = 0, y = 0, x2 = -1, y2 = -1;
/* points will not be added within mindist of the center; the chance for a
* point between mindist and maxdist to be added to the selection starts at
* 0% at mindist and increases linearly to 100% at maxdist */
xchar mindist = 0, maxdist = 0;
/* if limited is true, no points farther than maxdist will be added; if
* false, all points farther than maxdist will be added */
boolean limited = FALSE;
long type;
static const char *const gradtypes[] = {
"radial", "square", NULL
};
static const int gradtypes2i[] = {
SEL_GRADIENT_RADIAL, SEL_GRADIENT_SQUARE, -1
};
if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) {
lcheck_param_table(L);
type = gradtypes2i[get_table_option(L, "type", "radial", gradtypes)];
x = (schar) get_table_int(L, "x");
y = (schar) get_table_int(L, "y");
x2 = (schar) get_table_int_opt(L, "x2", -1);
y2 = (schar) get_table_int_opt(L, "y2", -1);
/* maxdist is required because there's no obvious default value for it,
* whereas mindist has an obvious defalt of 0 */
maxdist = get_table_int(L, "maxdist");
mindist = get_table_int_opt(L, "mindist", 0);
limited = get_table_boolean_opt(L, "limited", FALSE);
lua_pop(L, 1);
(void) l_selection_new(L);
sel = l_selection_check(L, 1);
} else {
nhl_error(L, "wrong parameters");
/* NOTREACHED */
}
/* someone might conceivably want to draw a gradient somewhere off-map. So
* the only coordinate that's "illegal" for that is (-1,-1).
* If a level designer really needs to draw a gradient line using that
* coordinate, they can do so by setting regular x and y to -1. */
if (x2 == -1 && y2 == -1) {
x2 = x;
y2 = y;
}
selection_do_gradient(sel, x, y, x2, y2, type, mindist, maxdist, limited);
lua_settop(L, 1);
return 1;
}
/* sel:iterate(function(x,y) ... end); */
static int
l_selection_iterate(L)
@@ -782,10 +846,8 @@ static const struct luaL_Reg l_selection_methods[] = {
{ "floodfill", l_selection_flood },
{ "circle", l_selection_circle },
{ "ellipse", l_selection_ellipse },
{ "gradient", l_selection_gradient },
{ "iterate", l_selection_iterate },
/* TODO:
{ "gradient", l_selection_gradient },
*/
{ NULL, NULL }
};

View File

@@ -4683,6 +4683,8 @@ long x, y, x2, y2, gtyp, mind, maxd, limit;
switch (gtyp) {
default:
impossible("Unrecognized gradient type! Defaulting to radial...");
/* FALLTHRU */
case SEL_GRADIENT_RADIAL: {
for (dx = 0; dx < COLNO; dx++)
for (dy = 0; dy < ROWNO; dy++) {