Some selection optimizations

- Add bounds, so that we don't process any locations outside
  as those locations are known to be unset
- The bounds are only recalculated if needed
- Replace instances of selection_not where we actually want
  a new selection with all locations set
This commit is contained in:
Pasi Kallinen
2022-08-26 12:43:40 +03:00
parent e815498f07
commit 5e9ed7a290
5 changed files with 203 additions and 31 deletions
+163 -19
View File
@@ -123,6 +123,7 @@ static const char *get_mkroom_name(int);
static int get_table_roomtype_opt(lua_State *, const char *, int);
static int get_table_traptype_opt(lua_State *, const char *, int);
static int get_traptype_byname(const char *);
static void selection_recalc_bounds(struct selectionvar *);
static lua_Integer get_table_intarray_entry(lua_State *, int, int);
static struct sp_coder *sp_level_coder_init(void);
@@ -4365,6 +4366,10 @@ selection_new(void)
tmps->wid = COLNO;
tmps->hei = ROWNO;
tmps->bounds_dirty = FALSE;
tmps->bounds.lx = COLNO;
tmps->bounds.ly = ROWNO;
tmps->bounds.hx = tmps->bounds.hy = 0;
tmps->map = (char *) alloc((COLNO * ROWNO) + 1);
(void) memset(tmps->map, 1, (COLNO * ROWNO));
tmps->map[(COLNO * ROWNO)] = '\0';
@@ -4385,6 +4390,24 @@ selection_free(struct selectionvar* sel, boolean freesel)
}
}
/* clear selection, setting all locations to value val */
void
selection_clear(struct selectionvar *sel, int val)
{
(void) memset(sel->map, 1 + val, (COLNO * ROWNO));
if (val) {
sel->bounds.lx = 0;
sel->bounds.ly = 0;
sel->bounds.hx = COLNO - 1;
sel->bounds.hy = ROWNO - 1;
} else {
sel->bounds.lx = COLNO;
sel->bounds.ly = ROWNO;
sel->bounds.hx = sel->bounds.hy = 0;
}
sel->bounds_dirty = FALSE;
}
struct selectionvar *
selection_clone(struct selectionvar* sel)
{
@@ -4396,6 +4419,98 @@ selection_clone(struct selectionvar* sel)
return tmps;
}
/* get boundary rect of selection sel into b */
void
selection_getbounds(struct selectionvar *sel, NhRect *b)
{
if (!sel || !b)
return;
selection_recalc_bounds(sel);
if (sel->bounds.lx >= sel->wid) {
b->lx = 0;
b->ly = 0;
b->hx = COLNO - 1;
b->hy = ROWNO - 1;
} else {
b->lx = sel->bounds.lx;
b->ly = sel->bounds.ly;
b->hx = sel->bounds.hx;
b->hy = sel->bounds.hy;
}
}
/* recalc the boundary of selection, if necessary */
static void
selection_recalc_bounds(struct selectionvar *sel)
{
coordxy x, y;
NhRect r;
if (!sel->bounds_dirty)
return;
sel->bounds.lx = COLNO;
sel->bounds.ly = ROWNO;
sel->bounds.hx = sel->bounds.hy = 0;
r.lx = r.ly = r.hx = r.hy = -1;
/* left */
for (x = 0; x < sel->wid; x++) {
for (y = 0; y < sel->hei; y++) {
if (selection_getpoint(x, y, sel)) {
r.lx = x;
break;
}
}
if (r.lx > -1)
break;
}
if (r.lx > -1) {
/* right */
for (x = sel->wid-1; x >= r.lx; x--) {
for (y = 0; y < sel->hei; y++) {
if (selection_getpoint(x, y, sel)) {
r.hx = x;
break;
}
}
if (r.hx > -1)
break;
}
/* top */
for (y = 0; y < sel->hei; y++) {
for (x = r.lx; x <= r.hx; x++) {
if (selection_getpoint(x, y, sel)) {
r.ly = y;
break;
}
}
if (r.ly > -1)
break;
}
/* bottom */
for (y = sel->hei-1; y >= r.ly; y--) {
for (x = r.lx; x <= r.hx; x++) {
if (selection_getpoint(x, y, sel)) {
r.hy = y;
break;
}
}
if (r.hy > -1)
break;
}
sel->bounds = r;
}
sel->bounds_dirty = FALSE;
}
coordxy
selection_getpoint(coordxy x, coordxy y, struct selectionvar* sel)
{
@@ -4415,6 +4530,15 @@ selection_setpoint(coordxy x, coordxy y, struct selectionvar* sel, int c)
if (x < 0 || y < 0 || x >= sel->wid || y >= sel->hei)
return;
if (c && !sel->bounds_dirty) {
if (sel->bounds.lx > x) sel->bounds.lx = x;
if (sel->bounds.ly > y) sel->bounds.ly = y;
if (sel->bounds.hx < x) sel->bounds.hx = x;
if (sel->bounds.hy < y) sel->bounds.hy = y;
} else {
sel->bounds_dirty = TRUE;
}
sel->map[sel->wid * y + x] = (char) (c + 1);
}
@@ -4436,14 +4560,17 @@ selection_filter_mapchar(struct selectionvar* ov, xint16 typ, int lit)
{
int x, y;
struct selectionvar *ret;
NhRect rect;
if (!ov)
return NULL;
ret = selection_new();
for (x = 1; x < ret->wid; x++)
for (y = 0; y < ret->hei; y++)
selection_getbounds(ov, &rect);
for (x = rect.lx; x <= rect.hx; x++)
for (y = rect.ly; y <= rect.hy; y++)
if (selection_getpoint(x, y, ov)
&& match_maptyps(typ, levl[x][y].typ)) {
switch (lit) {
@@ -4469,16 +4596,20 @@ selection_filter_percent(struct selectionvar* ov, int percent)
{
int x, y;
struct selectionvar *ret;
NhRect rect;
if (!ov)
return NULL;
ret = selection_new();
for (x = 0; x < ov->wid; x++)
for (y = 0; y < ov->hei; y++)
selection_getbounds(ov, &rect);
for (x = rect.lx; x <= rect.hx; x++)
for (y = rect.ly; y <= rect.hy; y++)
if (selection_getpoint(x, y, ov) && (rn2(100) < percent))
selection_setpoint(x, y, ret, 1);
return ret;
}
@@ -4488,16 +4619,19 @@ selection_rndcoord(struct selectionvar* ov, coordxy *x, coordxy *y, boolean remo
int idx = 0;
int c;
int dx, dy;
NhRect rect;
for (dx = 1; dx < ov->wid; dx++)
for (dy = 0; dy < ov->hei; dy++)
selection_getbounds(ov, &rect);
for (dx = rect.lx; dx <= rect.hx; dx++)
for (dy = rect.ly; dy <= rect.hy; dy++)
if (selection_getpoint(dx, dy, ov))
idx++;
if (idx) {
c = rn2(idx);
for (dx = 1; dx < ov->wid; dx++)
for (dy = 0; dy < ov->hei; dy++)
for (dx = rect.lx; dx <= rect.hx; dx++)
for (dy = rect.ly; dy <= rect.hy; dy++)
if (selection_getpoint(dx, dy, ov)) {
if (!c) {
*x = dx;
@@ -4526,6 +4660,7 @@ selection_do_grow(struct selectionvar* ov, int dir)
{
coordxy x, y;
struct selectionvar *tmp;
NhRect rect;
if (!ov)
return;
@@ -4535,8 +4670,10 @@ selection_do_grow(struct selectionvar* ov, int dir)
if (dir == W_RANDOM)
dir = random_wdir();
for (x = 1; x < ov->wid; x++)
for (y = 0; y < ov->hei; y++) {
selection_getbounds(ov, &rect);
for (x = max(0, rect.lx-1); x <= min(COLNO-1, rect.hx+1); x++)
for (y = max(0, rect.ly-1); y <= min(ROWNO-1, rect.hy+1); y++) {
/* note: dir is a mask of multiple directions, but the only
way to specify diagonals is by including the two adjacent
orthogonal directions, which effectively specifies three-
@@ -4557,8 +4694,10 @@ selection_do_grow(struct selectionvar* ov, int dir)
}
}
for (x = 1; x < ov->wid; x++)
for (y = 0; y < ov->hei; y++)
selection_getbounds(tmp, &rect);
for (x = rect.lx; x <= rect.hx; x++)
for (y = rect.ly; y <= rect.hy; y++)
if (selection_getpoint(x, y, tmp))
selection_setpoint(x, y, ov, 1);
@@ -4943,13 +5082,15 @@ selection_iterate(
genericptr_t arg)
{
coordxy x, y;
NhRect rect;
if (!ov)
return;
/* yes, this is very naive, but it's not _that_ expensive. */
for (x = 0; x < ov->wid; x++)
for (y = 0; y < ov->hei; y++)
selection_getbounds(ov, &rect);
for (x = rect.lx; x <= rect.hx; x++)
for (y = rect.ly; y <= rect.hy; y++)
if (isok(x,y) && selection_getpoint(x, y, ov))
(*func)(x, y, arg);
}
@@ -5278,6 +5419,7 @@ lspo_replace_terrain(lua_State *L)
lua_Integer x1, y1, x2, y2;
int chance;
int tolit;
NhRect rect;
create_des_coder();
@@ -5325,7 +5467,7 @@ lspo_replace_terrain(lua_State *L)
freesel = TRUE;
if (x1 == -1 && y1 == -1 && x2 == -1 && y2 == -1) {
(void) selection_not(sel);
(void) selection_clear(sel, 1);
} else {
coordxy rx1, ry1, rx2, ry2;
rx1 = x1, ry1 = y1, rx2 = x2, ry2 = y2;
@@ -5337,8 +5479,10 @@ lspo_replace_terrain(lua_State *L)
}
}
for (y = 0; y <= sel->hei; y++)
for (x = 1; x < sel->wid; x++)
selection_getbounds(sel, &rect);
for (x = max(1, rect.lx); x <= rect.hx; x++)
for (y = rect.ly; y <= rect.hy; y++)
if (selection_getpoint(x, y,sel)) {
if (mf) {
if (mapfrag_match(mf, x, y) && (rn2(100)) < chance)
@@ -6059,7 +6203,7 @@ set_wallprop_in_selection(lua_State *L, int prop)
} else if (argc == 0) {
freesel = TRUE;
sel = selection_new();
selection_not(sel);
selection_clear(sel, 1);
}
if (sel) {