From 5be67a7c64f89dcca0afbccf112cc046ad388671 Mon Sep 17 00:00:00 2001 From: Miguel Angel Astor Romero Date: Mon, 29 May 2017 13:52:05 -0400 Subject: [PATCH] Added libfov source file. --- Makefile | 10 +- lib/libfov.a | Bin 17898 -> 0 bytes src/fov.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 433 insertions(+), 4 deletions(-) delete mode 100644 lib/libfov.a create mode 100644 src/fov.c diff --git a/Makefile b/Makefile index f5ef482..cba4b96 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ CC = gcc -OBJECTS = obj/main.o obj/game_state.o obj/in_game.o obj/main_menu.o obj/map.o obj/intro.o obj/game_over.o +OBJECTS = obj/main.o obj/game_state.o obj/in_game.o obj/main_menu.o obj/map.o obj/intro.o obj/game_over.o obj/fov.o TARGET = bin/cyjam CFLAGS = -Wall -I./include -std=c99 -LDFLAGS = -L./lib -LDLIBS = -lfov -lncursesw -lm +LDLIBS = -lncursesw -lm all: CFLAGS += -O3 all: $(TARGET) @@ -12,7 +11,7 @@ debug: CFLAGS += -g debug: $(TARGET) $(TARGET): $(OBJECTS) - $(CC) -o $(TARGET) $(OBJECTS) $(CLFAGS) $(LDFLAGS) $(LDLIBS) + $(CC) -o $(TARGET) $(OBJECTS) $(CLFAGS) $(LDLIBS) obj/main.o: src/main.c include/constants.h include/game_state.h $(CC) -c -o $@ $< $(CFLAGS) @@ -35,5 +34,8 @@ obj/game_over.o: src/game_over.c include/game_over.h include/game_state.h obj/map.o: src/map.c include/map.h $(CC) -c -o $@ $< $(CFLAGS) +obj/fov.o: src/fov.c include/fov.h + $(CC) -c -o $@ $< $(CFLAGS) + clean: $(RM) $(TARGET) $(OBJECTS) diff --git a/lib/libfov.a b/lib/libfov.a deleted file mode 100644 index 088e3cf7abf2bdfb4efa0deb9e93049221da4490..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17898 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 VpJ&|7_&y`qQEERI_LI=f_`k8H2%`W1 diff --git a/src/fov.c b/src/fov.c new file mode 100644 index 0000000..74ed5c8 --- /dev/null +++ b/src/fov.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2006, Greg McIntyre + * All rights reserved. See the file named COPYING in the distribution + * for more details. + */ + +#include +#include +#include +#define __USE_ISOC99 1 +#include +#include +#include +#include "fov.h" + +/* ++---++---++---++---+ +| || || || | +| || || || | +| || || || | ++---++---++---++---+ 2 ++---++---++---+##### +| || || |##### +| || || |##### +| || || |##### ++---++---++---+#####X 1 <-- y ++---++---++---++---+ +| || || || | +| @ || || || | <-- srcy centre -> dy = 0.5 = y - 0.5 +| || || || | ++---++---++---++---+ 0 +0 1 2 3 4 + ^ ^ + | | + srcx x -> dx = 3.5 = x + 0.5 +centre + +Slope from @ to X. + ++---++---++---++---+ +| || || || | +| || || || | +| || || || | ++---++---++---++---+ 2 ++---++---++---++---+ +| || || || | +| || || || | +| || || || | ++---++---++---+X---+ 1 <-- y ++---++---++---+##### +| || || |##### +| @ || || |##### <-- srcy centre -> dy = 0.5 = y - 0.5 +| || || |##### ++---++---++---+##### 0 +0 1 2 3 + ^ ^ + | | + srcx x -> dx = 2.5 = x - 0.5 +centre + +Slope from @ to X +*/ + + +/* Types ---------------------------------------------------------- */ + +/** \cond INTERNAL */ +typedef struct { + /*@observer@*/ fov_settings_type *settings; + /*@observer@*/ void *map; + /*@observer@*/ void *source; + int source_x; + int source_y; + unsigned radius; +} fov_private_data_type; +/** \endcond */ + +/* Options -------------------------------------------------------- */ + +void fov_settings_init(fov_settings_type *settings) { + settings->shape = FOV_SHAPE_CIRCLE_PRECALCULATE; + settings->corner_peek = FOV_CORNER_NOPEEK; + settings->opaque_apply = FOV_OPAQUE_APPLY; + settings->opaque = NULL; + settings->apply = NULL; + settings->heights = NULL; + settings->numheights = 0; +} + +void fov_settings_set_shape(fov_settings_type *settings, + fov_shape_type value) { + settings->shape = value; +} + +void fov_settings_set_corner_peek(fov_settings_type *settings, + fov_corner_peek_type value) { + settings->corner_peek = value; +} + +void fov_settings_set_opaque_apply(fov_settings_type *settings, + fov_opaque_apply_type value) { + settings->opaque_apply = value; +} + +void fov_settings_set_opacity_test_function(fov_settings_type *settings, + bool (*f)(void *map, + int x, int y)) { + settings->opaque = f; +} + +void fov_settings_set_apply_lighting_function(fov_settings_type *settings, + void (*f)(void *map, + int x, int y, + int dx, int dy, + void *src)) { + settings->apply = f; +} + +/* Circular FOV --------------------------------------------------- */ + +/*@null@*/ static unsigned *precalculate_heights(unsigned maxdist) { + unsigned i; + unsigned *result = (unsigned *)malloc((maxdist+2)*sizeof(unsigned)); + if (result) { + for (i = 0; i <= maxdist; ++i) { + result[i] = (unsigned)sqrtf((float)(maxdist*maxdist - i*i)); + } + result[maxdist+1] = 0; + } + return result; +} + +static unsigned height(fov_settings_type *settings, int x, + unsigned maxdist) { + unsigned **newheights; + + if (maxdist > settings->numheights) { + newheights = (unsigned **)calloc((size_t)maxdist, sizeof(unsigned*)); + if (newheights != NULL) { + if (settings->heights != NULL && settings->numheights > 0) { + /* Copy the pointers to the heights arrays we've already + * calculated. Once copied out, we can free the old + * array of pointers. */ + memcpy(newheights, settings->heights, + settings->numheights*sizeof(unsigned*)); + free(settings->heights); + } + settings->heights = newheights; + settings->numheights = maxdist; + } + } + if (settings->heights) { + if (settings->heights[maxdist-1] == NULL) { + settings->heights[maxdist-1] = precalculate_heights(maxdist); + } + if (settings->heights[maxdist-1] != NULL) { + return settings->heights[maxdist-1][abs(x)]; + } + } + return 0; +} + +void fov_settings_free(fov_settings_type *settings) { + unsigned i; + if (settings != NULL) { + if (settings->heights != NULL && settings->numheights > 0) { + /*@+forloopexec@*/ + for (i = 0; i < settings->numheights; ++i) { + unsigned *h = settings->heights[i]; + if (h != NULL) { + free(h); + } + settings->heights[i] = NULL; + } + /*@=forloopexec@*/ + free(settings->heights); + settings->heights = NULL; + settings->numheights = 0; + } + } +} + +/* Slope ---------------------------------------------------------- */ + +static float fov_slope(float dx, float dy) { + if (dx <= -FLT_EPSILON || dx >= FLT_EPSILON) { + return dy/dx; + } else { + return 0.0; + } +} + +/* Octants -------------------------------------------------------- */ + +#define FOV_DEFINE_OCTANT(signx, signy, rx, ry, nx, ny, nf, apply_edge, apply_diag) \ + static void fov_octant_##nx##ny##nf( \ + fov_private_data_type *data, \ + int dx, \ + float start_slope, \ + float end_slope) { \ + int x, y, dy, dy0, dy1; \ + unsigned h; \ + int prev_blocked = -1; \ + float end_slope_next; \ + fov_settings_type *settings = data->settings; \ + \ + if (dx == 0) { \ + fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope); \ + return; \ + } else if ((unsigned)dx > data->radius) { \ + return; \ + } \ + \ + dy0 = (int)(0.5f + ((float)dx)*start_slope); \ + dy1 = (int)(0.5f + ((float)dx)*end_slope); \ + \ + rx = data->source_##rx signx dx; \ + ry = data->source_##ry signy dy0; \ + \ + if (!apply_diag && dy1 == dx) { \ + /* We do diagonal lines on every second octant, so they don't get done twice. */ \ + --dy1; \ + } \ + \ + switch (settings->shape) { \ + case FOV_SHAPE_CIRCLE_PRECALCULATE: \ + h = height(settings, dx, data->radius); \ + break; \ + case FOV_SHAPE_CIRCLE: \ + h = (unsigned)sqrtf((float)(data->radius*data->radius - dx*dx)); \ + break; \ + case FOV_SHAPE_OCTAGON: \ + h = (data->radius - dx)<<1; \ + break; \ + default: \ + h = data->radius; \ + break; \ + }; \ + if ((unsigned)dy1 > h) { \ + if (h == 0) { \ + return; \ + } \ + dy1 = (int)h; \ + } \ + \ + /*fprintf(stderr, "(%2d) = [%2d .. %2d] (%f .. %f), h=%d,edge=%d\n", \ + dx, dy0, dy1, ((float)dx)*start_slope, \ + 0.5f + ((float)dx)*end_slope, h, apply_edge);*/ \ + \ + for (dy = dy0; dy <= dy1; ++dy) { \ + ry = data->source_##ry signy dy; \ + \ + if (settings->opaque(data->map, x, y)) { \ + if (settings->opaque_apply == FOV_OPAQUE_APPLY && (apply_edge || dy > 0)) { \ + settings->apply(data->map, x, y, x - data->source_x, y - data->source_y, data->source); \ + } \ + if (prev_blocked == 0) { \ + end_slope_next = fov_slope((float)dx + 0.5f, (float)dy - 0.5f); \ + fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope_next); \ + } \ + prev_blocked = 1; \ + } else { \ + if (apply_edge || dy > 0) { \ + settings->apply(data->map, x, y, x - data->source_x, y - data->source_y, data->source); \ + } \ + if (prev_blocked == 1) { \ + start_slope = fov_slope((float)dx - 0.5f, (float)dy - 0.5f); \ + } \ + prev_blocked = 0; \ + } \ + } \ + \ + if (prev_blocked == 0) { \ + fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope); \ + } \ + } + +FOV_DEFINE_OCTANT(+,+,x,y,p,p,n,true,true) +FOV_DEFINE_OCTANT(+,+,y,x,p,p,y,true,false) +FOV_DEFINE_OCTANT(+,-,x,y,p,m,n,false,true) +FOV_DEFINE_OCTANT(+,-,y,x,p,m,y,false,false) +FOV_DEFINE_OCTANT(-,+,x,y,m,p,n,true,true) +FOV_DEFINE_OCTANT(-,+,y,x,m,p,y,true,false) +FOV_DEFINE_OCTANT(-,-,x,y,m,m,n,false,true) +FOV_DEFINE_OCTANT(-,-,y,x,m,m,y,false,false) + + +/* Circle --------------------------------------------------------- */ + +static void _fov_circle(fov_private_data_type *data) { + /* + * Octants are defined by (x,y,r) where: + * x = [p]ositive or [n]egative x increment + * y = [p]ositive or [n]egative y increment + * r = [y]es or [n]o for reflecting on axis x = y + * + * \pmy|ppy/ + * \ | / + * \ | / + * mpn\|/ppn + * ----@---- + * mmn/|\pmn + * / | \ + * / | \ + * /mmy|mpy\ + */ + fov_octant_ppn(data, 1, (float)0.0f, (float)1.0f); + fov_octant_ppy(data, 1, (float)0.0f, (float)1.0f); + fov_octant_pmn(data, 1, (float)0.0f, (float)1.0f); + fov_octant_pmy(data, 1, (float)0.0f, (float)1.0f); + fov_octant_mpn(data, 1, (float)0.0f, (float)1.0f); + fov_octant_mpy(data, 1, (float)0.0f, (float)1.0f); + fov_octant_mmn(data, 1, (float)0.0f, (float)1.0f); + fov_octant_mmy(data, 1, (float)0.0f, (float)1.0f); +} + +void fov_circle(fov_settings_type *settings, + void *map, + void *source, + int source_x, + int source_y, + unsigned radius) { + fov_private_data_type data; + + data.settings = settings; + data.map = map; + data.source = source; + data.source_x = source_x; + data.source_y = source_y; + data.radius = radius; + + _fov_circle(&data); +} + +/** + * Limit x to the range [a, b]. + */ +static float betweenf(float x, float a, float b) { + if (x - a < FLT_EPSILON) { /* x < a */ + return a; + } else if (x - b > FLT_EPSILON) { /* x > b */ + return b; + } else { + return x; + } +} + +#define BEAM_DIRECTION(d, p1, p2, p3, p4, p5, p6, p7, p8) \ + if (direction == d) { \ + end_slope = betweenf(a, 0.0f, 1.0f); \ + fov_octant_##p1(&data, 1, 0.0f, end_slope); \ + fov_octant_##p2(&data, 1, 0.0f, end_slope); \ + if (a - 1.0f > FLT_EPSILON) { /* a > 1.0f */ \ + start_slope = betweenf(2.0f - a, 0.0f, 1.0f); \ + fov_octant_##p3(&data, 1, start_slope, 1.0f); \ + fov_octant_##p4(&data, 1, start_slope, 1.0f); \ + } \ + if (a - 2.0f > FLT_EPSILON) { /* a > 2.0f */ \ + end_slope = betweenf(a - 2.0f, 0.0f, 1.0f); \ + fov_octant_##p5(&data, 1, 0.0f, end_slope); \ + fov_octant_##p6(&data, 1, 0.0f, end_slope); \ + } \ + if (a - 3.0f > FLT_EPSILON) { /* a > 3.0f */ \ + start_slope = betweenf(4.0f - a, 0.0f, 1.0f); \ + fov_octant_##p7(&data, 1, start_slope, 1.0f); \ + fov_octant_##p8(&data, 1, start_slope, 1.0f); \ + } \ + } + +#define BEAM_DIRECTION_DIAG(d, p1, p2, p3, p4, p5, p6, p7, p8) \ + if (direction == d) { \ + start_slope = betweenf(1.0f - a, 0.0f, 1.0f); \ + fov_octant_##p1(&data, 1, start_slope, 1.0f); \ + fov_octant_##p2(&data, 1, start_slope, 1.0f); \ + if (a - 1.0f > FLT_EPSILON) { /* a > 1.0f */ \ + end_slope = betweenf(a - 1.0f, 0.0f, 1.0f); \ + fov_octant_##p3(&data, 1, 0.0f, end_slope); \ + fov_octant_##p4(&data, 1, 0.0f, end_slope); \ + } \ + if (a - 2.0f > FLT_EPSILON) { /* a > 2.0f */ \ + start_slope = betweenf(3.0f - a, 0.0f, 1.0f); \ + fov_octant_##p5(&data, 1, start_slope, 1.0f); \ + fov_octant_##p6(&data, 1, start_slope, 1.0f); \ + } \ + if (a - 3.0f > FLT_EPSILON) { /* a > 3.0f */ \ + end_slope = betweenf(a - 3.0f, 0.0f, 1.0f); \ + fov_octant_##p7(&data, 1, 0.0f, end_slope); \ + fov_octant_##p8(&data, 1, 0.0f, end_slope); \ + } \ + } + +void fov_beam(fov_settings_type *settings, void *map, void *source, + int source_x, int source_y, unsigned radius, + fov_direction_type direction, float angle) { + + fov_private_data_type data; + float start_slope, end_slope, a; + + data.settings = settings; + data.map = map; + data.source = source; + data.source_x = source_x; + data.source_y = source_y; + data.radius = radius; + + if (angle <= 0.0f) { + return; + } else if (angle >= 360.0f) { + _fov_circle(&data); + return; + } + + /* Calculate the angle as a percentage of 45 degrees, halved (for + * each side of the centre of the beam). e.g. angle = 180.0f means + * half the beam is 90.0 which is 2x45, so the result is 2.0. + */ + a = angle/90.0f; + + BEAM_DIRECTION(FOV_EAST, ppn, pmn, ppy, mpy, pmy, mmy, mpn, mmn); + BEAM_DIRECTION(FOV_WEST, mpn, mmn, pmy, mmy, ppy, mpy, ppn, pmn); + BEAM_DIRECTION(FOV_NORTH, mpy, mmy, mmn, pmn, mpn, ppn, pmy, ppy); + BEAM_DIRECTION(FOV_SOUTH, pmy, ppy, mpn, ppn, mmn, pmn, mmy, mpy); + BEAM_DIRECTION_DIAG(FOV_NORTHEAST, pmn, mpy, mmy, ppn, mmn, ppy, mpn, pmy); + BEAM_DIRECTION_DIAG(FOV_NORTHWEST, mmn, mmy, mpn, mpy, pmy, pmn, ppy, ppn); + BEAM_DIRECTION_DIAG(FOV_SOUTHEAST, ppn, ppy, pmy, pmn, mpn, mpy, mmn, mmy); + BEAM_DIRECTION_DIAG(FOV_SOUTHWEST, pmy, mpn, ppy, mmn, ppn, mmy, pmn, mpy); +}