packages feed

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&ouml;rn Bergstr&ouml;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