summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt33
-rw-r--r--cmake/FindSDL2.cmake254
-rw-r--r--src/main.cpp549
-rw-r--r--src/untitled.txt0
-rw-r--r--vendor/fov.c427
-rw-r--r--vendor/fov.h245
6 files changed, 1508 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3c629f5 --- /dev/null +++ b/CMakeLists.txt
@@ -0,0 +1,33 @@
1cmake_minimum_required (VERSION 3.1)
2project (Ether)
3
4set(CMAKE_BUILD_TYPE Debug)
5
6# Set directory to look for package helpers.
7set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Ether_SOURCE_DIR}/cmake")
8
9# Get dependencies.
10
11find_package(PkgConfig)
12pkg_check_modules(GLFW REQUIRED glfw3)
13
14find_package(SDL2 REQUIRED)
15
16set(ALL_LIBS
17 ${SDL2_LIBRARY}
18)
19
20include_directories(
21 ${SDL2_INCLUDE_DIR}
22 src
23 vendor
24)
25
26add_executable(Ether
27 src/main.cpp
28 vendor/fov.c
29)
30
31set_property(TARGET Ether PROPERTY CXX_STANDARD 17)
32set_property(TARGET Ether PROPERTY CXX_STANDARD_REQUIRED ON)
33target_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 @@
1# Locate SDL2 library
2# This module defines
3# SDL2_LIBRARY, the name of the library to link against
4# SDL2_FOUND, if false, do not try to link to SDL2
5# SDL2_INCLUDE_DIR, where to find SDL.h
6#
7# This module responds to the the flag:
8# SDL2_BUILDING_LIBRARY
9# If this is defined, then no SDL2_main will be linked in because
10# only applications need main().
11# Otherwise, it is assumed you are building an application and this
12# module will attempt to locate and set the the proper link flags
13# as part of the returned SDL2_LIBRARY variable.
14#
15# Don't forget to include SDL2main.h and SDL2main.m your project for the
16# OS X framework based version. (Other versions link to -lSDL2main which
17# this module will try to find on your behalf.) Also for OS X, this
18# module will automatically add the -framework Cocoa on your behalf.
19#
20#
21# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
22# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
23# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
24# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
25# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
26# as appropriate. These values are used to generate the final SDL2_LIBRARY
27# variable, but when these values are unset, SDL2_LIBRARY does not get created.
28#
29#
30# $SDL2 is an environment variable that would
31# correspond to the ./configure --prefix=$SDL2
32# used in building SDL2.
33# l.e.galup 9-20-02
34#
35# Modified by Eric Wing.
36# Added code to assist with automated building by using environmental variables
37# and providing a more controlled/consistent search behavior.
38# Added new modifications to recognize OS X frameworks and
39# additional Unix paths (FreeBSD, etc).
40# Also corrected the header search path to follow "proper" SDL2 guidelines.
41# Added a search for SDL2main which is needed by some platforms.
42# Added a search for threads which is needed by some platforms.
43# Added needed compile switches for MinGW.
44#
45# On OSX, this will prefer the Framework version (if found) over others.
46# People will have to manually change the cache values of
47# SDL2_LIBRARY to override this selection or set the CMake environment
48# CMAKE_INCLUDE_PATH to modify the search paths.
49#
50# Note that the header path has changed from SDL2/SDL.h to just SDL.h
51# This needed to change because "proper" SDL2 convention
52# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
53# reasons because not all systems place things in SDL2/ (see FreeBSD).
54#
55# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
56# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
57# was not created for redistribution, and exists temporarily pending official
58# SDL2 CMake modules.
59#
60# Note that on windows this will only search for the 32bit libraries, to search
61# for 64bit change x86/i686-w64 to x64/x86_64-w64
62
63#=============================================================================
64# Copyright 2003-2009 Kitware, Inc.
65#
66# CMake - Cross Platform Makefile Generator
67# Copyright 2000-2014 Kitware, Inc.
68# Copyright 2000-2011 Insight Software Consortium
69# All rights reserved.
70#
71# Redistribution and use in source and binary forms, with or without
72# modification, are permitted provided that the following conditions
73# are met:
74#
75# * Redistributions of source code must retain the above copyright
76# notice, this list of conditions and the following disclaimer.
77#
78# * Redistributions in binary form must reproduce the above copyright
79# notice, this list of conditions and the following disclaimer in the
80# documentation and/or other materials provided with the distribution.
81#
82# * Neither the names of Kitware, Inc., the Insight Software Consortium,
83# nor the names of their contributors may be used to endorse or promote
84# products derived from this software without specific prior written
85# permission.
86#
87# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
88# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
89# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
90# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
91# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
92# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
93# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
94# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
95# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
96# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
97# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
98#
99# This software is distributed WITHOUT ANY WARRANTY; without even the
100# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
101# See the License for more information.
102#=============================================================================
103# (To distribute this file outside of CMake, substitute the full
104# License text for the above reference.)
105
106FIND_PATH(SDL2_INCLUDE_DIR SDL.h
107 HINTS
108 ${SDL2}
109 $ENV{SDL2}
110 PATH_SUFFIXES include/SDL2 include SDL2
111 i686-w64-mingw32/include/SDL2
112 x86_64-w64-mingw32/include/SDL2
113 PATHS
114 ~/Library/Frameworks
115 /Library/Frameworks
116 /usr/local/include/SDL2
117 /usr/include/SDL2
118 /sw # Fink
119 /opt/local # DarwinPorts
120 /opt/csw # Blastwave
121 /opt
122)
123
124# Lookup the 64 bit libs on x64
125IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
126 FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2
127 HINTS
128 ${SDL2}
129 $ENV{SDL2}
130 PATH_SUFFIXES lib64 lib
131 lib/x64
132 x86_64-w64-mingw32/lib
133 PATHS
134 /sw
135 /opt/local
136 /opt/csw
137 /opt
138 )
139# On 32bit build find the 32bit libs
140ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
141 FIND_LIBRARY(SDL2_LIBRARY_TEMP SDL2
142 HINTS
143 ${SDL2}
144 $ENV{SDL2}
145 PATH_SUFFIXES lib
146 lib/x86
147 i686-w64-mingw32/lib
148 PATHS
149 /sw
150 /opt/local
151 /opt/csw
152 /opt
153 )
154ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
155
156IF(NOT SDL2_BUILDING_LIBRARY)
157 IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
158 # Non-OS X framework versions expect you to also dynamically link to
159 # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
160 # seem to provide SDL2main for compatibility even though they don't
161 # necessarily need it.
162 # Lookup the 64 bit libs on x64
163 IF(CMAKE_SIZEOF_VOID_P EQUAL 8)
164 FIND_LIBRARY(SDL2MAIN_LIBRARY
165 NAMES SDL2main
166 HINTS
167 ${SDL2}
168 $ENV{SDL2}
169 PATH_SUFFIXES lib64 lib
170 lib/x64
171 x86_64-w64-mingw32/lib
172 PATHS
173 /sw
174 /opt/local
175 /opt/csw
176 /opt
177 )
178 # On 32bit build find the 32bit libs
179 ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8)
180 FIND_LIBRARY(SDL2MAIN_LIBRARY
181 NAMES SDL2main
182 HINTS
183 ${SDL2}
184 $ENV{SDL2}
185 PATH_SUFFIXES lib
186 lib/x86
187 i686-w64-mingw32/lib
188 PATHS
189 /sw
190 /opt/local
191 /opt/csw
192 /opt
193 )
194 ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8)
195 ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
196ENDIF(NOT SDL2_BUILDING_LIBRARY)
197
198# SDL2 may require threads on your system.
199# The Apple build may not need an explicit flag because one of the
200# frameworks may already provide it.
201# But for non-OSX systems, I will use the CMake Threads package.
202IF(NOT APPLE)
203 FIND_PACKAGE(Threads)
204ENDIF(NOT APPLE)
205
206# MinGW needs an additional library, mwindows
207# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
208# (Actually on second look, I think it only needs one of the m* libraries.)
209IF(MINGW)
210 SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
211ENDIF(MINGW)
212
213SET(SDL2_FOUND "NO")
214 IF(SDL2_LIBRARY_TEMP)
215 # For SDL2main
216 IF(NOT SDL2_BUILDING_LIBRARY)
217 IF(SDL2MAIN_LIBRARY)
218 SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
219 ENDIF(SDL2MAIN_LIBRARY)
220 ENDIF(NOT SDL2_BUILDING_LIBRARY)
221
222 # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
223 # CMake doesn't display the -framework Cocoa string in the UI even
224 # though it actually is there if I modify a pre-used variable.
225 # I think it has something to do with the CACHE STRING.
226 # So I use a temporary variable until the end so I can set the
227 # "real" variable in one-shot.
228 IF(APPLE)
229 SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
230 ENDIF(APPLE)
231
232 # For threads, as mentioned Apple doesn't need this.
233 # In fact, there seems to be a problem if I used the Threads package
234 # and try using this line, so I'm just skipping it entirely for OS X.
235 IF(NOT APPLE)
236 SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
237 ENDIF(NOT APPLE)
238
239 # For MinGW library
240 IF(MINGW)
241 SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
242 ENDIF(MINGW)
243
244 # Set the final string here so the GUI reflects the final state.
245 SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
246 # Set the temp variable to INTERNAL so it is not seen in the CMake GUI
247 SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
248
249 SET(SDL2_FOUND "YES")
250ENDIF(SDL2_LIBRARY_TEMP)
251
252INCLUDE(FindPackageHandleStandardArgs)
253
254FIND_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 @@
1#include <SDL.h>
2#include <stdexcept>
3#include <memory>
4#include <vector>
5#include <random>
6#include <fov.h>
7#include <deque>
8
9class sdl_error : public std::logic_error {
10public:
11
12 sdl_error() : std::logic_error(SDL_GetError())
13 {
14 }
15};
16
17class window_deleter {
18public:
19
20 void operator()(SDL_Window* ptr)
21 {
22 SDL_DestroyWindow(ptr);
23 }
24};
25
26using window_ptr = std::unique_ptr<SDL_Window, window_deleter>;
27
28class renderer_deleter {
29public:
30
31 void operator()(SDL_Renderer* ptr)
32 {
33 SDL_DestroyRenderer(ptr);
34 }
35};
36
37using renderer_ptr = std::unique_ptr<SDL_Renderer, renderer_deleter>;
38
39enum class Tile {
40 Floor,
41 Wall,
42 Dark,
43 Dust,
44 Lamp
45};
46
47const int GAME_WIDTH = 640;
48const int GAME_HEIGHT = 480;
49const int TILE_WIDTH = 8;
50const int TILE_HEIGHT = 8;
51const int VIEW_WIDTH = GAME_WIDTH / TILE_WIDTH;
52const int VIEW_HEIGHT = GAME_HEIGHT / TILE_HEIGHT;
53
54class Map {
55public:
56
57 Map() :
58 tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor),
59 lighting(VIEW_WIDTH*VIEW_HEIGHT, false)
60 {
61 }
62
63 std::vector<Tile> tiles;
64 std::vector<bool> lighting;
65 std::deque<std::tuple<int, int>> playerLocs;
66};
67
68int player_x = VIEW_WIDTH / 2;
69int player_y = VIEW_HEIGHT / 2;
70
71void render(
72 SDL_Renderer* ren,
73 const Map& map,
74 bool drawDark = true)
75{
76 SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255);
77 SDL_RenderClear(ren);
78
79 for (int y = 0; y < VIEW_HEIGHT; y++)
80 {
81 for (int x = 0; x < VIEW_WIDTH; x++)
82 {
83 bool draw = true;
84
85 if (player_x == x && player_y == y)
86 {
87 SDL_SetRenderDrawColor(ren, 255, 255, 0, 255);
88 } else if (!map.lighting.at(x+VIEW_WIDTH*y))
89 {
90 if (drawDark)
91 {
92 SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
93 } else {
94 draw = false;
95 }
96 } else {
97 switch (map.tiles.at(x+y*VIEW_WIDTH))
98 {
99 case Tile::Floor:
100 {
101 SDL_SetRenderDrawColor(ren, 210, 210, 210, 255);
102 break;
103 }
104
105 case Tile::Wall:
106 case Tile::Dark:
107 {
108 SDL_SetRenderDrawColor(ren, 100, 100, 100, 255);
109 break;
110 }
111
112 case Tile::Dust:
113 {
114 SDL_SetRenderDrawColor(ren, 128, 40, 255, 255);
115 break;
116 }
117
118 case Tile::Lamp:
119 {
120 SDL_SetRenderDrawColor(ren, 0, 255, 255, 255);
121 break;
122 }
123 }
124 }
125
126
127 if (draw)
128 {
129 SDL_Rect rect{x*TILE_WIDTH, y*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
130 SDL_RenderFillRect(ren, &rect);
131 }
132
133
134 }
135 }
136
137 SDL_RenderPresent(ren);
138}
139
140void incrementIfSet(Map& map, int& count, int x, int y, int w, int h, Tile val = Tile::Dark)
141{
142 if ((x >= 0) && (x < w) && (y >= 0) && (y < h) && (map.tiles[x+w*y] == val))
143 {
144 count++;
145 }
146}
147
148void tick(Map& map, int x1 = 0, int y1 = 0, int x2 = VIEW_WIDTH, int y2 = VIEW_HEIGHT)
149{
150 std::vector<Tile> temp(map.tiles);
151
152 for (int y = std::max(y1, 0); y < std::min(y2, VIEW_HEIGHT); y++)
153 {
154 for (int x = std::max(x1, 0); x < std::min(x2, VIEW_WIDTH); x++)
155 {
156 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp)
157 {
158 continue;
159 }
160
161 int count = 0;
162
163 incrementIfSet(map, count, x-1, y-1, VIEW_WIDTH, VIEW_HEIGHT);
164 incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT);
165 incrementIfSet(map, count, x-1, y+1, VIEW_WIDTH, VIEW_HEIGHT);
166 incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT);
167 incrementIfSet(map, count, x , y , VIEW_WIDTH, VIEW_HEIGHT);
168 incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT);
169 incrementIfSet(map, count, x+1, y-1, VIEW_WIDTH, VIEW_HEIGHT);
170 incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT);
171 incrementIfSet(map, count, x+1, y+1, VIEW_WIDTH, VIEW_HEIGHT);
172
173 if (count >= 5)
174 {
175 temp[x+VIEW_WIDTH*y] = Tile::Dark;
176 } else {
177 temp[x+VIEW_WIDTH*y] = Tile::Floor;
178 }
179 }
180 }
181
182 map.tiles = temp;
183}
184
185void movePlayer(int x, int y, Map& map)
186{
187 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT) &&
188 map.tiles[x+VIEW_WIDTH*y] == Tile::Floor)
189 {
190 if (map.tiles[player_x+player_y*VIEW_WIDTH] == Tile::Floor)
191 {
192 map.tiles[player_x+player_y*VIEW_WIDTH] = Tile::Dust;
193 map.playerLocs.emplace_front(player_x, player_y);
194
195 if (map.playerLocs.size() > 5)
196 {
197 map.playerLocs.pop_back();
198 }
199 }
200
201
202
203
204 player_x = x;
205 player_y = y;
206 }
207}
208
209void setIfValid(Map& map, int x, int y, Tile val)
210{
211 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT))
212 {
213 map.tiles[x+VIEW_WIDTH*y] = val;
214 }
215}
216
217void recalculateLighting(Map& map, fov_settings_type* fov)
218{
219 map.lighting = std::vector<bool>(VIEW_WIDTH*VIEW_HEIGHT, false);
220
221 fov_settings_set_opacity_test_function(
222 fov,
223 [] (void* map, int x, int y) {
224 return
225 x >= 0 &&
226 x < VIEW_WIDTH &&
227 y >= 0 &&
228 y < VIEW_HEIGHT &&
229 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark;
230 });
231
232 fov_settings_set_apply_lighting_function(
233 fov,
234 [] (void* map, int x, int y, int, int, void*) {
235 if ((x >= 0) && (x < VIEW_WIDTH) && (y >= 0) && (y < VIEW_HEIGHT))
236 {
237 static_cast<Map*>(map)->lighting[x+VIEW_WIDTH*y] = true;
238 }
239 });
240
241 for (int y = 0; y < VIEW_HEIGHT; y++)
242 {
243 for (int x = 0; x < VIEW_WIDTH; x++)
244 {
245 if ((player_x == x && player_y == y) || map.tiles[x+VIEW_WIDTH*y] == Tile::Dust || map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp)
246 {
247 fov_circle(fov, static_cast<void*>(&map), nullptr, x, y, 8);
248 }
249
250 if (map.tiles[x+VIEW_WIDTH*y] == Tile::Lamp)
251 {
252 map.lighting[x+VIEW_WIDTH*y] = true;
253 }
254 }
255 }
256}
257
258int main(int, char**)
259{
260 std::random_device randomEngine;
261 std::mt19937 rng(randomEngine());
262
263 if (SDL_Init(SDL_INIT_VIDEO) != 0)
264 {
265 throw sdl_error();
266 }
267
268 try
269 {
270 window_ptr win(
271 SDL_CreateWindow("Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN));
272
273 if (!win)
274 {
275 throw sdl_error();
276 }
277
278 renderer_ptr ren(
279 SDL_CreateRenderer(
280 win.get(),
281 -1,
282 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
283
284 if (!ren)
285 {
286 throw sdl_error();
287 }
288
289 //std::vector<Tile> tiles(VIEW_WIDTH*VIEW_HEIGHT, Tile::Floor);
290 //std::vector<bool> lighting(VIEW_WIDTH*VIEW_HEIGHT, false);
291 Map map;
292
293 std::unique_ptr<fov_settings_type> fov(new fov_settings_type());
294 fov_settings_init(fov.get());
295
296
297 for (int y = 0; y < VIEW_HEIGHT; y++)
298 {
299 for (int x = 0; x < VIEW_WIDTH; x++)
300 {
301 if (std::bernoulli_distribution(0.5)(rng))
302 {
303 map.tiles[x+y*VIEW_WIDTH] = Tile::Dark;
304 }
305 }
306 }
307
308 tick(map);
309 tick(map);
310 tick(map);
311
312 bool quit = false;
313 SDL_Event e;
314 while (!quit)
315 {
316 //SDL_PumpEvents();
317 bool input = false;
318 int presses = 0;
319 while (SDL_PollEvent(&e))
320 {
321 if (e.type == SDL_QUIT)
322 {
323 quit = true;
324 } else if (e.type == SDL_KEYDOWN)
325 {
326 presses++;
327
328 switch (e.key.keysym.sym)
329 {
330 case SDLK_SPACE:
331 {
332 input = true;
333
334 setIfValid(map, player_x-1, player_y , Tile::Floor);
335 setIfValid(map, player_x+1, player_y , Tile::Floor);
336 setIfValid(map, player_x , player_y , Tile::Lamp);
337 setIfValid(map, player_x , player_y-1, Tile::Floor);
338 setIfValid(map, player_x , player_y+1, Tile::Floor);
339
340 auto locs = map.playerLocs;
341 while (!locs.empty())
342 {
343 movePlayer(std::get<0>(locs.front()), std::get<1>(locs.front()), map);
344 locs.pop_front();
345
346 tick(
347 map,
348 player_x - 7,
349 player_y - 7,
350 player_x + 8,
351 player_y + 8);
352
353 render(ren.get(), map, false);
354 SDL_Delay(30);
355 }
356
357 break;
358 }
359 }
360 } else if (e.type == SDL_KEYUP)
361 {
362 presses++;
363 }
364 }
365
366 if (presses > 0)
367 {
368 for (int y = 0; y < VIEW_HEIGHT; y++)
369 {
370 for (int x = 0; x < VIEW_WIDTH; x++)
371 {
372 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Dust)
373 {
374 map.tiles[x+y*VIEW_WIDTH] = Tile::Floor;
375 }
376 }
377 }
378 }
379
380 const Uint8* state = SDL_GetKeyboardState(NULL);
381
382 for (int i = 0; i < presses; i++)
383 {
384 //switch (e.key.keysym.sym)
385 {
386 //case SDLK_UP:
387 if (state[SDL_SCANCODE_UP])
388 {
389 movePlayer(player_x, player_y-1, map);
390 input = true;
391 //break;
392 }
393
394 //case SDLK_DOWN:
395 if (state[SDL_SCANCODE_DOWN])
396 {
397 movePlayer(player_x, player_y+1, map);
398 input = true;
399 //break;
400 }
401
402 //case SDLK_LEFT:
403 if (state[SDL_SCANCODE_LEFT])
404 {
405 movePlayer(player_x-1, player_y, map);
406 input = true;
407 //break;
408 }
409
410 //case SDLK_RIGHT:
411 if (state[SDL_SCANCODE_RIGHT])
412 {
413 movePlayer(player_x+1, player_y, map);
414 input = true;
415 //break;
416 }
417
418
419 }
420
421 if (input)
422 {
423 //render(ren.get(), tiles, false);
424 //SDL_Delay(1);
425 }
426
427 //}
428 }
429
430 bool checkForDust = true;
431
432 while (checkForDust)
433 {
434 checkForDust = false;
435
436 for (int y = 0; y < VIEW_HEIGHT; y++)
437 {
438 for (int x = 0; x < VIEW_WIDTH; x++)
439 {
440 if (map.tiles[x+y*VIEW_WIDTH] == Tile::Lamp)
441 {
442 int count = 0;
443
444 incrementIfSet(map, count, x-1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
445 incrementIfSet(map, count, x+1, y , VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
446 incrementIfSet(map, count, x , y-1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
447 incrementIfSet(map, count, x , y+1, VIEW_WIDTH, VIEW_HEIGHT, Tile::Dust);
448
449 if (count > 0)
450 {
451 checkForDust = true;
452
453 map.tiles[x+y*VIEW_WIDTH] = Tile::Dust;
454
455 /*for (int i = 0; i < 4; i++)
456 {
457 tick(
458 map,
459 x - 7,
460 y - 7,
461 x + 8,
462 y + 8);
463
464 for (int l = 0; l < (i*2+1); l++)
465 {
466 int px = x - i + l;
467 int py = y - i + l;
468
469 auto fillInDust = [&] (int sx, int sy) {
470 if (sx > 0 && sx < VIEW_WIDTH &&
471 sy > 0 && sy < VIEW_HEIGHT &&
472 map.tiles[sx+sy*VIEW_WIDTH] == Tile::Floor &&
473 !(player_y == sy && player_x == sx))
474 {
475 map.tiles[sx+sy*VIEW_WIDTH] = Tile::Dust;
476 }
477 };
478
479 fillInDust(px , y - i);
480 fillInDust(px , y + i);
481 fillInDust(x - i, py );
482 fillInDust(x + i, py );
483 }
484
485 render(ren.get(), map, false);
486 SDL_Delay(30);
487 }*/
488
489
490 /*
491
492 for (int py = std::max(0, y - 7); py < std::min(VIEW_HEIGHT, y + 8); py++)
493 {
494 for (int px = std::max(0, x - 7); px < std::min(VIEW_WIDTH, x + 8); px++)
495 {
496 if ((map.tiles[px+py*VIEW_WIDTH] == Tile::Floor) &&
497 !(player_y == py && player_x == px))
498 {
499 map.tiles[px+py*VIEW_WIDTH] = Tile::Dust;
500 }
501 }
502 }*/
503
504 std::unique_ptr<fov_settings_type> dusty(new fov_settings_type);
505 fov_settings_set_opacity_test_function(
506 dusty.get(),
507 [] (void* map, int x, int y) {
508 return
509 x >= 0 &&
510 x < VIEW_WIDTH &&
511 y >= 0 &&
512 y < VIEW_HEIGHT &&
513 static_cast<Map*>(map)->tiles.at(x+VIEW_WIDTH*y) == Tile::Dark;
514 });
515
516 fov_settings_set_apply_lighting_function(
517 dusty.get(),
518 [] (void* map, int x, int y, int, int, void*) {
519 if ((x >= 0) && (x < VIEW_WIDTH) &&
520 (y >= 0) && (y < VIEW_HEIGHT) &&
521 (static_cast<Map*>(map)->tiles[x+VIEW_WIDTH*y] == Tile::Floor))
522 {
523 static_cast<Map*>(map)->tiles[x+VIEW_WIDTH*y] = Tile::Dust;
524 }
525 });
526
527 fov_circle(dusty.get(), static_cast<void*>(&map), nullptr, x, y, 8);
528
529 render(ren.get(), map, false);
530 SDL_Delay(50);
531 }
532 }
533 }
534 }
535 }
536
537
538 recalculateLighting(map, fov.get());
539 render(ren.get(), map, true);
540 SDL_Delay(10);
541 }
542 } catch (const sdl_error&)
543 {
544 }
545
546 SDL_Quit();
547
548 return 0;
549} \ No newline at end of file
diff --git a/src/untitled.txt b/src/untitled.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/untitled.txt
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 @@
1/*
2 * Copyright (C) 2006, Greg McIntyre
3 * All rights reserved. See the file named COPYING in the distribution
4 * for more details.
5 */
6
7#include <stdlib.h>
8#include <string.h>
9#include <stdio.h>
10#define __USE_ISOC99 1
11#include <math.h>
12#include <float.h>
13#include <assert.h>
14#include "fov.h"
15
16/*
17+---++---++---++---+
18| || || || |
19| || || || |
20| || || || |
21+---++---++---++---+ 2
22+---++---++---+#####
23| || || |#####
24| || || |#####
25| || || |#####
26+---++---++---+#####X 1 <-- y
27+---++---++---++---+
28| || || || |
29| @ || || || | <-- srcy centre -> dy = 0.5 = y - 0.5
30| || || || |
31+---++---++---++---+ 0
320 1 2 3 4
33 ^ ^
34 | |
35 srcx x -> dx = 3.5 = x + 0.5
36centre
37
38Slope from @ to X.
39
40+---++---++---++---+
41| || || || |
42| || || || |
43| || || || |
44+---++---++---++---+ 2
45+---++---++---++---+
46| || || || |
47| || || || |
48| || || || |
49+---++---++---+X---+ 1 <-- y
50+---++---++---+#####
51| || || |#####
52| @ || || |##### <-- srcy centre -> dy = 0.5 = y - 0.5
53| || || |#####
54+---++---++---+##### 0
550 1 2 3
56 ^ ^
57 | |
58 srcx x -> dx = 2.5 = x - 0.5
59centre
60
61Slope from @ to X
62*/
63
64
65/* Types ---------------------------------------------------------- */
66
67/** \cond INTERNAL */
68typedef struct {
69 /*@observer@*/ fov_settings_type *settings;
70 /*@observer@*/ void *map;
71 /*@observer@*/ void *source;
72 int source_x;
73 int source_y;
74 unsigned radius;
75} fov_private_data_type;
76/** \endcond */
77
78/* Options -------------------------------------------------------- */
79
80void fov_settings_init(fov_settings_type *settings) {
81 settings->shape = FOV_SHAPE_CIRCLE_PRECALCULATE;
82 settings->corner_peek = FOV_CORNER_NOPEEK;
83 settings->opaque_apply = FOV_OPAQUE_APPLY;
84 settings->opaque = NULL;
85 settings->apply = NULL;
86 settings->heights = NULL;
87 settings->numheights = 0;
88}
89
90void fov_settings_set_shape(fov_settings_type *settings,
91 fov_shape_type value) {
92 settings->shape = value;
93}
94
95void fov_settings_set_corner_peek(fov_settings_type *settings,
96 fov_corner_peek_type value) {
97 settings->corner_peek = value;
98}
99
100void fov_settings_set_opaque_apply(fov_settings_type *settings,
101 fov_opaque_apply_type value) {
102 settings->opaque_apply = value;
103}
104
105void fov_settings_set_opacity_test_function(fov_settings_type *settings,
106 bool (*f)(void *map,
107 int x, int y)) {
108 settings->opaque = f;
109}
110
111void fov_settings_set_apply_lighting_function(fov_settings_type *settings,
112 void (*f)(void *map,
113 int x, int y,
114 int dx, int dy,
115 void *src)) {
116 settings->apply = f;
117}
118
119/* Circular FOV --------------------------------------------------- */
120
121/*@null@*/ static unsigned *precalculate_heights(unsigned maxdist) {
122 unsigned i;
123 unsigned *result = (unsigned *)malloc((maxdist+2)*sizeof(unsigned));
124 if (result) {
125 for (i = 0; i <= maxdist; ++i) {
126 result[i] = (unsigned)sqrtf((float)(maxdist*maxdist - i*i));
127 }
128 result[maxdist+1] = 0;
129 }
130 return result;
131}
132
133static unsigned height(fov_settings_type *settings, int x,
134 unsigned maxdist) {
135 unsigned **newheights;
136
137 if (maxdist > settings->numheights) {
138 newheights = (unsigned **)calloc((size_t)maxdist, sizeof(unsigned*));
139 if (newheights != NULL) {
140 if (settings->heights != NULL && settings->numheights > 0) {
141 /* Copy the pointers to the heights arrays we've already
142 * calculated. Once copied out, we can free the old
143 * array of pointers. */
144 memcpy(newheights, settings->heights,
145 settings->numheights*sizeof(unsigned*));
146 free(settings->heights);
147 }
148 settings->heights = newheights;
149 settings->numheights = maxdist;
150 }
151 }
152 if (settings->heights) {
153 if (settings->heights[maxdist-1] == NULL) {
154 settings->heights[maxdist-1] = precalculate_heights(maxdist);
155 }
156 if (settings->heights[maxdist-1] != NULL) {
157 return settings->heights[maxdist-1][abs(x)];
158 }
159 }
160 return 0;
161}
162
163void fov_settings_free(fov_settings_type *settings) {
164 unsigned i;
165 if (settings != NULL) {
166 if (settings->heights != NULL && settings->numheights > 0) {
167 /*@+forloopexec@*/
168 for (i = 0; i < settings->numheights; ++i) {
169 unsigned *h = settings->heights[i];
170 if (h != NULL) {
171 free(h);
172 }
173 settings->heights[i] = NULL;
174 }
175 /*@=forloopexec@*/
176 free(settings->heights);
177 settings->heights = NULL;
178 settings->numheights = 0;
179 }
180 }
181}
182
183/* Slope ---------------------------------------------------------- */
184
185static float fov_slope(float dx, float dy) {
186 if (dx <= -FLT_EPSILON || dx >= FLT_EPSILON) {
187 return dy/dx;
188 } else {
189 return 0.0;
190 }
191}
192
193/* Octants -------------------------------------------------------- */
194
195#define FOV_DEFINE_OCTANT(signx, signy, rx, ry, nx, ny, nf, apply_edge, apply_diag) \
196 static void fov_octant_##nx##ny##nf( \
197 fov_private_data_type *data, \
198 int dx, \
199 float start_slope, \
200 float end_slope) { \
201 int x, y, dy, dy0, dy1; \
202 unsigned h; \
203 int prev_blocked = -1; \
204 float end_slope_next; \
205 fov_settings_type *settings = data->settings; \
206 \
207 if (dx == 0) { \
208 fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope); \
209 return; \
210 } else if ((unsigned)dx > data->radius) { \
211 return; \
212 } \
213 \
214 dy0 = (int)(0.5f + ((float)dx)*start_slope); \
215 dy1 = (int)(0.5f + ((float)dx)*end_slope); \
216 \
217 rx = data->source_##rx signx dx; \
218 ry = data->source_##ry signy dy0; \
219 \
220 if (!apply_diag && dy1 == dx) { \
221 /* We do diagonal lines on every second octant, so they don't get done twice. */ \
222 --dy1; \
223 } \
224 \
225 switch (settings->shape) { \
226 case FOV_SHAPE_CIRCLE_PRECALCULATE: \
227 h = height(settings, dx, data->radius); \
228 break; \
229 case FOV_SHAPE_CIRCLE: \
230 h = (unsigned)sqrtf((float)(data->radius*data->radius - dx*dx)); \
231 break; \
232 case FOV_SHAPE_OCTAGON: \
233 h = (data->radius - dx)<<1; \
234 break; \
235 default: \
236 h = data->radius; \
237 break; \
238 }; \
239 if ((unsigned)dy1 > h) { \
240 if (h == 0) { \
241 return; \
242 } \
243 dy1 = (int)h; \
244 } \
245 \
246 /*fprintf(stderr, "(%2d) = [%2d .. %2d] (%f .. %f), h=%d,edge=%d\n", \
247 dx, dy0, dy1, ((float)dx)*start_slope, \
248 0.5f + ((float)dx)*end_slope, h, apply_edge);*/ \
249 \
250 for (dy = dy0; dy <= dy1; ++dy) { \
251 ry = data->source_##ry signy dy; \
252 \
253 if (settings->opaque(data->map, x, y)) { \
254 if (settings->opaque_apply == FOV_OPAQUE_APPLY && (apply_edge || dy > 0)) { \
255 settings->apply(data->map, x, y, x - data->source_x, y - data->source_y, data->source); \
256 } \
257 if (prev_blocked == 0) { \
258 end_slope_next = fov_slope((float)dx + 0.5f, (float)dy - 0.5f); \
259 fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope_next); \
260 } \
261 prev_blocked = 1; \
262 } else { \
263 if (apply_edge || dy > 0) { \
264 settings->apply(data->map, x, y, x - data->source_x, y - data->source_y, data->source); \
265 } \
266 if (prev_blocked == 1) { \
267 start_slope = fov_slope((float)dx - 0.5f, (float)dy - 0.5f); \
268 } \
269 prev_blocked = 0; \
270 } \
271 } \
272 \
273 if (prev_blocked == 0) { \
274 fov_octant_##nx##ny##nf(data, dx+1, start_slope, end_slope); \
275 } \
276 }
277
278FOV_DEFINE_OCTANT(+,+,x,y,p,p,n,true,true)
279FOV_DEFINE_OCTANT(+,+,y,x,p,p,y,true,false)
280FOV_DEFINE_OCTANT(+,-,x,y,p,m,n,false,true)
281FOV_DEFINE_OCTANT(+,-,y,x,p,m,y,false,false)
282FOV_DEFINE_OCTANT(-,+,x,y,m,p,n,true,true)
283FOV_DEFINE_OCTANT(-,+,y,x,m,p,y,true,false)
284FOV_DEFINE_OCTANT(-,-,x,y,m,m,n,false,true)
285FOV_DEFINE_OCTANT(-,-,y,x,m,m,y,false,false)
286
287
288/* Circle --------------------------------------------------------- */
289
290static void _fov_circle(fov_private_data_type *data) {
291 /*
292 * Octants are defined by (x,y,r) where:
293 * x = [p]ositive or [n]egative x increment
294 * y = [p]ositive or [n]egative y increment
295 * r = [y]es or [n]o for reflecting on axis x = y
296 *
297 * \pmy|ppy/
298 * \ | /
299 * \ | /
300 * mpn\|/ppn
301 * ----@----
302 * mmn/|\pmn
303 * / | \
304 * / | \
305 * /mmy|mpy\
306 */
307 fov_octant_ppn(data, 1, (float)0.0f, (float)1.0f);
308 fov_octant_ppy(data, 1, (float)0.0f, (float)1.0f);
309 fov_octant_pmn(data, 1, (float)0.0f, (float)1.0f);
310 fov_octant_pmy(data, 1, (float)0.0f, (float)1.0f);
311 fov_octant_mpn(data, 1, (float)0.0f, (float)1.0f);
312 fov_octant_mpy(data, 1, (float)0.0f, (float)1.0f);
313 fov_octant_mmn(data, 1, (float)0.0f, (float)1.0f);
314 fov_octant_mmy(data, 1, (float)0.0f, (float)1.0f);
315}
316
317void fov_circle(fov_settings_type *settings,
318 void *map,
319 void *source,
320 int source_x,
321 int source_y,
322 unsigned radius) {
323 fov_private_data_type data;
324
325 data.settings = settings;
326 data.map = map;
327 data.source = source;
328 data.source_x = source_x;
329 data.source_y = source_y;
330 data.radius = radius;
331
332 _fov_circle(&data);
333}
334
335/**
336 * Limit x to the range [a, b].
337 */
338static float betweenf(float x, float a, float b) {
339 if (x - a < FLT_EPSILON) { /* x < a */
340 return a;
341 } else if (x - b > FLT_EPSILON) { /* x > b */
342 return b;
343 } else {
344 return x;
345 }
346}
347
348#define BEAM_DIRECTION(d, p1, p2, p3, p4, p5, p6, p7, p8) \
349 if (direction == d) { \
350 end_slope = betweenf(a, 0.0f, 1.0f); \
351 fov_octant_##p1(&data, 1, 0.0f, end_slope); \
352 fov_octant_##p2(&data, 1, 0.0f, end_slope); \
353 if (a - 1.0f > FLT_EPSILON) { /* a > 1.0f */ \
354 start_slope = betweenf(2.0f - a, 0.0f, 1.0f); \
355 fov_octant_##p3(&data, 1, start_slope, 1.0f); \
356 fov_octant_##p4(&data, 1, start_slope, 1.0f); \
357 } \
358 if (a - 2.0f > FLT_EPSILON) { /* a > 2.0f */ \
359 end_slope = betweenf(a - 2.0f, 0.0f, 1.0f); \
360 fov_octant_##p5(&data, 1, 0.0f, end_slope); \
361 fov_octant_##p6(&data, 1, 0.0f, end_slope); \
362 } \
363 if (a - 3.0f > FLT_EPSILON) { /* a > 3.0f */ \
364 start_slope = betweenf(4.0f - a, 0.0f, 1.0f); \
365 fov_octant_##p7(&data, 1, start_slope, 1.0f); \
366 fov_octant_##p8(&data, 1, start_slope, 1.0f); \
367 } \
368 }
369
370#define BEAM_DIRECTION_DIAG(d, p1, p2, p3, p4, p5, p6, p7, p8) \
371 if (direction == d) { \
372 start_slope = betweenf(1.0f - a, 0.0f, 1.0f); \
373 fov_octant_##p1(&data, 1, start_slope, 1.0f); \
374 fov_octant_##p2(&data, 1, start_slope, 1.0f); \
375 if (a - 1.0f > FLT_EPSILON) { /* a > 1.0f */ \
376 end_slope = betweenf(a - 1.0f, 0.0f, 1.0f); \
377 fov_octant_##p3(&data, 1, 0.0f, end_slope); \
378 fov_octant_##p4(&data, 1, 0.0f, end_slope); \
379 } \
380 if (a - 2.0f > FLT_EPSILON) { /* a > 2.0f */ \
381 start_slope = betweenf(3.0f - a, 0.0f, 1.0f); \
382 fov_octant_##p5(&data, 1, start_slope, 1.0f); \
383 fov_octant_##p6(&data, 1, start_slope, 1.0f); \
384 } \
385 if (a - 3.0f > FLT_EPSILON) { /* a > 3.0f */ \
386 end_slope = betweenf(a - 3.0f, 0.0f, 1.0f); \
387 fov_octant_##p7(&data, 1, 0.0f, end_slope); \
388 fov_octant_##p8(&data, 1, 0.0f, end_slope); \
389 } \
390 }
391
392void fov_beam(fov_settings_type *settings, void *map, void *source,
393 int source_x, int source_y, unsigned radius,
394 fov_direction_type direction, float angle) {
395
396 fov_private_data_type data;
397 float start_slope, end_slope, a;
398
399 data.settings = settings;
400 data.map = map;
401 data.source = source;
402 data.source_x = source_x;
403 data.source_y = source_y;
404 data.radius = radius;
405
406 if (angle <= 0.0f) {
407 return;
408 } else if (angle >= 360.0f) {
409 _fov_circle(&data);
410 return;
411 }
412
413 /* Calculate the angle as a percentage of 45 degrees, halved (for
414 * each side of the centre of the beam). e.g. angle = 180.0f means
415 * half the beam is 90.0 which is 2x45, so the result is 2.0.
416 */
417 a = angle/90.0f;
418
419 BEAM_DIRECTION(FOV_EAST, ppn, pmn, ppy, mpy, pmy, mmy, mpn, mmn);
420 BEAM_DIRECTION(FOV_WEST, mpn, mmn, pmy, mmy, ppy, mpy, ppn, pmn);
421 BEAM_DIRECTION(FOV_NORTH, mpy, mmy, mmn, pmn, mpn, ppn, pmy, ppy);
422 BEAM_DIRECTION(FOV_SOUTH, pmy, ppy, mpn, ppn, mmn, pmn, mmy, mpy);
423 BEAM_DIRECTION_DIAG(FOV_NORTHEAST, pmn, mpy, mmy, ppn, mmn, ppy, mpn, pmy);
424 BEAM_DIRECTION_DIAG(FOV_NORTHWEST, mmn, mmy, mpn, mpy, pmy, pmn, ppy, ppn);
425 BEAM_DIRECTION_DIAG(FOV_SOUTHEAST, ppn, ppy, pmy, pmn, mpn, mpy, mmn, mmy);
426 BEAM_DIRECTION_DIAG(FOV_SOUTHWEST, pmy, mpn, ppy, mmn, ppn, mmy, pmn, mpy);
427}
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 @@
1/*
2 * Copyright (C) 2006-2007, Greg McIntyre. All rights reserved. See the file
3 * named COPYING in the distribution for more details.
4 */
5
6/**
7 * \mainpage Field of View Library
8 *
9 * \section about About
10 *
11 * This is a C library which implements a course-grained lighting
12 * algorithm suitable for tile-based games such as roguelikes.
13 *
14 * \section copyright Copyright
15 *
16 * \verbinclude COPYING
17 *
18 * \section thanks Thanks
19 *
20 * Thanks to Bj&ouml;rn Bergstr&ouml;m
21 * <bjorn.bergstrom@hyperisland.se> for the algorithm.
22 *
23 */
24
25/**
26 * \file fov.h
27 * Field-of-view algorithm for dynamically casting light/shadow on a
28 * low resolution 2D raster.
29 */
30#ifndef LIBFOV_HEADER
31#define LIBFOV_HEADER
32
33#include <stdbool.h>
34#include <stddef.h>
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40/** Eight-way directions. */
41typedef enum {
42 FOV_EAST = 0,
43 FOV_NORTHEAST,
44 FOV_NORTH,
45 FOV_NORTHWEST,
46 FOV_WEST,
47 FOV_SOUTHWEST,
48 FOV_SOUTH,
49 FOV_SOUTHEAST
50} fov_direction_type;
51
52/** Values for the shape setting. */
53typedef enum {
54 FOV_SHAPE_CIRCLE_PRECALCULATE,
55 FOV_SHAPE_SQUARE,
56 FOV_SHAPE_CIRCLE,
57 FOV_SHAPE_OCTAGON
58} fov_shape_type;
59
60/** Values for the corner peek setting. */
61typedef enum {
62 FOV_CORNER_NOPEEK,
63 FOV_CORNER_PEEK
64} fov_corner_peek_type;
65
66/** Values for the opaque apply setting. */
67typedef enum {
68 FOV_OPAQUE_APPLY,
69 FOV_OPAQUE_NOAPPLY
70} fov_opaque_apply_type;
71
72/** @cond INTERNAL */
73typedef /*@null@*/ unsigned *height_array_t;
74/** @endcond */
75
76typedef struct {
77 /** Opacity test callback. */
78 /*@null@*/ bool (*opaque)(void *map, int x, int y);
79
80 /** Lighting callback to set lighting on a map tile. */
81 /*@null@*/ void (*apply)(void *map, int x, int y, int dx, int dy, void *src);
82
83 /** Shape setting. */
84 fov_shape_type shape;
85
86 /** Whether to peek around corners. */
87 fov_corner_peek_type corner_peek;
88
89 /** Whether to call apply on opaque tiles. */
90 fov_opaque_apply_type opaque_apply;
91
92 /** \cond INTERNAL */
93
94 /** Pre-calculated data. \internal */
95 /*@null@*/ height_array_t *heights;
96
97 /** Size of pre-calculated data. \internal */
98 unsigned numheights;
99
100 /** \endcond */
101} fov_settings_type;
102
103/** The opposite direction to that given. */
104#define fov_direction_opposite(direction) ((fov_direction_type)(((direction)+4)&0x7))
105
106/**
107 * Set all the default options. You must call this option when you
108 * create a new settings data structure.
109 *
110 * These settings are the defaults used:
111 *
112 * - shape: FOV_SHAPE_CIRCLE_PRECALCULATE
113 * - corner_peek: FOV_CORNER_NOPEEK
114 * - opaque_apply: FOV_OPAQUE_APPLY
115 *
116 * Callbacks still need to be set up after calling this function.
117 *
118 * \param settings Pointer to data structure containing settings.
119 */
120void fov_settings_init(fov_settings_type *settings);
121
122/**
123 * Set the shape of the field of view.
124 *
125 * \param settings Pointer to data structure containing settings.
126 * \param value One of the following values, where R is the radius:
127 *
128 * - FOV_SHAPE_CIRCLE_PRECALCULATE \b (default): Limit the FOV to a
129 * circle with radius R by precalculating, which consumes more memory
130 * at the rate of 4*(R+2) bytes per R used in calls to fov_circle.
131 * Each radius is only calculated once so that it can be used again.
132 * Use fov_free() to free this precalculated data's memory.
133 *
134 * - FOV_SHAPE_CIRCLE: Limit the FOV to a circle with radius R by
135 * calculating on-the-fly.
136 *
137 * - FOV_SHAPE_OCTOGON: Limit the FOV to an octogon with maximum radius R.
138 *
139 * - FOV_SHAPE_SQUARE: Limit the FOV to an R*R square.
140 */
141void fov_settings_set_shape(fov_settings_type *settings, fov_shape_type value);
142
143/**
144 * <em>NOT YET IMPLEMENTED</em>.
145 *
146 * Set whether sources will peek around corners.
147 *
148 * \param settings Pointer to data structure containing settings.
149 * \param value One of the following values:
150 *
151 * - FOV_CORNER_PEEK \b (default): Renders:
152\verbatim
153 ........
154 ........
155 ........
156 ..@#
157 ...#
158\endverbatim
159 * - FOV_CORNER_NOPEEK: Renders:
160\verbatim
161 ......
162 .....
163 ....
164 ..@#
165 ...#
166\endverbatim
167 */
168void fov_settings_set_corner_peek(fov_settings_type *settings, fov_corner_peek_type value);
169
170/**
171 * Whether to call the apply callback on opaque tiles.
172 *
173 * \param settings Pointer to data structure containing settings.
174 * \param value One of the following values:
175 *
176 * - FOV_OPAQUE_APPLY \b (default): Call apply callback on opaque tiles.
177 * - FOV_OPAQUE_NOAPPLY: Do not call the apply callback on opaque tiles.
178 */
179void fov_settings_set_opaque_apply(fov_settings_type *settings, fov_opaque_apply_type value);
180
181/**
182 * Set the function used to test whether a map tile is opaque.
183 *
184 * \param settings Pointer to data structure containing settings.
185 * \param f The function called to test whether a map tile is opaque.
186 */
187void fov_settings_set_opacity_test_function(fov_settings_type *settings, bool (*f)(void *map, int x, int y));
188
189/**
190 * Set the function used to apply lighting to a map tile.
191 *
192 * \param settings Pointer to data structure containing settings.
193 * \param f The function called to apply lighting to a map tile.
194 */
195void fov_settings_set_apply_lighting_function(fov_settings_type *settings, void (*f)(void *map, int x, int y, int dx, int dy, void *src));
196
197/**
198 * Free any memory that may have been cached in the settings
199 * structure.
200 *
201 * \param settings Pointer to data structure containing settings.
202 */
203void fov_settings_free(fov_settings_type *settings);
204
205/**
206 * Calculate a full circle field of view from a source at (x,y).
207 *
208 * \param settings Pointer to data structure containing settings.
209 * \param map Pointer to map data structure to be passed to callbacks.
210 * \param source Pointer to data structure holding source of light.
211 * \param source_x x-axis coordinate from which to start.
212 * \param source_y y-axis coordinate from which to start.
213 * \param radius Euclidean distance from (x,y) after which to stop.
214 */
215void fov_circle(fov_settings_type *settings, void *map, void *source,
216 int source_x, int source_y, unsigned radius
217);
218
219/**
220 * Calculate a field of view from source at (x,y), pointing
221 * in the given direction and with the given angle. The larger
222 * the angle, the wider, "less focused" the beam. Each side of the
223 * line pointing in the direction from the source will be half the
224 * angle given such that the angle specified will be represented on
225 * the raster.
226 *
227 * \param settings Pointer to data structure containing settings.
228 * \param map Pointer to map data structure to be passed to callbacks.
229 * \param source Pointer to data structure holding source of light.
230 * \param source_x x-axis coordinate from which to start.
231 * \param source_y y-axis coordinate from which to start.
232 * \param radius Euclidean distance from (x,y) after which to stop.
233 * \param direction One of eight directions the beam of light can point.
234 * \param angle The angle at the base of the beam of light, in degrees.
235 */
236void fov_beam(fov_settings_type *settings, void *map, void *source,
237 int source_x, int source_y, unsigned radius,
238 fov_direction_type direction, float angle
239);
240
241#ifdef __cplusplus
242} /* extern "C" */
243#endif
244
245#endif