hfov (empty) → 0.5
raw patch · 6 files changed
+826/−0 lines, 6 filesdep +basedep +haskell98setup-changed
Dependencies added: base, haskell98
Files
+ FOV.hsc view
@@ -0,0 +1,114 @@+{-# OPTIONS -fffi -fglasgow-exts #-}+-- | HFOV is a library for calculating field of view in a 2D raster grid, such+-- as those found in roguelike games.+--+-- Thanks to Greg McIntyre for the original C library to which this Haskell+-- library binds. It can be found at <http://libfov.sourceforge.net/wiki>.+module FOV (+ Settings,+ Shape(..),+ Direction(..),+ newSettings, -- IO Settings+ setShape, -- Settings -> Shape -> IO ()+ setOpaqueApply, -- Settings -> Bool -> IO ()+ circle,+ beam+ ) where++import Foreign.Ptr+import Foreign.ForeignPtr++#include "fov.h"++type OpacityTestFn a = Ptr a -> Int -> Int -> IO Bool+foreign import ccall "wrapper" mkOpacityTestFn :: OpacityTestFn a -> IO (FunPtr (OpacityTestFn a))++type ApplyFn map src = Ptr map -> Int -> Int -> Int -> Int -> Ptr src -> IO ()+foreign import ccall "wrapper" mkApplyFn :: ApplyFn a b -> IO (FunPtr (ApplyFn a b))++data SettingsRaw++-- | Opaque data structure for holding information about FOV calculation.+newtype Settings = Settings (ForeignPtr SettingsRaw)++-- | Shape of the field.+data Shape+ -- | Limit the field of view to a circle radius R by precalculating the+ -- circle shape. This consumes memory at the rate of 4*(R+2) bytes per R+ -- used in calls to fovCircle. Each radius is only calculated once.+ = CirclePrecalculate+ -- | Limit the field to a circle shape calculated on the fly.+ | Circle+ -- | Limit the field to an octagon with maximum radius R.+ | Octagon+ -- | Limit the field to an RxR square.+ | Square++data Direction = East | NorthEast | North | NorthWest | West | SouthWest | South | SouthEast++rawshape :: (Num t) => Shape -> t+rawshape CirclePrecalculate = #const FOV_SHAPE_CIRCLE_PRECALCULATE+rawshape Square = #const FOV_SHAPE_SQUARE+rawshape Circle = #const FOV_SHAPE_CIRCLE+rawshape Octagon = #const FOV_SHAPE_OCTAGON++rawdirection :: (Num t) => Direction -> t+rawdirection East = #const FOV_EAST+rawdirection NorthEast = #const FOV_NORTHEAST+rawdirection North = #const FOV_NORTH+rawdirection NorthWest = #const FOV_NORTHWEST+rawdirection West = #const FOV_WEST+rawdirection SouthWest = #const FOV_SOUTHWEST+rawdirection South = #const FOV_SOUTH+rawdirection SouthEast = #const FOV_SOUTHEAST++foreign import ccall unsafe new_fov_settings :: IO (Ptr SettingsRaw)+foreign import ccall unsafe fov_settings_set_shape :: Ptr SettingsRaw -> Int -> IO ()+foreign import ccall unsafe fov_settings_set_opaque_apply :: Ptr SettingsRaw -> Int -> IO ()+foreign import ccall unsafe fov_settings_set_apply_lighting_function :: Ptr SettingsRaw -> FunPtr (ApplyFn a b) -> IO ()+foreign import ccall unsafe fov_settings_set_opacity_test_function :: Ptr SettingsRaw -> FunPtr (OpacityTestFn a) -> IO ()+foreign import ccall unsafe "&fov_settings_free" fov_settings_free :: FunPtr (Ptr SettingsRaw -> IO ())+foreign import ccall fov_circle :: Ptr SettingsRaw -> Ptr map -> Ptr src -> Int -> Int -> Int -> IO ()+foreign import ccall fov_beam :: Ptr SettingsRaw -> Ptr map -> Ptr src -> Int -> Int -> Int -> Int -> Float -> IO ()++-- | Create a new FOV settings structure.+newSettings :: IO Settings+newSettings = do+ s <- new_fov_settings >>= newForeignPtr fov_settings_free+ return $ Settings s++-- | Set the shape of the field of view. The default is CirclePrecalculate.+setShape :: Settings -> Shape -> IO ()+setShape (Settings fps) sh = withForeignPtr fps $ \s -> do+ fov_settings_set_shape s (rawshape sh)++-- | Sets whether or not to apply lighting to opaque squares.+setOpaqueApply :: Settings -> Bool -> IO ()+setOpaqueApply (Settings fps) a = withForeignPtr fps $ \s -> do+ fov_settings_set_opaque_apply s (if a then (#const FOV_OPAQUE_APPLY) else (#const FOV_OPAQUE_NOAPPLY))++-- | Cast a 360 degree field of view.+circle :: Settings -- ^The FOV settings structure to use+ -> (Int,Int) -- ^The centre of the field+ -> Int -- ^The radius+ -> (Int -> Int -> IO ()) -- ^The function to be called in order to apply light to a certain position+ -> (Int -> Int -> IO Bool) -- ^The function to determine the opacity of a certain cell+ -> IO ()+circle (Settings fps) (x,y) r apply opaque = withForeignPtr fps $ \s -> do+ fov_settings_set_apply_lighting_function s =<< mkApplyFn (\_ x' y' _ _ _ -> apply x' y')+ fov_settings_set_opacity_test_function s =<< mkOpacityTestFn (\_ x' y' -> opaque x' y')+ fov_circle s nullPtr nullPtr x y r++-- | Cast a beam.+beam :: Settings -- ^The FOV settings structure to use+ -> (Int,Int) -- ^Origin of the beam+ -> Int -- ^Length (radius) of the beam+ -> Direction -- ^Direction of the centre of the beam+ -> Float -- ^Width of the beam (in degrees)+ -> (Int -> Int -> IO ()) -- ^Light application function+ -> (Int -> Int -> IO Bool) -- ^Opacity test function+ -> IO ()+beam (Settings fps) (x,y) r dir angle apply opaque = withForeignPtr fps $ \s -> do+ fov_settings_set_apply_lighting_function s =<< mkApplyFn (\_ x' y' _ _ _ -> apply x' y')+ fov_settings_set_opacity_test_function s =<< mkOpacityTestFn (\_ x' y' -> opaque x' y')+ fov_beam s nullPtr nullPtr x y r (rawdirection dir) angle
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2006-2007 Greg McIntyre, 2008 Jeremy Apthorp+All rights reserved.++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ fov.c view
@@ -0,0 +1,429 @@+/*+ * Copyright (C) 2006, Greg McIntyre+ * All rights reserved. See the file named COPYING in the distribution+ * for more details.+ */++#include <stdlib.h>+#include <string.h>+#include <stdio.h>+#define __USE_ISOC99 1+#include <math.h>+#include <float.h>+#include <assert.h>+#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 ---------------------------------------------------------- */++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;++/* 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->numheights = 0;+}++fov_settings_type *new_fov_settings() {+ fov_settings_type *s = malloc(sizeof(fov_settings_type));+ fov_settings_init(s);+ return s;+}++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, dx, dy, 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, dx, dy, 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);+ }++ /* 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);+}
+ fov.h view
@@ -0,0 +1,238 @@+/*+ * Copyright (C) 2006-2007, Greg McIntyre. All rights reserved. See the file+ * named COPYING in the distribution for more details.+ */++/**+ * \mainpage Field of View Library+ * + * \section about About+ * + * This is a C library which implements a course-grained lighting+ * algorithm suitable for tile-based games such as roguelikes.+ * + * \section copyright Copyright+ * + * \verbinclude COPYING+ * + * \section thanks Thanks+ * + * Thanks to Björn Bergström+ * <bjorn.bergstrom@hyperisland.se> for the algorithm.+ * + */++/**+ * \file fov.h+ * Field-of-view algorithm for dynamically casting light/shadow on a+ * low resolution 2D raster.+ */+#ifndef LIBFOV_HEADER+#define LIBFOV_HEADER++#include <stdbool.h>+#include <stddef.h>++#ifdef __cplusplus+extern "C" {+#endif++/** Eight-way directions. */+typedef enum {+ FOV_EAST = 0,+ FOV_NORTHEAST,+ FOV_NORTH,+ FOV_NORTHWEST,+ FOV_WEST,+ FOV_SOUTHWEST,+ FOV_SOUTH,+ FOV_SOUTHEAST+} fov_direction_type;++/** Values for the shape setting. */+typedef enum {+ FOV_SHAPE_CIRCLE_PRECALCULATE,+ FOV_SHAPE_SQUARE,+ FOV_SHAPE_CIRCLE,+ FOV_SHAPE_OCTAGON+} fov_shape_type;++/** Values for the corner peek setting. */+typedef enum {+ FOV_CORNER_NOPEEK,+ FOV_CORNER_PEEK+} fov_corner_peek_type;++/** Values for the opaque apply setting. */+typedef enum {+ FOV_OPAQUE_APPLY,+ FOV_OPAQUE_NOAPPLY+} fov_opaque_apply_type;++/** @cond INTERNAL */+typedef /*@null@*/ unsigned *height_array_t;+/** @endcond */++typedef struct {+ /** Opacity test callback. */+ /*@null@*/ bool (*opaque)(void *map, int x, int y);++ /** Lighting callback to set lighting on a map tile. */+ /*@null@*/ void (*apply)(void *map, int x, int y, int dx, int dy, void *src);++ /** Shape setting. */+ fov_shape_type shape;+ fov_corner_peek_type corner_peek;+ fov_opaque_apply_type opaque_apply;++ /* Pre-calculated data. */+ /*@null@*/ height_array_t *heights;++ /* Size of pre-calculated data. */+ unsigned numheights;+} fov_settings_type;++/** The opposite direction to that given. */+#define fov_direction_opposite(direction) ((fov_direction_type)(((direction)+4)&0x7))++/**+ * Set all the default options. You must call this option when you+ * create a new settings data structure.+ *+ * These settings are the defaults used:+ *+ * - shape: FOV_SHAPE_CIRCLE_PRECALCULATE+ * - corner_peek: FOV_CORNER_NOPEEK+ * - opaque_apply: FOV_OPAQUE_APPLY+ *+ * Callbacks still need to be set up after calling this function.+ *+ * \param settings Pointer to data structure containing settings.+ */+void fov_settings_init(fov_settings_type *settings);+fov_settings_type *new_fov_settings();++/**+ * Set the shape of the field of view.+ *+ * \param settings Pointer to data structure containing settings.+ * \param value One of the following values, where R is the radius:+ *+ * - FOV_SHAPE_CIRCLE_PRECALCULATE \b (default): Limit the FOV to a+ * circle with radius R by precalculating, which consumes more memory+ * at the rate of 4*(R+2) bytes per R used in calls to fov_circle. + * Each radius is only calculated once so that it can be used again. + * Use fov_free() to free this precalculated data's memory.+ *+ * - FOV_SHAPE_CIRCLE: Limit the FOV to a circle with radius R by+ * calculating on-the-fly.+ *+ * - FOV_SHAPE_OCTOGON: Limit the FOV to an octogon with maximum radius R.+ *+ * - FOV_SHAPE_SQUARE: Limit the FOV to an R*R square.+ */+void fov_settings_set_shape(fov_settings_type *settings, fov_shape_type value);++/**+ * <em>NOT YET IMPLEMENTED</em>.+ *+ * Set whether sources will peek around corners.+ *+ * \param settings Pointer to data structure containing settings.+ * \param value One of the following values:+ *+ * - FOV_CORNER_PEEK \b (default): Renders:+\verbatim+ ........+ ........+ ........+ ..@# + ...# +\endverbatim+ * - FOV_CORNER_NOPEEK: Renders:+\verbatim+ ......+ .....+ ....+ ..@#+ ...#+\endverbatim+ */+void fov_settings_set_corner_peek(fov_settings_type *settings, fov_corner_peek_type value);++/**+ * Whether to call the apply callback on opaque tiles.+ *+ * \param settings Pointer to data structure containing settings.+ * \param value One of the following values:+ *+ * - FOV_OPAQUE_APPLY \b (default): Call apply callback on opaque tiles.+ * - FOV_OPAQUE_NOAPPLY: Do not call the apply callback on opaque tiles.+ */+void fov_settings_set_opaque_apply(fov_settings_type *settings, fov_opaque_apply_type value);++/**+ * Set the function used to test whether a map tile is opaque.+ *+ * \param settings Pointer to data structure containing settings.+ * \param f The function called to test whether a map tile is opaque.+ */+void fov_settings_set_opacity_test_function(fov_settings_type *settings, bool (*f)(void *map, int x, int y));++/**+ * Set the function used to apply lighting to a map tile.+ *+ * \param settings Pointer to data structure containing settings.+ * \param f The function called to apply lighting to a map tile.+ */+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));++/**+ * Free any memory that may have been cached in the settings+ * structure.+ *+ * \param settings Pointer to data structure containing settings.+ */+void fov_settings_free(fov_settings_type *settings);++/**+ * Calculate a full circle field of view from a source at (x,y).+ *+ * \param settings Pointer to data structure containing settings.+ * \param map Pointer to map data structure to be passed to callbacks.+ * \param source Pointer to data structure holding source of light.+ * \param source_x x-axis coordinate from which to start.+ * \param source_y y-axis coordinate from which to start.+ * \param radius Euclidean distance from (x,y) after which to stop.+ */+void fov_circle(fov_settings_type *settings, void *map, void *source,+ int source_x, int source_y, unsigned radius+);++/**+ * Calculate a field of view from source at (x,y), pointing+ * in the given direction and with the given angle. The larger+ * the angle, the wider, "less focused" the beam. Each side of the+ * line pointing in the direction from the source will be half the+ * angle given such that the angle specified will be represented on+ * the raster.+ *+ * \param settings Pointer to data structure containing settings.+ * \param map Pointer to map data structure to be passed to callbacks.+ * \param source Pointer to data structure holding source of light.+ * \param source_x x-axis coordinate from which to start.+ * \param source_y y-axis coordinate from which to start.+ * \param radius Euclidean distance from (x,y) after which to stop.+ * \param direction One of eight directions the beam of light can point.+ * \param angle The angle at the base of the beam of light, in degrees.+ */+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+);++#ifdef __cplusplus+} /* extern "C" */+#endif++#endif
+ hfov.cabal view
@@ -0,0 +1,22 @@+Name: hfov+Version: 0.5+Category: Game+Synopsis: Field-of-view calculation for low-resolution 2D raster grids.+Description: A Haskell binding to a Field of View calculation library+ written by Greg McIntyre (blue_puyo) in C.+Stability: Unstable+License: BSD3+License-file: LICENSE+Author: Jeremy Apthorp <nornagon@nornagon.net>, Greg McIntyre+Maintainer: nornagon@nornagon.net+Build-Depends: base >= 1.0, haskell98 >= 1.0+Build-Type: Simple+Tested-with: GHC==6.8.2++Exposed-Modules: FOV+C-sources: fov.c+Includes: fov.h+Extra-source-files: fov.h+Extensions: CPP, ForeignFunctionInterface+Include-dirs: .+ghc-options: -Wall