From f545cf0276e95c9dca33d36d1a0cfe3b4995473a Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Wed, 23 May 2018 21:28:29 -0400 Subject: somethign --- CMakeLists.txt | 33 ++++ cmake/FindSDL2.cmake | 254 ++++++++++++++++++++++++ src/main.cpp | 549 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/untitled.txt | 0 vendor/fov.c | 427 +++++++++++++++++++++++++++++++++++++++ vendor/fov.h | 245 +++++++++++++++++++++++ 6 files changed, 1508 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindSDL2.cmake create mode 100644 src/main.cpp create mode 100644 src/untitled.txt create mode 100644 vendor/fov.c create mode 100644 vendor/fov.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3c629f5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required (VERSION 3.1) +project (Ether) + +set(CMAKE_BUILD_TYPE Debug) + +# Set directory to look for package helpers. +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Ether_SOURCE_DIR}/cmake") + +# Get dependencies. + +find_package(PkgConfig) +pkg_check_modules(GLFW REQUIRED glfw3) + +find_package(SDL2 REQUIRED) + +set(ALL_LIBS + ${SDL2_LIBRARY} +) + +include_directories( + ${SDL2_INCLUDE_DIR} + src + vendor +) + +add_executable(Ether + src/main.cpp + vendor/fov.c +) + +set_property(TARGET Ether PROPERTY CXX_STANDARD 17) +set_property(TARGET Ether PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(Ether ${ALL_LIBS}) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 0000000..f9ebcf3 --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,254 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDL2main.h and SDL2main.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2 is an environment variable that would +# correspond to the ./configure --prefix=$SDL2 +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL2 guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL2 convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). +# +# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake +# module with the minor edit of changing "SDL" to "SDL2" where necessary. This +# was not created for redistribution, and exists temporarily pending official +# SDL2 CMake modules. +# +# Note that on windows this will only search for the 32bit libraries, to search +# for 64bit change x86/i686-w64 to x64/x86_64-w64 + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# CMake - Cross Platform Makefile Generator +# Copyright 2000-2014 Kitware, Inc. +# Copyright 2000-2011 Insight Software Consortium +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + ${SDL2} + $ENV{SDL2} + PATH_SUFFIXES include/SDL2 include SDL2 + i686-w64-mingw32/include/SDL2 + x86_64-w64-mingw32/include/SDL2 + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include/SDL2 + /usr/include/SDL2 + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) + +# Lookup the 64 bit libs on x64 +IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2 + HINTS + ${SDL2} + $ENV{SDL2} + PATH_SUFFIXES lib64 lib + lib/x64 + x86_64-w64-mingw32/lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) +# On 32bit build find the 32bit libs +ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8) + FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2 + HINTS + ${SDL2} + $ENV{SDL2} + PATH_SUFFIXES lib + lib/x86 + i686-w64-mingw32/lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) +ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + # Lookup the 64 bit libs on x64 + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + ${SDL2} + $ENV{SDL2} + PATH_SUFFIXES lib64 lib + lib/x64 + x86_64-w64-mingw32/lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + # On 32bit build find the 32bit libs + ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8) + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + ${SDL2} + $ENV{SDL2} + PATH_SUFFIXES lib + lib/x86 + i686-w64-mingw32/lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +SET(SDL2_FOUND "NO") + IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + + SET(SDL2_FOUND "YES") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..2fc610b --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,549 @@ +#include +#include +#include +#include +#include +#include +#include + +class sdl_error : public std::logic_error { +public: + + sdl_error() : std::logic_error(SDL_GetError()) + { + } +}; + +class window_deleter { +public: + + void operator()(SDL_Window* ptr) + { + SDL_DestroyWindow(ptr); + } +}; + +using window_ptr = std::unique_ptr; + +class renderer_deleter { +public: + + void operator()(SDL_Renderer* ptr) + { + SDL_DestroyRenderer(ptr); + } +}; + +using renderer_ptr = std::unique_ptr; + +enum class Tile { + Floor, + Wall, + Dark, + Dust, + Lamp +}; + +const int GAME_WIDTH = 640; +const int GAME_HEIGHT = 480; +const int TILE_WIDTH = 8; +const int TILE_HEIGHT = 8; +const int VIEW_WIDTH = GAME_WIDTH / TILE_WIDTH; +const int VIEW_HEIGHT = GAME_HEIGHT / TILE_HEIGHT; + +class Map { +public: + + Map() : + tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor), + lighting(VIEW_WIDTH*VIEW_HEIGHT, false) + { + } + + std::vector tiles; + std::vector lighting; + std::deque> playerLocs; +}; + +int player_x = VIEW_WIDTH / 2; +int player_y = VIEW_HEIGHT / 2; + +void render( + SDL_Renderer* ren, + const Map& map, + bool drawDark = true) +{ + SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255); + SDL_RenderClear(ren); + + for (int y = 0; y < VIEW_HEIGHT; y++) + { + for (int x = 0; x < VIEW_WIDTH; x++) + { + bool draw = true; + + if (player_x == x && player_y == y) + { + SDL_SetRenderDrawColor(ren, 255, 255, 0, 255); + } else if (!map.lighting.at(x+VIEW_WIDTH*y)) + { + if (drawDark) + { + SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); + } else { + draw = false; + } + } else { + switch (map.tiles.at(x+y*VIEW_WIDTH)) + { + case Tile::Floor: + { + SDL_SetRenderDrawColor(ren, 210, 210, 210, 255); + break; + } + + case Tile::Wall: + case Tile::Dark: + { + SDL_SetRenderDrawColor(ren, 100, 100, 100, 255); + break; + } + + case Tile::Dust: + { + SDL_SetRenderDrawColor(ren, 128, 40, 255, 255); + break; + } + + case Tile::Lamp: + { + SDL_SetRenderDrawColor(ren, 0, 255, 255, 255); + break; + } + } + } + + + if (draw) + { + SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT}; + SDL_RenderFillRect(ren, &rect); + } + + + } + } + + SDL_RenderPresent(ren); +} + +void incrementIfSet(Map& map, int& count, int x, int y, int w, int h, Tile val = Tile::Dark) +{ + if ((x >= 0) && (x < w) && (y >= 0) && (y < h) && (map.tiles[x+w*y] == val)) + { + count++; + } +} + +void tick(Map& map, int x1 = 0, int y1 = 0, int x2 = VIEW_WIDTH, int y2 = VIEW_HEIGHT) +{ + std::vector temp(map.tiles); + + for (int y = std::max(y1, 0); y < std::min(y2, VIEW_HEIGHT); y++) + { + for (int x = std::max(x1, 0); x < std::min(x2, VIEW_WIDTH); x++) + { + if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp) + { + continue; + } + + int count = 0; + + incrementIfSet(map, count, x-1, y-1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x-1, y+1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x , y , VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x+1, y-1, VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT); + incrementIfSet(map, count, x+1, y+1, VIEW_WIDTH, VIEW_HEIGHT); + + if (count >= 5) + { + temp[x+VIEW_WIDTH*y] = Tile::Dark; + } else { + temp[x+VIEW_WIDTH*y] = Tile::Floor; + } + } + } + + map.tiles = temp; +} + +void movePlayer(int x, int y, Map& map) +{ + if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT) && + map.tiles[x+VIEW_WIDTH*y] == Tile::Floor) + { + if (map.tiles[player_x+player_y*VIEW_WIDTH] == Tile::Floor) + { + map.tiles[player_x+player_y*VIEW_WIDTH] = Tile::Dust; + map.playerLocs.emplace_front(player_x, player_y); + + if (map.playerLocs.size() > 5) + { + map.playerLocs.pop_back(); + } + } + + + + + player_x = x; + player_y = y; + } +} + +void setIfValid(Map& map, int x, int y, Tile val) +{ + if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) + { + map.tiles[x+VIEW_WIDTH*y] = val; + } +} + +void recalculateLighting(Map& map, fov_settings_type* fov) +{ + map.lighting = std::vector(VIEW_WIDTH*VIEW_HEIGHT, false); + + fov_settings_set_opacity_test_function( + fov, + [] (void* map, int x, int y) { + return + x >= 0 && + x < VIEW_WIDTH && + y >= 0 && + y < VIEW_HEIGHT && + static_cast(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark; + }); + + fov_settings_set_apply_lighting_function( + fov, + [] (void* map, int x, int y, int, int, void*) { + if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT)) + { + static_cast(map)->lighting[x+VIEW_WIDTH*y] = true; + } + }); + + for (int y = 0; y < VIEW_HEIGHT; y++) + { + for (int x = 0; x < VIEW_WIDTH; x++) + { + if ((player_x == x && player_y == y) || map.tiles[x+VIEW_WIDTH*y] == Tile::Dust || map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + { + fov_circle(fov, static_cast(&map), nullptr, x, y, 8); + } + + if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp) + { + map.lighting[x+VIEW_WIDTH*y] = true; + } + } + } +} + +int main(int, char**) +{ + std::random_device randomEngine; + std::mt19937 rng(randomEngine()); + + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + throw sdl_error(); + } + + try + { + window_ptr win( + SDL_CreateWindow("Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN)); + + if (!win) + { + throw sdl_error(); + } + + renderer_ptr ren( + SDL_CreateRenderer( + win.get(), + -1, + SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); + + if (!ren) + { + throw sdl_error(); + } + + //std::vector tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor); + //std::vector lighting(VIEW_WIDTH*VIEW_HEIGHT, false); + Map map; + + std::unique_ptr fov(new fov_settings_type()); + fov_settings_init(fov.get()); + + + for (int y = 0; y < VIEW_HEIGHT; y++) + { + for (int x = 0; x < VIEW_WIDTH; x++) + { + if (std::bernoulli_distribution(0.5)(rng)) + { + map.tiles[x+y*VIEW_WIDTH] = Tile::Dark; + } + } + } + + tick(map); + tick(map); + tick(map); + + bool quit = false; + SDL_Event e; + while (!quit) + { + //SDL_PumpEvents(); + bool input = false; + int presses = 0; + while (SDL_PollEvent(&e)) + { + if (e.type == SDL_QUIT) + { + quit = true; + } else if (e.type == SDL_KEYDOWN) + { + presses++; + + switch (e.key.keysym.sym) + { + case SDLK_SPACE: + { + input = true; + + setIfValid(map, player_x-1, player_y , Tile::Floor); + setIfValid(map, player_x+1, player_y , Tile::Floor); + setIfValid(map, player_x , player_y , Tile::Lamp); + setIfValid(map, player_x , player_y-1, Tile::Floor); + setIfValid(map, player_x , player_y+1, Tile::Floor); + + auto locs = map.playerLocs; + while (!locs.empty()) + { + movePlayer(std::get<0>(locs.front()), std::get<1>(locs.front()), map); + locs.pop_front(); + + tick( + map, + player_x - 7, + player_y - 7, + player_x + 8, + player_y + 8); + + render(ren.get(), map, false); + SDL_Delay(30); + } + + break; + } + } + } else if (e.type == SDL_KEYUP) + { + presses++; + } + } + + if (presses > 0) + { + for (int y = 0; y < VIEW_HEIGHT; y++) + { + for (int x = 0; x < VIEW_WIDTH; x++) + { + if (map.tiles[x+y*VIEW_WIDTH] == Tile::Dust) + { + map.tiles[x+y*VIEW_WIDTH] = Tile::Floor; + } + } + } + } + + const Uint8* state = SDL_GetKeyboardState(NULL); + + for (int i = 0; i < presses; i++) + { + //switch (e.key.keysym.sym) + { + //case SDLK_UP: + if (state[SDL_SCANCODE_UP]) + { + movePlayer(player_x, player_y-1, map); + input = true; + //break; + } + + //case SDLK_DOWN: + if (state[SDL_SCANCODE_DOWN]) + { + movePlayer(player_x, player_y+1, map); + input = true; + //break; + } + + //case SDLK_LEFT: + if (state[SDL_SCANCODE_LEFT]) + { + movePlayer(player_x-1, player_y, map); + input = true; + //break; + } + + //case SDLK_RIGHT: + if (state[SDL_SCANCODE_RIGHT]) + { + movePlayer(player_x+1, player_y, map); + input = true; + //break; + } + + + } + + if (input) + { + //render(ren.get(), tiles, false); + //SDL_Delay(1); + } + + //} + } + + bool checkForDust = true; + + while (checkForDust) + { + checkForDust = false; + + for (int y = 0; y < VIEW_HEIGHT; y++) + { + for (int x = 0; x < VIEW_WIDTH; x++) + { + if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp) + { + int count = 0; + + incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust); + incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust); + incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust); + incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust); + + if (count > 0) + { + checkForDust = true; + + map.tiles[x+y*VIEW_WIDTH] = Tile::Dust; + + /*for (int i = 0; i < 4; i++) + { + tick( + map, + x - 7, + y - 7, + x + 8, + y + 8); + + for (int l = 0; l < (i*2+1); l++) + { + int px = x - i + l; + int py = y - i + l; + + auto fillInDust = [&] (int sx, int sy) { + if (sx > 0 && sx < VIEW_WIDTH && + sy > 0 && sy < VIEW_HEIGHT && + map.tiles[sx+sy*VIEW_WIDTH] == Tile::Floor && + !(player_y == sy && player_x == sx)) + { + map.tiles[sx+sy*VIEW_WIDTH] = Tile::Dust; + } + }; + + fillInDust(px , y - i); + fillInDust(px , y + i); + fillInDust(x - i, py ); + fillInDust(x + i, py ); + } + + render(ren.get(), map, false); + SDL_Delay(30); + }*/ + + + /* + + for (int py = std::max(0, y - 7); py < std::min(VIEW_HEIGHT, y + 8); py++) + { + for (int px = std::max(0, x - 7); px < std::min(VIEW_WIDTH, x + 8); px++) + { + if ((map.tiles[px+py*VIEW_WIDTH] == Tile::Floor) && + !(player_y == py && player_x == px)) + { + map.tiles[px+py*VIEW_WIDTH] = Tile::Dust; + } + } + }*/ + + std::unique_ptr dusty(new fov_settings_type); + fov_settings_set_opacity_test_function( + dusty.get(), + [] (void* map, int x, int y) { + return + x >= 0 && + x < VIEW_WIDTH && + y >= 0 && + y < VIEW_HEIGHT && + static_cast(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark; + }); + + fov_settings_set_apply_lighting_function( + dusty.get(), + [] (void* map, int x, int y, int, int, void*) { + if ((x >= 0) && (x < VIEW_WIDTH) && + (y >= 0) && (y < VIEW_HEIGHT) && + (static_cast(map)->tiles[x+VIEW_WIDTH*y] == Tile::Floor)) + { + static_cast(map)->tiles[x+VIEW_WIDTH*y] = Tile::Dust; + } + }); + + fov_circle(dusty.get(), static_cast(&map), nullptr, x, y, 8); + + render(ren.get(), map, false); + SDL_Delay(50); + } + } + } + } + } + + + recalculateLighting(map, fov.get()); + render(ren.get(), map, true); + SDL_Delay(10); + } + } catch (const sdl_error&) + { + } + + SDL_Quit(); + + return 0; +} \ No newline at end of file diff --git a/src/untitled.txt b/src/untitled.txt new file mode 100644 index 0000000..e69de29 diff --git a/vendor/fov.c b/vendor/fov.c new file mode 100644 index 0000000..74ed5c8 --- /dev/null +++ b/vendor/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); +} diff --git a/vendor/fov.h b/vendor/fov.h new file mode 100644 index 0000000..b27f59c --- /dev/null +++ b/vendor/fov.h @@ -0,0 +1,245 @@ +/* + * 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 + * 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 +#include + +#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; + + /** Whether to peek around corners. */ + fov_corner_peek_type corner_peek; + + /** Whether to call apply on opaque tiles. */ + fov_opaque_apply_type opaque_apply; + + /** \cond INTERNAL */ + + /** Pre-calculated data. \internal */ + /*@null@*/ height_array_t *heights; + + /** Size of pre-calculated data. \internal */ + unsigned numheights; + + /** \endcond */ +} 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); + +/** + * 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); + +/** + * NOT YET IMPLEMENTED. + * + * 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 -- cgit 1.4.1