summary refs log tree commit diff stats
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp522
1 files changed, 15 insertions, 507 deletions
diff --git a/src/main.cpp b/src/main.cpp index 03e7cda..8f20635 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -1,455 +1,9 @@
1#include <SDL.h>
2#include <SDL_image.h>
3#include <stdexcept>
4#include <memory>
5#include <vector> 1#include <vector>
6#include <list>
7#include <random>
8#include <fov.h> 2#include <fov.h>
9#include <iostream> 3#include <iostream>
10#include <tuple>
11#include <set>
12#include "util.h" 4#include "util.h"
13#include "map.h" 5#include "game.h"
14 6#include "renderer.h"
15class sdl_error : public std::logic_error {
16public:
17
18 sdl_error() : std::logic_error(SDL_GetError())
19 {
20 }
21};
22
23class img_error : public std::logic_error {
24public:
25
26 img_error() : std::logic_error(IMG_GetError())
27 {
28 }
29};
30
31class window_deleter {
32public:
33
34 void operator()(SDL_Window* ptr)
35 {
36 SDL_DestroyWindow(ptr);
37 }
38};
39
40using window_ptr = std::unique_ptr<SDL_Window, window_deleter>;
41
42class renderer_deleter {
43public:
44
45 void operator()(SDL_Renderer* ptr)
46 {
47 SDL_DestroyRenderer(ptr);
48 }
49};
50
51using renderer_ptr = std::unique_ptr<SDL_Renderer, renderer_deleter>;
52
53class surface_deleter {
54public:
55
56 void operator()(SDL_Surface* ptr)
57 {
58 SDL_FreeSurface(ptr);
59 }
60};
61
62using surface_ptr = std::unique_ptr<SDL_Surface, surface_deleter>;
63
64class texture_deleter {
65public:
66
67 void operator()(SDL_Texture* ptr)
68 {
69 SDL_DestroyTexture(ptr);
70 }
71};
72
73using texture_ptr = std::unique_ptr<SDL_Texture, texture_deleter>;
74
75enum class Tile {
76 Floor,
77 Wall,
78 Dust,
79 Lamp
80};
81
82enum class Source {
83 None,
84 Dust,
85 Lamp,
86 Player
87};
88
89enum class LoseState {
90 None,
91 PoppingLamps,
92 PoppingPlayer,
93 Outro
94};
95
96const int GAME_WIDTH = 640*2;
97const int GAME_HEIGHT = 480*2;
98const int TILE_WIDTH = 8*2;
99const int TILE_HEIGHT = TILE_WIDTH;
100const int INIT_ZOOM = 10;
101const int ZOOM_X_FACTOR = 8;
102const int ZOOM_Y_FACTOR = 6;
103const int RADIUS = 8;
104
105struct Input {
106 bool left = false;
107 bool right = false;
108 bool up = false;
109 bool down = false;
110};
111
112using coord = std::tuple<int, int>;
113
114struct Kickup {
115 int x;
116 int y;
117 size_t cur;
118 size_t radius;
119 size_t chain;
120 std::set<coord> done;
121 std::set<coord> front;
122};
123
124struct MapData {
125 Tile tile = Tile::Floor;
126 bool lit = false;
127 bool wasLit = false;
128 double visibility = 0.0;
129 size_t dustLife = 0;
130 Source lightType = Source::None;
131 int lightRadius = 0;
132 std::set<coord> litTiles;
133};
134
135class Game {
136public:
137
138 Game(std::mt19937& rng) :
139 rng(rng),
140 map(
141 -INIT_ZOOM * ZOOM_X_FACTOR / 2,
142 -INIT_ZOOM * ZOOM_Y_FACTOR / 2,
143 INIT_ZOOM * ZOOM_X_FACTOR,
144 INIT_ZOOM * ZOOM_Y_FACTOR)
145 {
146 }
147
148 std::mt19937& rng;
149
150 Map<MapData> map;
151 std::list<Kickup> kickups;
152 int litSpots = 0;
153 bool dirtyLighting = true;
154 size_t numLamps = 0;
155 size_t numDust = 0;
156
157 int player_x = 0;
158 int player_y = 0;
159 bool renderPlayer = true;
160
161 int curZoom = INIT_ZOOM;
162 int maxZoom = INIT_ZOOM;
163
164 bool zooming = false;
165 //size_t oldZoom;
166 int zoomProgress = 0;
167
168};
169
170void render(
171 SDL_Renderer* ren,
172 const Game& game,
173 bool drawDark = true)
174{
175 texture_ptr origFade;
176 {
177 surface_ptr pfs(IMG_Load("../res/lighting.png"));
178 if (!pfs)
179 {
180 throw img_error();
181 }
182
183 origFade = texture_ptr(SDL_CreateTextureFromSurface(ren, pfs.get()));
184 }
185
186 SDL_SetTextureBlendMode(origFade.get(), SDL_BLENDMODE_BLEND);
187
188 texture_ptr playerFade(
189 SDL_CreateTexture(
190 ren,
191 SDL_PIXELFORMAT_RGBA4444,
192 SDL_TEXTUREACCESS_TARGET,
193 144,
194 144));
195
196 if (!playerFade)
197 {
198 throw sdl_error();
199 }
200
201 SDL_SetRenderTarget(ren, playerFade.get());
202 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
203 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
204 SDL_RenderClear(ren);
205 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
206
207 texture_ptr lampFade(
208 SDL_CreateTexture(
209 ren,
210 SDL_PIXELFORMAT_RGBA4444,
211 SDL_TEXTUREACCESS_TARGET,
212 144,
213 144));
214
215 if (!lampFade)
216 {
217 throw sdl_error();
218 }
219
220 SDL_SetRenderTarget(ren, lampFade.get());
221
222 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
223 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
224 SDL_RenderClear(ren);
225 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
226
227 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD);
228 SDL_SetRenderDrawColor(ren, 255, 204, 58, 255);
229 SDL_RenderFillRect(ren, nullptr);
230
231 texture_ptr dustFade(
232 SDL_CreateTexture(
233 ren,
234 SDL_PIXELFORMAT_RGBA4444,
235 SDL_TEXTUREACCESS_TARGET,
236 144,
237 144));
238
239 if (!dustFade)
240 {
241 throw sdl_error();
242 }
243
244 SDL_SetRenderTarget(ren, dustFade.get());
245
246 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
247 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
248 SDL_RenderClear(ren);
249 SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr);
250
251 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD);
252 SDL_SetRenderDrawColor(ren, 255, 150, 255, 255);
253 SDL_RenderFillRect(ren, nullptr);
254
255 texture_ptr canvas(
256 SDL_CreateTexture(
257 ren,
258 SDL_PIXELFORMAT_RGBA8888,
259 SDL_TEXTUREACCESS_TARGET,
260 TILE_WIDTH * game.map.getWidth(),
261 TILE_HEIGHT * game.map.getHeight()));
262
263 if (!canvas)
264 {
265 throw sdl_error();
266 }
267
268 SDL_SetRenderTarget(ren, canvas.get());
269 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
270 SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255);
271 SDL_RenderClear(ren);
272
273 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
274 {
275 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
276 {
277 bool draw = true;
278
279 if ((game.player_x == x && game.player_y == y) && game.renderPlayer)
280 {
281 SDL_SetRenderDrawColor(ren, 255, 255, 0, 255);
282 } else if (!game.map.at(x,y).lit)
283 {
284 if (drawDark)
285 {
286 SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
287 } else {
288 draw = false;
289 }
290 } else {
291 int alpha = 255;
292
293 switch (game.map.at(x,y).tile)
294 {
295 case Tile::Floor:
296 {
297 SDL_SetRenderDrawColor(ren, 210, 210, 210, alpha);
298 break;
299 }
300
301 case Tile::Wall:
302 {
303 SDL_SetRenderDrawColor(ren, 100, 100, 100, alpha);
304 break;
305 }
306
307 case Tile::Dust:
308 {
309 SDL_SetRenderDrawColor(ren, 128, 40, 255, alpha);
310 break;
311 }
312
313 case Tile::Lamp:
314 {
315 SDL_SetRenderDrawColor(ren, 0, 255, 255, alpha);
316 break;
317 }
318 }
319 }
320
321 if (draw)
322 {
323 SDL_Rect rect {
324 game.map.getTrueX(x) * TILE_WIDTH,
325 game.map.getTrueY(y) * TILE_HEIGHT,
326 TILE_WIDTH,
327 TILE_HEIGHT};
328
329 //SDL_RenderFillRect(ren, &rect);
330
331 //int alpha = (1.0 - game.map.at(x,y).visibility) * 255;
332 //SDL_SetRenderDrawColor(ren, 40, 40, 40, 255);
333 SDL_RenderFillRect(ren, &rect);
334 }
335 }
336 }
337
338 texture_ptr mask(
339 SDL_CreateTexture(
340 ren,
341 SDL_PIXELFORMAT_RGBA8888,
342 SDL_TEXTUREACCESS_TARGET,
343 TILE_WIDTH * game.map.getWidth(),
344 TILE_HEIGHT * game.map.getHeight()));
345
346 if (!mask)
347 {
348 throw sdl_error();
349 }
350
351 SDL_SetRenderTarget(ren, mask.get());
352 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
353 SDL_RenderClear(ren);
354
355 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
356 {
357 for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
358 {
359 if (game.map.at(x,y).lightType != Source::None)
360 {
361 texture_ptr sourceMask(
362 SDL_CreateTexture(
363 ren,
364 SDL_PIXELFORMAT_RGBA8888,
365 SDL_TEXTUREACCESS_TARGET,
366 TILE_WIDTH * game.map.getWidth(),
367 TILE_HEIGHT * game.map.getHeight()));
368
369 if (!sourceMask)
370 {
371 throw sdl_error();
372 }
373
374 SDL_SetRenderTarget(ren, sourceMask.get());
375 SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE);
376 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
377 SDL_RenderClear(ren);
378
379 int fadeX = game.map.getTrueX(x) - game.map.at(x,y).lightRadius;
380 int fadeY = game.map.getTrueY(y) - game.map.at(x,y).lightRadius;
381 int fadeRight = game.map.getTrueX(x) + game.map.at(x,y).lightRadius;
382 int fadeBottom = game.map.getTrueY(y) + game.map.at(x,y).lightRadius;
383
384 SDL_Rect fadeRect {
385 fadeX * TILE_WIDTH,
386 fadeY * TILE_HEIGHT,
387 (game.map.at(x,y).lightRadius * 2 + 1) * TILE_WIDTH,
388 (game.map.at(x,y).lightRadius * 2 + 1) * TILE_HEIGHT};
389
390 if (game.map.at(x,y).lightType == Source::Lamp)
391 {
392 SDL_SetTextureBlendMode(lampFade.get(), SDL_BLENDMODE_NONE);
393 SDL_RenderCopy(ren, lampFade.get(), nullptr, &fadeRect);
394 } else if (game.map.at(x,y).lightType == Source::Player) {
395 SDL_SetTextureBlendMode(playerFade.get(), SDL_BLENDMODE_NONE);
396 SDL_RenderCopy(ren, playerFade.get(), nullptr, &fadeRect);
397 } else if (game.map.at(x,y).lightType == Source::Dust) {
398 SDL_SetTextureBlendMode(dustFade.get(), SDL_BLENDMODE_NONE);
399 SDL_RenderCopy(ren, dustFade.get(), nullptr, &fadeRect);
400 }
401
402 SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
403
404 for (int sy = fadeY; sy < fadeBottom; sy++)
405 {
406 for (int sx = fadeX; sx < fadeRight; sx++)
407 {
408 if (!game.map.at(x,y).litTiles.count({sx, sy}))
409 {
410 SDL_Rect rect {
411 game.map.getTrueX(sx) * TILE_WIDTH,
412 game.map.getTrueY(sy) * TILE_HEIGHT,
413 TILE_WIDTH,
414 TILE_HEIGHT};
415
416 SDL_RenderFillRect(ren, &rect);
417 }
418 }
419 }
420
421 SDL_SetRenderTarget(ren, mask.get());
422 SDL_SetTextureBlendMode(sourceMask.get(), SDL_BLENDMODE_ADD);
423 SDL_RenderCopy(ren, sourceMask.get(), nullptr, nullptr);
424 }
425 }
426 }
427
428 SDL_SetRenderTarget(ren, canvas.get());
429 SDL_SetTextureBlendMode(mask.get(), SDL_BLENDMODE_MOD);
430 SDL_RenderCopy(ren, mask.get(), nullptr, nullptr);
431
432 SDL_SetRenderTarget(ren, nullptr);
433
434 if (!game.zooming)
435 {
436 SDL_RenderCopy(ren, canvas.get(), nullptr, nullptr);
437 } else {
438 // TODO: zooming back in to the player
439 SDL_Rect zoomRect {
440 ((game.maxZoom - game.curZoom) * TILE_WIDTH + game.zoomProgress)
441 * ZOOM_X_FACTOR / 2,
442 ((game.maxZoom - game.curZoom) * TILE_HEIGHT + game.zoomProgress)
443 * ZOOM_Y_FACTOR / 2,
444 (game.curZoom * TILE_WIDTH - game.zoomProgress) * ZOOM_X_FACTOR,
445 (game.curZoom * TILE_HEIGHT - game.zoomProgress) * ZOOM_Y_FACTOR
446 };
447
448 SDL_RenderCopy(ren, canvas.get(), &zoomRect, nullptr);
449 }
450
451 SDL_RenderPresent(ren);
452}
453 7
454void incrementIfSet(Game& game, int& count, int x, int y, Tile val = Tile::Wall) 8void incrementIfSet(Game& game, int& count, int x, int y, Tile val = Tile::Wall)
455{ 9{
@@ -543,7 +97,7 @@ void movePlayer(Game& game, int x, int y)
543 } 97 }
544} 98}
545 99
546void recalculateLighting(Game& game, fov_settings_type* fov) 100void recalculateLighting(Game& game)
547{ 101{
548 game.litSpots = 0; 102 game.litSpots = 0;
549 103
@@ -551,12 +105,14 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
551 { 105 {
552 md.wasLit = md.lit; 106 md.wasLit = md.lit;
553 md.lit = false; 107 md.lit = false;
554 md.visibility = 0.0;
555 md.litTiles.clear(); 108 md.litTiles.clear();
556 } 109 }
557 110
111 fov_settings_type fov;
112 fov_settings_init(&fov);
113
558 fov_settings_set_opacity_test_function( 114 fov_settings_set_opacity_test_function(
559 fov, 115 &fov,
560 [] (void* data, int x, int y) { 116 [] (void* data, int x, int y) {
561 Game& game = *static_cast<Game*>(data); 117 Game& game = *static_cast<Game*>(data);
562 118
@@ -564,7 +120,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
564 }); 120 });
565 121
566 fov_settings_set_apply_lighting_function( 122 fov_settings_set_apply_lighting_function(
567 fov, 123 &fov,
568 [] (void* data, int x, int y, int dx, int dy, void* source) { 124 [] (void* data, int x, int y, int dx, int dy, void* source) {
569 Game& game = *static_cast<Game*>(data); 125 Game& game = *static_cast<Game*>(data);
570 126
@@ -580,21 +136,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
580 136
581 game.map.at(x,y).lit = true; 137 game.map.at(x,y).lit = true;
582 138
583 /*game.map.at(x,y).visibility = std::max(
584 game.map.at(x,y).visibility,
585 std::pow(
586 std::max(
587 0.0,
588 1.0 - std::sqrt(dx * dx + dy * dy) / lightRadius),
589 1.0/3.0));*/
590
591 sourceData.litTiles.emplace(x,y); 139 sourceData.litTiles.emplace(x,y);
592
593 //Source ls = *static_cast<Source*>(source);
594 //if (static_cast<size_t>(ls) > static_cast<size_t>(m.lightSource[x+VIEW_WIDTH*y]))
595 {
596 //m.lightSource[x+VIEW_WIDTH*y] = ls;
597 }
598 } 140 }
599 }); 141 });
600 142
@@ -620,7 +162,6 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
620 } 162 }
621 163
622 game.map.at(x,y).lightType = ls; 164 game.map.at(x,y).lightType = ls;
623 //game.map.at(x,y).litTiles.clear();
624 165
625 if (ls != Source::None) 166 if (ls != Source::None)
626 { 167 {
@@ -628,7 +169,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
628 game.map.at(x,y).litTiles.emplace(x,y); 169 game.map.at(x,y).litTiles.emplace(x,y);
629 170
630 fov_circle( 171 fov_circle(
631 fov, 172 &fov,
632 static_cast<void*>(&game), 173 static_cast<void*>(&game),
633 static_cast<void*>(&game.map.at(x,y)), 174 static_cast<void*>(&game.map.at(x,y)),
634 x, 175 x,
@@ -636,7 +177,6 @@ void recalculateLighting(Game& game, fov_settings_type* fov)
636 lightRadius); 177 lightRadius);
637 178
638 game.map.at(x,y).lit = true; 179 game.map.at(x,y).lit = true;
639 game.map.at(x,y).visibility = 1.0;
640 } 180 }
641 } 181 }
642 } 182 }
@@ -832,44 +372,12 @@ int main(int, char**)
832 std::random_device randomEngine; 372 std::random_device randomEngine;
833 std::mt19937 rng(randomEngine()); 373 std::mt19937 rng(randomEngine());
834 374
835 if (SDL_Init(SDL_INIT_VIDEO) != 0)
836 {
837 throw sdl_error();
838 }
839
840 if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG)
841 {
842 throw img_error();
843 }
844
845 try 375 try
846 { 376 {
847 window_ptr win( 377 Renderer renderer;
848 SDL_CreateWindow("Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN));
849
850 if (!win)
851 {
852 throw sdl_error();
853 }
854
855 renderer_ptr ren(
856 SDL_CreateRenderer(
857 win.get(),
858 -1,
859 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
860
861 if (!ren)
862 {
863 throw sdl_error();
864 }
865
866 SDL_SetRenderDrawBlendMode(ren.get(), SDL_BLENDMODE_BLEND);
867 378
868 Game game(rng); 379 Game game(rng);
869 380
870 std::unique_ptr<fov_settings_type> fov(new fov_settings_type());
871 fov_settings_init(fov.get());
872
873 for (MapData& md : game.map.data()) 381 for (MapData& md : game.map.data())
874 { 382 {
875 if (std::bernoulli_distribution(0.5)(rng)) 383 if (std::bernoulli_distribution(0.5)(rng))
@@ -1091,7 +599,7 @@ int main(int, char**)
1091 599
1092 if (game.dirtyLighting) 600 if (game.dirtyLighting)
1093 { 601 {
1094 recalculateLighting(game, fov.get()); 602 recalculateLighting(game);
1095 603
1096 for (int y = game.map.getTop(); y < game.map.getBottom(); y++) 604 for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
1097 { 605 {
@@ -1140,15 +648,15 @@ int main(int, char**)
1140 zoomAcc -= zoomDt; 648 zoomAcc -= zoomDt;
1141 } 649 }
1142 650
1143 render(ren.get(), game, true); 651 renderer.render(game, true);
1144 } 652 }
1145 } catch (const sdl_error& ex) 653 } catch (const sdl_error& ex)
1146 { 654 {
1147 std::cout << "SDL error (" << ex.what() << ")" << std::endl; 655 std::cout << "SDL error (" << ex.what() << ")" << std::endl;
656 } catch (const img_error& ex)
657 {
658 std::cout << "SDL_IMG error (" << ex.what() << ")" << std::endl;
1148 } 659 }
1149 660
1150 IMG_Quit();
1151 SDL_Quit();
1152
1153 return 0; 661 return 0;
1154} 662}