Skip to content
Snippets Groups Projects
Commit 5900d936 authored by dg's avatar dg
Browse files

FOV/LOS shape can now be altered by modules using a simple:...

FOV/LOS shape can now be altered by modules using a simple: core.fov.set_vision_shape("circle") . The parameter can be one of "circle", "circle_floor", "circle_ceil", "circle_plus1", "diamond", "octagon", "square"


git-svn-id: http://svn.net-core.org/repos/t-engine4@4404 51575b47-30f0-44d4-a5cc-537603b46e54
parent 70a209ed
No related branches found
No related tags found
No related merge requests found
......@@ -383,6 +383,10 @@ function _M:instanciate(mod, name, new_game, no_reboot)
-- Turn based by default
core.game.setRealtime(0)
-- FOV Shape
core.fov.set_vision_shape("circle")
core.fov.set_permissiveness("square")
-- Init the module directories
mod.load("setup")
......
......@@ -1106,6 +1106,7 @@ end
-- "firstpeek" is the least permissive setting that allows @ to see r below:
-- @##
-- ..r
-- Default is "square"
function core.fov.set_permissiveness(val)
val = type(val) == "string" and (string.lower(val) == "square" and 0.0 or
string.lower(val) == "diamond" and 0.5 or
......@@ -1116,6 +1117,27 @@ function core.fov.set_permissiveness(val)
if type(val) ~= "number" then return end
val = util.bound(val, 0.0, 0.5)
core.fov.set_permissiveness_base(val)
return 2*val
end
--- Sets the vision shape or distance metric for field of vision, talent ranges, AoEs, etc.
-- @param should be a string: circle, circle_round (same as circle), circle_floor, circle_ceil, circle_plus1, octagon, diamond, square.
-- See "src/fov/fov.h" to see how each shape calculates distance and height.
-- "circle_round" is aesthetically pleasing, "octagon" is a traditional roguelike FoV shape, and "circle_plus1" is similar to both "circle_round" and "octagon"
-- Default is "circle_round"
function core.fov.set_vision_shape(val)
sval = type(val) == "string" and string.lower(val)
val = sval and ((sval == "circle" or sval == "circle_round") and 0 or
sval == "circle_floor" and 1 or
sval == "circle_ceil" and 2 or
sval == "circle_plus1" and 3 or
sval == "octagon" and 4 or
sval == "diamond" and 5 or
sval == "square" and 6) or
type(tonumber(val)) == "number" and tonumber(val)
if type(val) ~= "number" then return end
core.fov.set_vision_shape_base(val)
return val
end
......
......@@ -43,6 +43,7 @@
******************************************************************/
static const char FOV_PERMISSIVE_KEY = 'k';
static const char FOV_VISION_SHAPE_KEY = 'k';
struct lua_fovcache
{
......@@ -83,23 +84,43 @@ static int lua_fov_get_permissiveness(lua_State *L)
lua_settable(L, LUA_REGISTRYINDEX);
}
}
static int lua_fov_set_vision_shape(lua_State *L)
{
int val = luaL_checknumber(L, 1);
lua_pushlightuserdata(L, (void *)&FOV_VISION_SHAPE_KEY); // push address as guaranteed unique key
lua_pushnumber(L, val);
lua_settable(L, LUA_REGISTRYINDEX);
return 0;
}
static int lua_fov_get_vision_shape(lua_State *L)
{
lua_pushlightuserdata(L, (void *)&FOV_VISION_SHAPE_KEY); // push address as guaranteed unique key
lua_gettable(L, LUA_REGISTRYINDEX); /* retrieve value */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); // remove nil
lua_pushlightuserdata(L, (void *)&FOV_VISION_SHAPE_KEY); // push address as guaranteed unique key
lua_pushnumber(L, FOV_SHAPE_CIRCLE_ROUND);
lua_settable(L, LUA_REGISTRYINDEX);
}
}
static void map_seen(void *m, int x, int y, int dx, int dy, int radius, void *src)
{
struct lua_fov *fov = (struct lua_fov *)m;
if (x < 0 || y < 0 || x >= fov->w || y >= fov->h) return;
if (dx*dx + dy*dy <= radius*radius + radius) // <-- use shape of FoV. Also, is this check really necessary? TODO: verify and delete if unnecessary
{
// circular view - can be changed if you like
lua_rawgeti(fov->L, LUA_REGISTRYINDEX, fov->apply_ref);
if (fov->cache) lua_rawgeti(fov->L, LUA_REGISTRYINDEX, fov->cache_ref);
else lua_pushnil(fov->L);
lua_pushnumber(fov->L, x);
lua_pushnumber(fov->L, y);
lua_pushnumber(fov->L, dx);
lua_pushnumber(fov->L, dy);
lua_pushnumber(fov->L, dx*dx + dy*dy);
lua_call(fov->L, 6, 0);
}
// circular view - can be changed if you like
lua_rawgeti(fov->L, LUA_REGISTRYINDEX, fov->apply_ref);
if (fov->cache) lua_rawgeti(fov->L, LUA_REGISTRYINDEX, fov->cache_ref);
else lua_pushnil(fov->L);
lua_pushnumber(fov->L, x);
lua_pushnumber(fov->L, y);
lua_pushnumber(fov->L, dx);
lua_pushnumber(fov->L, dy);
lua_pushnumber(fov->L, dx*dx + dy*dy);
lua_call(fov->L, 6, 0);
}
static bool map_opaque(void *m, int x, int y)
......@@ -155,6 +176,8 @@ static int lua_fov_calc_circle(lua_State *L)
fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
lua_fov_get_permissiveness(L);
fov.fov_settings.permissiveness = luaL_checknumber(L, -1);
lua_fov_get_vision_shape(L);
fov.fov_settings.shape = luaL_checknumber(L, -1);
fov_circle(&(fov.fov_settings), &fov, NULL, x, y, radius);
map_seen(&fov, x, y, 0, 0, radius, NULL);
......@@ -213,6 +236,8 @@ static int lua_fov_calc_beam(lua_State *L)
fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
lua_fov_get_permissiveness(L);
fov.fov_settings.permissiveness = luaL_checknumber(L, -1);
lua_fov_get_vision_shape(L);
fov.fov_settings.shape = luaL_checknumber(L, -1);
fov_beam(&(fov.fov_settings), &fov, NULL, x, y, radius, dir, angle);
map_seen(&fov, x, y, 0, 0, radius, NULL);
......@@ -259,6 +284,8 @@ static int lua_fov_calc_beam_any_angle(lua_State *L)
fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
lua_fov_get_permissiveness(L);
fov.fov_settings.permissiveness = luaL_checknumber(L, -1);
lua_fov_get_vision_shape(L);
fov.fov_settings.shape = luaL_checknumber(L, -1);
fov_beam_any_angle(&(fov.fov_settings), &fov, NULL, x, y, radius, dx, dy, beam_angle);
map_seen(&fov, x, y, 0, 0, radius, NULL);
......@@ -277,9 +304,49 @@ static int lua_distance(lua_State *L)
double y1 = luaL_checknumber(L, 2);
double x2 = luaL_checknumber(L, 3);
double y2 = luaL_checknumber(L, 4);
bool ret_float = lua_toboolean(L, 5);
double dx = fabs(x2 - x1);
double dy = fabs(y2 - y1);
double dist;
lua_fov_get_vision_shape(L);
int shape = luaL_checknumber(L, -1);
switch(shape) {
case FOV_SHAPE_CIRCLE_ROUND :
dist = sqrt(dx*dx + dy*dy) + 0.5;
break;
case FOV_SHAPE_CIRCLE_FLOOR :
dist = sqrt(dx*dx + dy*dy);
break;
case FOV_SHAPE_CIRCLE_CEIL :
if (ret_float)
dist = sqrt(dx*dx + dy*dy);
else
dist = ceil(sqrt(dx*dx + dy*dy));
break;
case FOV_SHAPE_CIRCLE_PLUS1 :
dist = sqrt(dx*dx + dy*dy);
if (dist > 0.5) dist = dist + 1 - 1.0/dist;
break;
case FOV_SHAPE_OCTAGON :
dist = (dx > dy) ? (dx + 0.5*dy) : (dy + 0.5*dx);
break;
case FOV_SHAPE_DIAMOND :
dist = dx + dy;
break;
case FOV_SHAPE_SQUARE :
dist = (dx > dy) ? dx : dy;
break;
default :
dist = sqrt(dx*dx + dy*dy) + 0.5;
break;
}
if (ret_float)
lua_pushnumber(L, dist);
else
lua_pushnumber(L, (int)dist);
// TODO: switch/case based on FoV shape. Use rounded circle for now
lua_pushnumber(L, (int)(sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) + 0.5f));
return 1;
}
......@@ -355,101 +422,101 @@ typedef struct {
static void map_default_seen(void *m, int x, int y, int dx, int dy, int radius, void *src)
{
// TODO: understand how this function uses distances and use "lua_distance" (i.e., core.fov.distance) if necessary
default_fov *def = (default_fov*)src;
struct lua_fov *fov = (struct lua_fov *)m;
float sqdist = dx*dx + dy*dy;
float dist = sqrtf(sqdist);
if (dx*dx + dy*dy <= radius*radius + radius) // <-- use FoV shape. Also, is this check really necessary? TODO: verify and delete if unnecessary
{
// Distance Map
if (def->do_dmap)
{
lua_pushnumber(fov->L, x + y * def->w);
lua_pushnumber(fov->L, def->turn + radius - dist);
lua_rawset(fov->L, STACK_DMAP);
}
// Apply
if (def->do_apply)
{
lua_pushvalue(fov->L, STACK_APPLY);
lua_pushnumber(fov->L, x);
lua_pushnumber(fov->L, y);
lua_pushnumber(fov->L, dx);
lua_pushnumber(fov->L, dy);
lua_pushnumber(fov->L, sqdist);
lua_call(fov->L, 5, 0);
}
if (x < 0 || y < 0 || x >= fov->w || y >= fov->h) return;
// Get entity
// Distance Map
if (def->do_dmap)
{
lua_pushnumber(fov->L, x + y * def->w);
lua_rawget(fov->L, STACK_MAP);
if (!lua_istable(fov->L, -1)) { lua_pop(fov->L, 1); return; }
lua_pushnumber(fov->L, def->entity);
lua_rawget(fov->L, -2);
if (!lua_istable(fov->L, -1)) { lua_pop(fov->L, 2); return; }
// Check if dead
lua_pushstring(fov->L, "dead");
lua_gettable(fov->L, -2);
if (lua_toboolean(fov->L, -1)) { lua_pop(fov->L, 3); return; }
lua_pop(fov->L, 1);
// Set sqdist in the actor for faster sorting
lua_pushstring(fov->L, "__sqdist");
lua_pushnumber(fov->L, sqdist);
lua_rawset(fov->L, -3);
lua_pushnumber(fov->L, def->turn + radius - dist);
lua_rawset(fov->L, STACK_DMAP);
}
// Make a table to hold data
lua_newtable(fov->L);
lua_pushstring(fov->L, "x");
// Apply
if (def->do_apply)
{
lua_pushvalue(fov->L, STACK_APPLY);
lua_pushnumber(fov->L, x);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "y");
lua_pushnumber(fov->L, y);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "dx");
lua_pushnumber(fov->L, dx);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "dy");
lua_pushnumber(fov->L, dy);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "sqdist");
lua_pushnumber(fov->L, sqdist);
lua_rawset(fov->L, -3);
// Set the actor table
lua_pushvalue(fov->L, -2);
lua_pushvalue(fov->L, -2);
lua_rawset(fov->L, STACK_ACTOR);
// Set the dist table
def->dist_idx++;
lua_pushnumber(fov->L, def->dist_idx);
lua_pushvalue(fov->L, -3);
lua_rawset(fov->L, STACK_DIST);
lua_call(fov->L, 5, 0);
}
// Call seen_by, if possible
lua_pushstring(fov->L, "updateFOV");
lua_gettable(fov->L, -3);
// Get entity
lua_pushnumber(fov->L, x + y * def->w);
lua_rawget(fov->L, STACK_MAP);
if (!lua_istable(fov->L, -1)) { lua_pop(fov->L, 1); return; }
lua_pushnumber(fov->L, def->entity);
lua_rawget(fov->L, -2);
if (!lua_istable(fov->L, -1)) { lua_pop(fov->L, 2); return; }
// Check if dead
lua_pushstring(fov->L, "dead");
lua_gettable(fov->L, -2);
if (lua_toboolean(fov->L, -1)) { lua_pop(fov->L, 3); return; }
lua_pop(fov->L, 1);
// Set sqdist in the actor for faster sorting
lua_pushstring(fov->L, "__sqdist");
lua_pushnumber(fov->L, sqdist);
lua_rawset(fov->L, -3);
// Make a table to hold data
lua_newtable(fov->L);
lua_pushstring(fov->L, "x");
lua_pushnumber(fov->L, x);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "y");
lua_pushnumber(fov->L, y);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "dx");
lua_pushnumber(fov->L, dx);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "dy");
lua_pushnumber(fov->L, dy);
lua_rawset(fov->L, -3);
lua_pushstring(fov->L, "sqdist");
lua_pushnumber(fov->L, sqdist);
lua_rawset(fov->L, -3);
// Set the actor table
lua_pushvalue(fov->L, -2);
lua_pushvalue(fov->L, -2);
lua_rawset(fov->L, STACK_ACTOR);
// Set the dist table
def->dist_idx++;
lua_pushnumber(fov->L, def->dist_idx);
lua_pushvalue(fov->L, -3);
lua_rawset(fov->L, STACK_DIST);
// Call seen_by, if possible
lua_pushstring(fov->L, "updateFOV");
lua_gettable(fov->L, -3);
lua_pushvalue(fov->L, -3);
lua_pushvalue(fov->L, STACK_SELF);
lua_pushnumber(fov->L, sqdist);
lua_call(fov->L, 3, 0);
// Call seen_by, if possible
lua_pushstring(fov->L, "seen_by");
lua_gettable(fov->L, -3);
if (lua_isfunction(fov->L, -1))
{
lua_pushvalue(fov->L, -3);
lua_pushvalue(fov->L, STACK_SELF);
lua_pushnumber(fov->L, sqdist);
lua_call(fov->L, 3, 0);
// Call seen_by, if possible
lua_pushstring(fov->L, "seen_by");
lua_gettable(fov->L, -3);
if (lua_isfunction(fov->L, -1))
{
lua_pushvalue(fov->L, -3);
lua_pushvalue(fov->L, STACK_SELF);
lua_call(fov->L, 2, 0);
}
else lua_pop(fov->L, 1);
lua_pop(fov->L, 3);
lua_call(fov->L, 2, 0);
}
else lua_pop(fov->L, 1);
lua_pop(fov->L, 3);
}
static bool map_default_opaque(void *m, int x, int y)
......@@ -497,6 +564,8 @@ static int lua_fov_calc_default_fov(lua_State *L)
fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_default_seen);
lua_fov_get_permissiveness(L);
fov.fov_settings.permissiveness = luaL_checknumber(L, -1);
lua_fov_get_vision_shape(L);
fov.fov_settings.shape = luaL_checknumber(L, -1);
fov_circle(&(fov.fov_settings), &fov, &def, x, y, radius);
map_default_seen(&fov, x, y, 0, 0, radius, &def);
......@@ -539,10 +608,13 @@ static int lua_fov_line_init(lua_State *L)
bool start_at_end = lua_toboolean(L, 8);
fov.w = w;
fov.h = h;
fov_settings_init(&(fov.fov_settings));
fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque);
lua_fov_get_permissiveness(L);
fov.fov_settings.permissiveness = luaL_checknumber(L, -1);
lua_fov_get_vision_shape(L);
fov.fov_settings.shape = luaL_checknumber(L, -1);
fov_line_data *line = (fov_line_data*)lua_newuserdata(L, sizeof(fov_line_data));
......@@ -715,6 +787,7 @@ static const struct luaL_reg fovlib[] =
{"line_base", lua_fov_line_init},
{"line_import", lua_fov_line_import},
{"set_permissiveness_base", lua_fov_set_permissiveness},
{"set_vision_shape_base", lua_fov_set_vision_shape},
{NULL, NULL},
};
......
......@@ -82,7 +82,7 @@ typedef struct {
/* Options -------------------------------------------------------- */
void fov_settings_init(fov_settings_type *settings) {
settings->shape = FOV_SHAPE_CIRCLE_PRECALCULATE;
settings->shape = FOV_SHAPE_CIRCLE_ROUND;
settings->corner_peek = FOV_CORNER_NOPEEK;
settings->opaque_apply = FOV_OPAQUE_APPLY;
settings->opaque = NULL;
......@@ -238,23 +238,32 @@ static float fov_slope(float dx, float dy) {
} \
\
switch (settings->shape) { \
case FOV_SHAPE_CIRCLE_PRECALCULATE: \
case FOV_SHAPE_CIRCLE_ROUND : \
h = height(settings, dx, data->radius); \
break; \
case FOV_SHAPE_CIRCLE: \
h = (unsigned)(sqrt((data->radius)*(data->radius) + data->radius - dx*dx)); \
case FOV_SHAPE_CIRCLE_FLOOR : \
h = (unsigned)(sqrt((data->radius)*(data->radius) + 2*data->radius - dx*dx)); \
break; \
case FOV_SHAPE_CIRCLE_CEIL : \
h = (unsigned)(sqrt((data->radius)*(data->radius) - dx*dx)); \
break; \
case FOV_SHAPE_CIRCLE_PLUS1 : \
h = (unsigned)(sqrt((data->radius)*(data->radius) + 1 - dx*dx)); \
break; \
case FOV_SHAPE_OCTAGON: \
h = (data->radius - dx)<<1; \
h = 2u*(data->radius - (unsigned)dx) + 1u; \
break; \
default: \
case FOV_SHAPE_DIAMOND : \
h = data->radius - (unsigned)dx; \
break; \
case FOV_SHAPE_SQUARE : \
h = data->radius; \
break; \
default : \
h = (unsigned)(sqrt((data->radius)*(data->radius) + data->radius - dx*dx)); \
break; \
}; \
if ((unsigned)dy1 > h) { \
if (h == 0) { \
return; \
} \
dy1 = (int)h; \
} \
\
......@@ -469,82 +478,92 @@ void fov_beam(fov_settings_type *settings, void *map, void *source,
end_slope = betweenf(angle_end, 0.0f, 1.0f); \
fov_octant_##p1(&data, 1, start_slope, end_slope, true, true); \
\
if (angle_end - 1.0 > FLT_EPSILON) { \
if (angle_end - 1.0f > FLT_EPSILON) { \
start_slope = betweenf(2.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p2(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 2.0 > 2.0f * FLT_EPSILON) { \
if (angle_end - 2.0f > 2.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 2.0f, 0.0f, 1.0f); \
fov_octant_##p3(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 3.0 > 3.0f * FLT_EPSILON) { \
if (angle_end - 3.0f > 3.0f * FLT_EPSILON) { \
start_slope = betweenf(4.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p4(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 4.0 > 4.0f * FLT_EPSILON) { \
if (angle_end - 4.0f > 4.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 4.0f, 0.0f, 1.0f); \
fov_octant_##p5(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 5.0 > 5.0f * FLT_EPSILON) { \
if (angle_end - 5.0f > 5.0f * FLT_EPSILON) { \
start_slope = betweenf(6.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p6(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 6.0 > 6.0f * FLT_EPSILON) { \
if (angle_end - 6.0f > 6.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 6.0f, 0.0f, 1.0f); \
fov_octant_##p7(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 7.0 > 7.0f * FLT_EPSILON) { \
if (angle_end - 7.0f > 7.0f * FLT_EPSILON) { \
start_slope = betweenf(8.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p8(&data, 1, start_slope, 1.0f, false, false); \
}}}}}}}
fov_octant_##p8(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 8.0f > 8.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 8.0f, 0.0f, 1.0f); \
start_slope = betweenf(angle_end - 8.0f, 0.0f, 1.0f); \
fov_octant_##p1(&data, 1, 0.0f, end_slope, false, false); \
}}}}}}}}
#define BEAM_ANY_DIRECTION_DIAG(offset, p1, p2, p3, p4, p5, p6, p7, p8) \
angle_begin -= offset; \
angle_end -= offset; \
start_slope = betweenf(1.0 - angle_end, 0.0f, 1.0f); \
end_slope = 1.0 - angle_begin; \
start_slope = betweenf(1.0f - angle_end, 0.0f, 1.0f); \
end_slope = 1.0f - angle_begin; \
fov_octant_##p1(&data, 1, start_slope, end_slope, true, true); \
\
if (angle_end - 1.0 > FLT_EPSILON) { \
if (angle_end - 1.0f > FLT_EPSILON) { \
end_slope = betweenf(angle_end - 1.0f, 0.0f, 1.0f); \
fov_octant_##p2(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 2.0 > 2.0f * FLT_EPSILON) { \
if (angle_end - 2.0f > 2.0f * FLT_EPSILON) { \
start_slope = betweenf(3.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p3(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 3.0 > 3.0f * FLT_EPSILON) { \
if (angle_end - 3.0f > 3.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 3.0f, 0.0f, 1.0f); \
fov_octant_##p4(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 4.0 > 4.0f * FLT_EPSILON) { \
if (angle_end - 4.0f > 4.0f * FLT_EPSILON) { \
start_slope = betweenf(5.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p5(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 5.0 > 5.0f * FLT_EPSILON) { \
if (angle_end - 5.0f > 5.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 5.0f, 0.0f, 1.0f); \
fov_octant_##p6(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 6.0 > 6.0f * FLT_EPSILON) { \
if (angle_end - 6.0f > 6.0f * FLT_EPSILON) { \
start_slope = betweenf(7.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p7(&data, 1, start_slope, 1.0f, true, false); \
\
if (angle_end - 7.0 > 7.0f * FLT_EPSILON) { \
if (angle_end - 7.0f > 7.0f * FLT_EPSILON) { \
end_slope = betweenf(angle_end - 7.0f, 0.0f, 1.0f); \
fov_octant_##p8(&data, 1, 0.0f, end_slope, false, false); \
}}}}}}}
fov_octant_##p8(&data, 1, 0.0f, end_slope, false, true); \
\
if (angle_end - 8.0f > 8.0f * FLT_EPSILON) { \
start_slope = betweenf(9.0f - angle_end, 0.0f, 1.0f); \
fov_octant_##p1(&data, 1, start_slope, 1.0f, false, false); \
}}}}}}}}
void fov_beam_any_angle(fov_settings_type *settings, void *map, void *source,
int source_x, int source_y, unsigned radius,
float dx, float dy, float beam_angle) {
/* Note: angle_begin and angle_end are misnomers, since FoV calculation uses slopes, not angles.
* Hence, it may not be clear that we implicitly use a tan(x) ~ 4/pi*x approximation
* for x in range (0, pi/4) radians, or (0, 45) degrees. We can (and will) make this much
* more precise, which is why the function now uses parameters dx, dy instead of dir_angle.
* TODO: make this more precise by not using approximations */
* We previously used a tan(x) ~ 4/pi*x approximation * for x in range (0, pi/4) radians, or 45 degrees.
* We no longer use this approximation. Angles and slopes are calculated precisely,
* so this function can be used for numerically precise purposes if desired.
*/
fov_private_data_type data;
float start_slope, end_slope, angle_begin, angle_end, dir_angle;
float start_slope, end_slope, angle_begin, angle_end, x_start, y_start, x_end, y_end;
data.settings = settings;
data.map = map;
......@@ -560,20 +579,45 @@ void fov_beam_any_angle(fov_settings_type *settings, void *map, void *source,
return;
}
dir_angle = RtoD*atan2(dy, dx);
while (dir_angle >= 360.0f) {
dir_angle -= 360.0f;
beam_angle = 0.5f * DtoR * beam_angle;
x_start = cos(beam_angle)*dx + sin(beam_angle)*dy;
y_start = cos(beam_angle)*dy - sin(beam_angle)*dx;
x_end = cos(beam_angle)*dx - sin(beam_angle)*dy;
y_end = cos(beam_angle)*dy + sin(beam_angle)*dx;
if (y_start > 0.0f) {
if (x_start > 0.0f) { /* octant 1 */ /* octant 2 */
angle_begin = ( y_start < x_start) ? (y_start / x_start) : (2.0f - x_start / y_start);
}
else { /* octant 3 */ /* octant 4 */
angle_begin = (-x_start < y_start) ? (2.0f - x_start / y_start) : (4.0f + y_start / x_start);
}
} else {
if (x_start < 0.0f) { /* octant 5 */ /* octant 6 */
angle_begin = (-y_start < -x_start) ? (4.0f + y_start / x_start) : (6.0f - x_start / y_start);
}
else { /* octant 7 */ /* octant 8 */
angle_begin = ( x_start < -y_start) ? (6.0f - x_start / y_start) : (8.0f + y_start / x_start);
}
}
while (dir_angle < 0.0f) {
dir_angle += 360.0f;
if (y_end > 0.0f) {
if (x_end > 0.0f) { /* octant 1 */ /* octant 2 */
angle_end = ( y_end < x_end) ? (y_end / x_end) : (2.0f - x_end / y_end);
}
else { /* octant 3 */ /* octant 4 */
angle_end = (-x_end < y_end) ? (2.0f - x_end / y_end) : (4.0f + y_end / x_end);
}
} else {
if (x_end < 0.0f) { /* octant 5 */ /* octant 6 */
angle_end = (-y_end < -x_end) ? (4.0f + y_end / x_end) : (6.0f - x_end / y_end);
}
else { /* octant 7 */ /* octant 8 */
angle_end = ( x_end < -y_end) ? (6.0f - x_end / y_end) : (8.0f + y_end / x_end);
}
}
/* Calculate the angles as a percentage of 45 degrees */
angle_begin = (dir_angle - 0.5*beam_angle) / 45.0f;
angle_end = (dir_angle + 0.5*beam_angle) / 45.0f;
if (angle_begin < 0.0f) {
angle_begin += 8.0f;
if (angle_end < angle_begin) {
angle_end += 8.0f;
}
......
......@@ -55,12 +55,15 @@ typedef enum {
FOV_SOUTHEAST
} fov_direction_type;
/** Values for the shape setting. */
/** Values for the shape setting. Distance Y (given x, radius r) Square distance check */
typedef enum {
FOV_SHAPE_CIRCLE_PRECALCULATE,
FOV_SHAPE_SQUARE,
FOV_SHAPE_CIRCLE,
FOV_SHAPE_OCTAGON
FOV_SHAPE_CIRCLE_ROUND, /* floor(sqrt(x^2 + y^2) + 0.5) sqrt(r^2 + r - x^2) x^2 + y^2 <= r^2 + r */
FOV_SHAPE_CIRCLE_FLOOR, /* floor(sqrt(x^2 + y^2)) sqrt(r^2 + 2*r - x^2) x^2 + y^2 <= r^2 + 2*r */
FOV_SHAPE_CIRCLE_CEIL, /* ceil(sqrt(x^2 + y^2)) sqrt(r^2 - x^2) x^2 + y^2 <= r^2 */
FOV_SHAPE_CIRCLE_PLUS1, /* floor(d + 1 - 1.0/d) sqrt(r^2 + 1 - x^2) x^2 + y^2 <= r^2 + 1 */
FOV_SHAPE_OCTAGON, /* max(x, y) + min(x, y)/2 2*(r - x) + 1 */
FOV_SHAPE_DIAMOND, /* x + y r - x */
FOV_SHAPE_SQUARE /* max(x, y) r */
} fov_shape_type;
/** Values for the corner peek setting. */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment