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:
@@ -399,6 +399,8 @@ E NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo;
|
||||
|
||||
struct selectionvar {
|
||||
int wid, hei;
|
||||
boolean bounds_dirty;
|
||||
NhRect bounds; /* use selection_getbounds() */
|
||||
char *map;
|
||||
};
|
||||
|
||||
|
||||
@@ -2307,6 +2307,7 @@ extern void init_rect(void);
|
||||
extern void free_rect(void);
|
||||
extern NhRect *get_rect(NhRect *);
|
||||
extern NhRect *rnd_rect(void);
|
||||
extern void rect_bounds(NhRect, NhRect, NhRect *);
|
||||
extern void remove_rect(NhRect *);
|
||||
extern void add_rect(NhRect *);
|
||||
extern void split_rects(NhRect *, NhRect *);
|
||||
@@ -2582,7 +2583,9 @@ extern boolean load_special(const char *);
|
||||
extern coordxy selection_getpoint(coordxy, coordxy, struct selectionvar *);
|
||||
extern struct selectionvar *selection_new(void);
|
||||
extern void selection_free(struct selectionvar *, boolean);
|
||||
extern void selection_clear(struct selectionvar *, int);
|
||||
extern struct selectionvar *selection_clone(struct selectionvar *);
|
||||
extern void selection_getbounds(struct selectionvar *, NhRect *);
|
||||
extern void set_selection_floodfillchk(int(*)(coordxy, coordxy));
|
||||
extern void selection_floodfill(struct selectionvar *, coordxy, coordxy, boolean);
|
||||
extern boolean pm_good_location(coordxy, coordxy, struct permonst *);
|
||||
|
||||
37
src/nhlsel.c
37
src/nhlsel.c
@@ -234,7 +234,7 @@ l_selection_not(lua_State *L)
|
||||
if (argc == 0) {
|
||||
(void) l_selection_new(L);
|
||||
sel = l_selection_check(L, 1);
|
||||
selection_not(sel);
|
||||
selection_clear(sel, 1);
|
||||
} else {
|
||||
sel = l_selection_check(L, 1);
|
||||
(void) l_selection_clone(L);
|
||||
@@ -252,9 +252,12 @@ l_selection_and(lua_State *L)
|
||||
struct selectionvar *sela = l_selection_check(L, 1);
|
||||
struct selectionvar *selb = l_selection_check(L, 2);
|
||||
struct selectionvar *selr = l_selection_push_new(L);
|
||||
NhRect rect;
|
||||
|
||||
for (x = 0; x < selr->wid; x++)
|
||||
for (y = 0; y < selr->hei; y++) {
|
||||
rect_bounds(sela->bounds, selb->bounds, &rect);
|
||||
|
||||
for (x = rect.lx; x <= rect.hx; x++)
|
||||
for (y = rect.ly; y <= rect.hy; y++) {
|
||||
int val = selection_getpoint(x, y, sela) & selection_getpoint(x, y, selb);
|
||||
selection_setpoint(x, y, selr, val);
|
||||
}
|
||||
@@ -272,9 +275,12 @@ l_selection_or(lua_State *L)
|
||||
struct selectionvar *sela = l_selection_check(L, 1);
|
||||
struct selectionvar *selb = l_selection_check(L, 2);
|
||||
struct selectionvar *selr = l_selection_push_new(L);
|
||||
NhRect rect;
|
||||
|
||||
for (x = 0; x < selr->wid; x++)
|
||||
for (y = 0; y < selr->hei; y++) {
|
||||
rect_bounds(sela->bounds, selb->bounds, &rect);
|
||||
|
||||
for (x = rect.lx; x <= rect.hx; x++)
|
||||
for (y = rect.ly; y <= rect.hy; y++) {
|
||||
int val = selection_getpoint(x, y, sela) | selection_getpoint(x, y, selb);
|
||||
selection_setpoint(x, y, selr, val);
|
||||
}
|
||||
@@ -292,9 +298,12 @@ l_selection_xor(lua_State *L)
|
||||
struct selectionvar *sela = l_selection_check(L, 1);
|
||||
struct selectionvar *selb = l_selection_check(L, 2);
|
||||
struct selectionvar *selr = l_selection_push_new(L);
|
||||
NhRect rect;
|
||||
|
||||
for (x = 0; x < selr->wid; x++)
|
||||
for (y = 0; y < selr->hei; y++) {
|
||||
rect_bounds(sela->bounds, selb->bounds, &rect);
|
||||
|
||||
for (x = rect.lx; x <= rect.hx; x++)
|
||||
for (y = rect.ly; y <= rect.hy; y++) {
|
||||
int val = selection_getpoint(x, y, sela) ^ selection_getpoint(x, y, selb);
|
||||
selection_setpoint(x, y, selr, val);
|
||||
}
|
||||
@@ -313,15 +322,17 @@ l_selection_sub(lua_State *L)
|
||||
struct selectionvar *sela = l_selection_check(L, 1);
|
||||
struct selectionvar *selb = l_selection_check(L, 2);
|
||||
struct selectionvar *selr = l_selection_push_new(L);
|
||||
NhRect rect;
|
||||
|
||||
for (x = 0; x < selr->wid; x++) {
|
||||
for (y = 0; y < selr->hei; y++) {
|
||||
rect_bounds(sela->bounds, selb->bounds, &rect);
|
||||
|
||||
for (x = rect.lx; x <= rect.hx; x++)
|
||||
for (y = rect.ly; y <= rect.hy; y++) {
|
||||
coordxy a_pt = selection_getpoint(x, y, sela);
|
||||
coordxy b_pt = selection_getpoint(x, y, selb);
|
||||
int val = (a_pt ^ b_pt) & a_pt;
|
||||
selection_setpoint(x, y, selr, val);
|
||||
}
|
||||
}
|
||||
|
||||
lua_remove(L, 1);
|
||||
lua_remove(L, 1);
|
||||
@@ -817,11 +828,13 @@ l_selection_iterate(lua_State *L)
|
||||
int argc = lua_gettop(L);
|
||||
struct selectionvar *sel = (struct selectionvar *) 0;
|
||||
int x, y;
|
||||
NhRect rect;
|
||||
|
||||
if (argc == 2 && lua_type(L, 2) == LUA_TFUNCTION) {
|
||||
sel = l_selection_check(L, 1);
|
||||
for (y = 0; y < sel->hei; y++)
|
||||
for (x = 1; x < sel->wid; x++)
|
||||
selection_getbounds(sel, &rect);
|
||||
for (y = rect.ly; y <= rect.hy; y++)
|
||||
for (x = max(1,rect.lx); x <= rect.hx; x++)
|
||||
if (selection_getpoint(x, y, sel)) {
|
||||
lua_pushvalue(L, 2);
|
||||
lua_pushinteger(L, x - g.xstart);
|
||||
|
||||
10
src/rect.c
10
src/rect.c
@@ -128,6 +128,16 @@ intersect(NhRect* r1, NhRect* r2, NhRect* r3)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Put the rectangle containing both r1 and r2 into r3 */
|
||||
void
|
||||
rect_bounds(NhRect r1, NhRect r2, NhRect *r3)
|
||||
{
|
||||
r3->lx = min(r1.lx, r2.lx);
|
||||
r3->ly = min(r1.ly, r2.ly);
|
||||
r3->hx = max(r1.hx, r2.hx);
|
||||
r3->hy = max(r1.hy, r2.hy);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a rectangle from the list of free NhRect.
|
||||
*/
|
||||
|
||||
182
src/sp_lev.c
182
src/sp_lev.c
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user