diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2022-03-17 15:28:22 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2022-03-17 15:28:22 -0400 |
commit | 5324adfe51f1348fc97fe2ee0ca4e4bbd2a6ad64 (patch) | |
tree | 6b3ff32f9ad2764405fd73a70e15c960a076ed00 | |
parent | e0fd87411eb5368fee47e268ae03d073293e58c3 (diff) | |
download | ether-5324adfe51f1348fc97fe2ee0ca4e4bbd2a6ad64.tar.gz ether-5324adfe51f1348fc97fe2ee0ca4e4bbd2a6ad64.tar.bz2 ether-5324adfe51f1348fc97fe2ee0ca4e4bbd2a6ad64.zip |
lotta performance improvements
the two main things: 1) When ticking three times after a lighting change, we no longer iterate over the entire map. Instead, we keep a list of the tiles that have changed and the ones adjacent to them, and we iterate over that list. 2) The map tile type is now stored in a separate array from the rest of the tile data. This is because the tile type is the only thing needed for the cellular automata tick, and thus the only thing that we need to actually copy.
-rw-r--r-- | src/game.cpp | 195 | ||||
-rw-r--r-- | src/game.h | 4 | ||||
-rw-r--r-- | src/map.h | 94 | ||||
-rw-r--r-- | src/renderer.cpp | 4 |
4 files changed, 200 insertions, 97 deletions
diff --git a/src/game.cpp b/src/game.cpp index 088ab4d..9d557e3 100644 --- a/src/game.cpp +++ b/src/game.cpp | |||
@@ -20,7 +20,7 @@ Game::Game(std::mt19937& rng, Muxer& muxer, Renderer& renderer) : | |||
20 | { | 20 | { |
21 | for (int x = -1; x <= 1; x++) | 21 | for (int x = -1; x <= 1; x++) |
22 | { | 22 | { |
23 | map.at(x,y).tile = Tile::Floor; | 23 | map.tile(x,y) = Tile::Floor; |
24 | } | 24 | } |
25 | } | 25 | } |
26 | 26 | ||
@@ -35,12 +35,12 @@ Game::Game(std::mt19937& rng, Muxer& muxer, Renderer& renderer) : | |||
35 | 35 | ||
36 | inline bool isTileSetOrNotLit(const Map& map, int x, int y) | 36 | inline bool isTileSetOrNotLit(const Map& map, int x, int y) |
37 | { | 37 | { |
38 | return (map.inBounds(x, y) && (map.at(x,y).tile == Tile::Wall || !map.at(x,y).lit)); | 38 | return (map.inBounds(x, y) && (map.tile(x,y) == Tile::Wall || !map.at(x,y).lit)); |
39 | } | 39 | } |
40 | 40 | ||
41 | inline bool isTileSet(const Map& map, int x, int y, Tile val = Tile::Wall) | 41 | inline bool isTileSet(const Map& map, int x, int y, Tile val = Tile::Wall) |
42 | { | 42 | { |
43 | return (map.inBounds(x, y) && map.at(x,y).tile == val); | 43 | return (map.inBounds(x, y) && map.tile(x,y) == val); |
44 | } | 44 | } |
45 | 45 | ||
46 | inline void incrementIfSet(const Game& game, int& count, int x, int y, Tile val = Tile::Wall) | 46 | inline void incrementIfSet(const Game& game, int& count, int x, int y, Tile val = Tile::Wall) |
@@ -55,6 +55,56 @@ inline int getZoomLevel(const Game& game) { | |||
55 | return game.curZoom - INIT_ZOOM; | 55 | return game.curZoom - INIT_ZOOM; |
56 | } | 56 | } |
57 | 57 | ||
58 | inline void tickIndividual(Game& game, std::vector<Tile>& mapDoubleBuffer, int x, int y, bool onlyDark) { | ||
59 | if (onlyDark && game.map.at(x,y).lit) | ||
60 | { | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | if (game.map.tile(x,y) == Tile::Lamp) | ||
65 | { | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | int count = 0; | ||
70 | |||
71 | incrementIfSet(game, count, x-1, y-1); | ||
72 | incrementIfSet(game, count, x-1, y ); | ||
73 | incrementIfSet(game, count, x-1, y+1); | ||
74 | incrementIfSet(game, count, x , y-1); | ||
75 | incrementIfSet(game, count, x , y ); | ||
76 | incrementIfSet(game, count, x , y+1); | ||
77 | incrementIfSet(game, count, x+1, y-1); | ||
78 | incrementIfSet(game, count, x+1, y ); | ||
79 | incrementIfSet(game, count, x+1, y+1); | ||
80 | |||
81 | int tempIndex = game.map.getTrueX(x) + game.map.getTrueY(y) * game.map.getWidth(); | ||
82 | if (count >= 5) | ||
83 | { | ||
84 | mapDoubleBuffer[tempIndex] = Tile::Wall; | ||
85 | } else { | ||
86 | mapDoubleBuffer[tempIndex] = Tile::Floor; | ||
87 | } | ||
88 | |||
89 | if (mapDoubleBuffer[tempIndex] != game.map.tile(x,y)) { | ||
90 | game.map.at(x,y).dirtyRender = true; | ||
91 | game.dirtyRender = true; | ||
92 | game.map.markDirtyAround(x,y); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | void Game::tickDirty(bool onlyDark) { | ||
97 | mapDoubleBuffer = map.tiles(); | ||
98 | std::vector<coord> dirty = map.getDirty(); | ||
99 | map.resetDirty(); | ||
100 | |||
101 | for (auto [x,y] : dirty) { | ||
102 | tickIndividual(*this, mapDoubleBuffer, x, y, onlyDark); | ||
103 | } | ||
104 | |||
105 | std::swap(map.tiles(), mapDoubleBuffer); | ||
106 | } | ||
107 | |||
58 | void Game::tick( | 108 | void Game::tick( |
59 | int x1, | 109 | int x1, |
60 | int y1, | 110 | int y1, |
@@ -63,7 +113,8 @@ void Game::tick( | |||
63 | bool invert, | 113 | bool invert, |
64 | bool onlyDark) | 114 | bool onlyDark) |
65 | { | 115 | { |
66 | mapDoubleBuffer = map.data(); | 116 | mapDoubleBuffer = map.tiles(); |
117 | map.resetDirty(); | ||
67 | 118 | ||
68 | for (int y = map.getTop(); y < map.getBottom(); y++) | 119 | for (int y = map.getTop(); y < map.getBottom(); y++) |
69 | { | 120 | { |
@@ -74,44 +125,11 @@ void Game::tick( | |||
74 | continue; | 125 | continue; |
75 | } | 126 | } |
76 | 127 | ||
77 | if (onlyDark && map.at(x,y).lit) | 128 | tickIndividual(*this, mapDoubleBuffer, x, y, onlyDark); |
78 | { | ||
79 | continue; | ||
80 | } | ||
81 | |||
82 | if (map.at(x,y).tile == Tile::Lamp) | ||
83 | { | ||
84 | continue; | ||
85 | } | ||
86 | |||
87 | int count = 0; | ||
88 | |||
89 | incrementIfSet(*this, count, x-1, y-1); | ||
90 | incrementIfSet(*this, count, x-1, y ); | ||
91 | incrementIfSet(*this, count, x-1, y+1); | ||
92 | incrementIfSet(*this, count, x , y-1); | ||
93 | incrementIfSet(*this, count, x , y ); | ||
94 | incrementIfSet(*this, count, x , y+1); | ||
95 | incrementIfSet(*this, count, x+1, y-1); | ||
96 | incrementIfSet(*this, count, x+1, y ); | ||
97 | incrementIfSet(*this, count, x+1, y+1); | ||
98 | |||
99 | int tempIndex = map.getTrueX(x) + map.getTrueY(y) * map.getWidth(); | ||
100 | if (count >= 5) | ||
101 | { | ||
102 | mapDoubleBuffer[tempIndex].tile = Tile::Wall; | ||
103 | } else { | ||
104 | mapDoubleBuffer[tempIndex].tile = Tile::Floor; | ||
105 | } | ||
106 | |||
107 | if (mapDoubleBuffer[tempIndex].tile != map.at(x,y).tile) { | ||
108 | mapDoubleBuffer[tempIndex].dirtyRender = true; | ||
109 | dirtyRender = true; | ||
110 | } | ||
111 | } | 129 | } |
112 | } | 130 | } |
113 | 131 | ||
114 | std::swap(map.data(), mapDoubleBuffer); | 132 | std::swap(map.tiles(), mapDoubleBuffer); |
115 | } | 133 | } |
116 | 134 | ||
117 | void Game::tick(bool onlyDark) | 135 | void Game::tick(bool onlyDark) |
@@ -127,11 +145,11 @@ void Game::tick(bool onlyDark) | |||
127 | 145 | ||
128 | bool Game::movePlayer(int x, int y) | 146 | bool Game::movePlayer(int x, int y) |
129 | { | 147 | { |
130 | if (map.at(x,y).tile == Tile::Floor && !map.at(x,y).sign) | 148 | if (map.tile(x,y) == Tile::Floor && !map.at(x,y).sign) |
131 | { | 149 | { |
132 | if (map.at(player_x, player_y).tile == Tile::Floor) | 150 | if (map.tile(player_x, player_y) == Tile::Floor) |
133 | { | 151 | { |
134 | map.at(player_x, player_y).tile = Tile::Dust; | 152 | map.tile(player_x, player_y) = Tile::Dust; |
135 | map.at(player_x, player_y).dustLife = 1; | 153 | map.at(player_x, player_y).dustLife = 1; |
136 | numDust++; | 154 | numDust++; |
137 | } | 155 | } |
@@ -169,14 +187,15 @@ void Game::recalculateLighting() | |||
169 | litSpots = 0; | 187 | litSpots = 0; |
170 | dirtyRender = true; | 188 | dirtyRender = true; |
171 | 189 | ||
172 | for (MapData& md : map.data()) | 190 | for (int y=map.getTop(); y<map.getBottom(); y++) { |
173 | { | 191 | for (int x=map.getLeft(); x<map.getRight(); x++) { |
174 | md.wasLit = md.lit; | 192 | map.at(x,y).wasLit = map.at(x,y).lit; |
175 | md.lit = false; | 193 | map.at(x,y).lit = false; |
176 | md.litTiles.clear(); | 194 | map.at(x,y).litTiles.clear(); |
177 | 195 | ||
178 | if (md.tile == Tile::Wall) { | 196 | if (map.tile(x,y) == Tile::Wall) { |
179 | md.dirtyRender = true; | 197 | map.at(x,y).dirtyRender = true; |
198 | } | ||
180 | } | 199 | } |
181 | } | 200 | } |
182 | 201 | ||
@@ -188,7 +207,7 @@ void Game::recalculateLighting() | |||
188 | [] (void* data, int x, int y) { | 207 | [] (void* data, int x, int y) { |
189 | Game& game = *static_cast<Game*>(data); | 208 | Game& game = *static_cast<Game*>(data); |
190 | 209 | ||
191 | return game.map.inBounds(x,y) && game.map.at(x,y).tile == Tile::Wall; | 210 | return game.map.inBounds(x,y) && game.map.tile(x,y) == Tile::Wall; |
192 | }); | 211 | }); |
193 | 212 | ||
194 | fov_settings_set_apply_lighting_function( | 213 | fov_settings_set_apply_lighting_function( |
@@ -223,11 +242,11 @@ void Game::recalculateLighting() | |||
223 | { | 242 | { |
224 | ls = Source::Player; | 243 | ls = Source::Player; |
225 | lightRadius = RADIUS; | 244 | lightRadius = RADIUS; |
226 | } else if (map.at(x,y).tile == Tile::Dust) | 245 | } else if (map.tile(x,y) == Tile::Dust) |
227 | { | 246 | { |
228 | ls = Source::Dust; | 247 | ls = Source::Dust; |
229 | lightRadius = 2; | 248 | lightRadius = 2; |
230 | } else if (map.at(x,y).tile == Tile::Lamp) | 249 | } else if (map.tile(x,y) == Tile::Lamp) |
231 | { | 250 | { |
232 | ls = Source::Lamp; | 251 | ls = Source::Lamp; |
233 | lightRadius = RADIUS; | 252 | lightRadius = RADIUS; |
@@ -265,7 +284,7 @@ void Game::recalculateRender() { | |||
265 | if (map.at(x,y).dirtyRender) { | 284 | if (map.at(x,y).dirtyRender) { |
266 | map.at(x,y).dirtyRender = false; | 285 | map.at(x,y).dirtyRender = false; |
267 | 286 | ||
268 | if (map.at(x,y).tile == Tile::Floor) { | 287 | if (map.tile(x,y) == Tile::Floor) { |
269 | int renderDesc = 0; | 288 | int renderDesc = 0; |
270 | if (isTileSetOrNotLit(map, x-1, y-1)) renderDesc |= (1 << 7); | 289 | if (isTileSetOrNotLit(map, x-1, y-1)) renderDesc |= (1 << 7); |
271 | if (isTileSetOrNotLit(map, x , y-1)) renderDesc |= (1 << 6); | 290 | if (isTileSetOrNotLit(map, x , y-1)) renderDesc |= (1 << 6); |
@@ -297,7 +316,7 @@ void Game::recalculateRender() { | |||
297 | map.at(x,y).renderId = -1; | 316 | map.at(x,y).renderId = -1; |
298 | map.at(x,y).sign = false; | 317 | map.at(x,y).sign = false; |
299 | } | 318 | } |
300 | } else if (map.at(x,y).tile == Tile::Wall) { | 319 | } else if (map.tile(x,y) == Tile::Wall) { |
301 | static bool initWalls = false; | 320 | static bool initWalls = false; |
302 | static std::vector<int> wallRenders(256, TilesetIndex(0, 0)); | 321 | static std::vector<int> wallRenders(256, TilesetIndex(0, 0)); |
303 | if (!initWalls) { | 322 | if (!initWalls) { |
@@ -439,12 +458,12 @@ void Game::popLamp(int x, int y, size_t chain) | |||
439 | { | 458 | { |
440 | muxer.playSoundAtPosition("pop", x, y); | 459 | muxer.playSoundAtPosition("pop", x, y); |
441 | 460 | ||
442 | if (map.at(x,y).tile == Tile::Lamp) | 461 | if (map.tile(x,y) == Tile::Lamp) |
443 | { | 462 | { |
444 | numLamps--; | 463 | numLamps--; |
445 | } | 464 | } |
446 | 465 | ||
447 | map.at(x,y).tile = Tile::Dust; | 466 | map.tile(x,y) = Tile::Dust; |
448 | map.at(x,y).dustLife = 2; | 467 | map.at(x,y).dustLife = 2; |
449 | numDust++; | 468 | numDust++; |
450 | dirtyLighting = true; | 469 | dirtyLighting = true; |
@@ -465,19 +484,19 @@ void Game::processKickup() | |||
465 | coord c {x,y}; | 484 | coord c {x,y}; |
466 | 485 | ||
467 | if (map.inBounds(x,y) && | 486 | if (map.inBounds(x,y) && |
468 | (map.at(x,y).tile == Tile::Floor || map.at(x,y).tile == Tile::Lamp) && | 487 | (map.tile(x,y) == Tile::Floor || map.tile(x,y) == Tile::Lamp) && |
469 | !kickup.done.count(c)) | 488 | !kickup.done.count(c)) |
470 | { | 489 | { |
471 | newFront.insert(c); | 490 | newFront.insert(c); |
472 | kickup.done.insert(c); | 491 | kickup.done.insert(c); |
473 | 492 | ||
474 | if (map.at(x,y).tile == Tile::Floor) | 493 | if (map.tile(x,y) == Tile::Floor) |
475 | { | 494 | { |
476 | map.at(x,y).tile = Tile::Dust; | 495 | map.tile(x,y) = Tile::Dust; |
477 | map.at(x,y).dustLife = 2; | 496 | map.at(x,y).dustLife = 2; |
478 | numDust++; | 497 | numDust++; |
479 | dirtyLighting = true; | 498 | dirtyLighting = true; |
480 | } else if (map.at(x,y).tile == Tile::Lamp) | 499 | } else if (map.tile(x,y) == Tile::Lamp) |
481 | { | 500 | { |
482 | popLamp(x, y, kickup.chain + 1); | 501 | popLamp(x, y, kickup.chain + 1); |
483 | } | 502 | } |
@@ -571,11 +590,11 @@ void Game::setZoom(size_t zoom) | |||
571 | } | 590 | } |
572 | 591 | ||
573 | void Game::performDash() { | 592 | void Game::performDash() { |
574 | if (map.at(player_x, player_y).tile == Tile::Floor) { | 593 | if (map.tile(player_x, player_y) == Tile::Floor) { |
575 | std::vector<coord> freeSpaces; | 594 | std::vector<coord> freeSpaces; |
576 | 595 | ||
577 | auto addIfFree = [&] (int x, int y) { | 596 | auto addIfFree = [&] (int x, int y) { |
578 | if (map.inBounds(x,y) && map.at(x,y).tile == Tile::Floor) | 597 | if (map.inBounds(x,y) && map.tile(x,y) == Tile::Floor) |
579 | { | 598 | { |
580 | freeSpaces.emplace_back(x, y); | 599 | freeSpaces.emplace_back(x, y); |
581 | } | 600 | } |
@@ -592,7 +611,7 @@ void Game::performDash() { | |||
592 | 611 | ||
593 | if (!freeSpaces.empty()) | 612 | if (!freeSpaces.empty()) |
594 | { | 613 | { |
595 | map.at(player_x, player_y).tile = Tile::Lamp; | 614 | map.tile(player_x, player_y) = Tile::Lamp; |
596 | numLamps++; | 615 | numLamps++; |
597 | dirtyLighting = true; | 616 | dirtyLighting = true; |
598 | kickUpDust(player_x, player_y, 0); | 617 | kickUpDust(player_x, player_y, 0); |
@@ -725,18 +744,19 @@ void Game::updatePlaying(size_t frameTime) { | |||
725 | { | 744 | { |
726 | numDust = 0; | 745 | numDust = 0; |
727 | 746 | ||
728 | for (MapData& md : map.data()) | 747 | for (int y=map.getTop(); y<map.getBottom(); y++) { |
729 | { | 748 | for (int x=map.getLeft(); x<map.getRight(); x++) { |
730 | if (md.tile == Tile::Dust) | 749 | if (map.tile(x,y) == Tile::Dust) |
731 | { | ||
732 | md.dustLife--; | ||
733 | |||
734 | if (md.dustLife <= 0) | ||
735 | { | 750 | { |
736 | md.tile = Tile::Floor; | 751 | map.at(x,y).dustLife--; |
737 | dirtyLighting = true; | 752 | |
738 | } else { | 753 | if (map.at(x,y).dustLife <= 0) |
739 | numDust++; | 754 | { |
755 | map.tile(x,y) = Tile::Floor; | ||
756 | dirtyLighting = true; | ||
757 | } else { | ||
758 | numDust++; | ||
759 | } | ||
740 | } | 760 | } |
741 | } | 761 | } |
742 | } | 762 | } |
@@ -784,7 +804,7 @@ void Game::updatePlaying(size_t frameTime) { | |||
784 | { | 804 | { |
785 | for (int x = map.getLeft(); x < map.getRight(); x++) | 805 | for (int x = map.getLeft(); x < map.getRight(); x++) |
786 | { | 806 | { |
787 | if (map.at(x,y).tile == Tile::Lamp) | 807 | if (map.tile(x,y) == Tile::Lamp) |
788 | { | 808 | { |
789 | lamps.emplace_back(x, y); | 809 | lamps.emplace_back(x, y); |
790 | } | 810 | } |
@@ -874,29 +894,24 @@ void Game::updatePlaying(size_t frameTime) { | |||
874 | { | 894 | { |
875 | if (!map.at(x,y).lit && map.at(x,y).wasLit) | 895 | if (!map.at(x,y).lit && map.at(x,y).wasLit) |
876 | { | 896 | { |
897 | Tile oldTile = map.tile(x,y); | ||
877 | if (std::bernoulli_distribution(0.5)(rng)) | 898 | if (std::bernoulli_distribution(0.5)(rng)) |
878 | { | 899 | { |
879 | map.at(x,y).tile = Tile::Wall; | 900 | map.tile(x,y) = Tile::Wall; |
880 | } else { | 901 | } else { |
881 | map.at(x,y).tile = Tile::Floor; | 902 | map.tile(x,y) = Tile::Floor; |
903 | } | ||
904 | if (map.tile(x,y) != oldTile) { | ||
905 | map.at(x,y).dirtyRender = true; | ||
906 | map.markDirtyAround(x,y); | ||
882 | } | 907 | } |
883 | map.at(x,y).dirtyRender = true; | ||
884 | } | 908 | } |
885 | } | 909 | } |
886 | } | 910 | } |
887 | 911 | ||
888 | /*int x1 = player_x - curZoom * ZOOM_X_FACTOR / 2 - 1; | 912 | tickDirty(true); |
889 | int y1 = player_y - curZoom * ZOOM_Y_FACTOR / 2 - 1; | 913 | tickDirty(true); |
890 | int x2 = player_x + curZoom * ZOOM_X_FACTOR / 2 + 2; | 914 | tickDirty(true); |
891 | int y2 = player_y + curZoom * ZOOM_Y_FACTOR / 2 + 2;*/ | ||
892 | int x1 = player_x - CHUNK_WIDTH / 2 - 1; | ||
893 | int y1 = player_y - CHUNK_HEIGHT / 2 - 1; | ||
894 | int x2 = player_x + CHUNK_WIDTH / 2 + 2; | ||
895 | int y2 = player_y + CHUNK_HEIGHT / 2 + 2; | ||
896 | |||
897 | tick(x1, y1, x2, y2, false, true); | ||
898 | tick(x1, y1, x2, y2, false, true); | ||
899 | tick(x1, y1, x2, y2, false, true); | ||
900 | 915 | ||
901 | // TODO: better zoom algorithm | 916 | // TODO: better zoom algorithm |
902 | setZoom(litSpots / 1500 + INIT_ZOOM); | 917 | setZoom(litSpots / 1500 + INIT_ZOOM); |
diff --git a/src/game.h b/src/game.h index 637a033..c75d43b 100644 --- a/src/game.h +++ b/src/game.h | |||
@@ -71,7 +71,7 @@ public: | |||
71 | bool dirtyRender = true; | 71 | bool dirtyRender = true; |
72 | size_t numLamps = 0; | 72 | size_t numLamps = 0; |
73 | size_t numDust = 0; | 73 | size_t numDust = 0; |
74 | std::vector<MapData> mapDoubleBuffer; | 74 | std::vector<Tile> mapDoubleBuffer; |
75 | 75 | ||
76 | int player_x = 0; | 76 | int player_x = 0; |
77 | int player_y = 0; | 77 | int player_y = 0; |
@@ -111,6 +111,8 @@ public: | |||
111 | 111 | ||
112 | private: | 112 | private: |
113 | 113 | ||
114 | void tickDirty(bool onlyDark); | ||
115 | |||
114 | void tick( | 116 | void tick( |
115 | int x1, | 117 | int x1, |
116 | int y1, | 118 | int y1, |
diff --git a/src/map.h b/src/map.h index de74b14..fe3270c 100644 --- a/src/map.h +++ b/src/map.h | |||
@@ -25,7 +25,6 @@ enum class Source { | |||
25 | }; | 25 | }; |
26 | 26 | ||
27 | struct MapData { | 27 | struct MapData { |
28 | Tile tile = Tile::Floor; | ||
29 | bool lit = false; | 28 | bool lit = false; |
30 | bool wasLit = false; | 29 | bool wasLit = false; |
31 | size_t dustLife = 0; | 30 | size_t dustLife = 0; |
@@ -39,6 +38,7 @@ struct MapData { | |||
39 | }; | 38 | }; |
40 | 39 | ||
41 | struct Chunk { | 40 | struct Chunk { |
41 | std::array<Tile, CHUNK_WIDTH*CHUNK_HEIGHT> tiles; | ||
42 | std::array<MapData, CHUNK_WIDTH*CHUNK_HEIGHT> data; | 42 | std::array<MapData, CHUNK_WIDTH*CHUNK_HEIGHT> data; |
43 | int litTiles = 0; | 43 | int litTiles = 0; |
44 | int x; | 44 | int x; |
@@ -101,6 +101,16 @@ public: | |||
101 | (y < top_ + height_); | 101 | (y < top_ + height_); |
102 | } | 102 | } |
103 | 103 | ||
104 | inline const Tile& tile(int x, int y) const | ||
105 | { | ||
106 | return loadedTiles_[(x - left_) + width_ * (y - top_)]; | ||
107 | } | ||
108 | |||
109 | inline Tile& tile(int x, int y) | ||
110 | { | ||
111 | return const_cast<Tile&>(static_cast<const Map&>(*this).tile(x, y)); | ||
112 | } | ||
113 | |||
104 | inline const MapData& at(int x, int y) const | 114 | inline const MapData& at(int x, int y) const |
105 | { | 115 | { |
106 | return loaded_[(x - left_) + width_ * (y - top_)]; | 116 | return loaded_[(x - left_) + width_ * (y - top_)]; |
@@ -111,6 +121,16 @@ public: | |||
111 | return const_cast<MapData&>(static_cast<const Map&>(*this).at(x, y)); | 121 | return const_cast<MapData&>(static_cast<const Map&>(*this).at(x, y)); |
112 | } | 122 | } |
113 | 123 | ||
124 | inline const std::vector<Tile>& tiles() const | ||
125 | { | ||
126 | return loadedTiles_; | ||
127 | } | ||
128 | |||
129 | inline std::vector<Tile>& tiles() | ||
130 | { | ||
131 | return loadedTiles_; | ||
132 | } | ||
133 | |||
114 | inline const std::vector<MapData>& data() const | 134 | inline const std::vector<MapData>& data() const |
115 | { | 135 | { |
116 | return loaded_; | 136 | return loaded_; |
@@ -139,6 +159,11 @@ public: | |||
139 | int startX = chunkX * CHUNK_WIDTH; | 159 | int startX = chunkX * CHUNK_WIDTH; |
140 | int startY = chunkY * CHUNK_HEIGHT; | 160 | int startY = chunkY * CHUNK_HEIGHT; |
141 | for (int y=0; y<CHUNK_HEIGHT; y++) { | 161 | for (int y=0; y<CHUNK_HEIGHT; y++) { |
162 | std::copy( | ||
163 | std::next(std::begin(loadedTiles_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH), | ||
164 | std::next(std::begin(loadedTiles_), (chunkY*CHUNK_HEIGHT + y)*width_ + (chunkX+1)*CHUNK_WIDTH), | ||
165 | std::next(std::begin(chunk.tiles), y*CHUNK_WIDTH)); | ||
166 | |||
142 | for (int x=0; x<CHUNK_WIDTH; x++) { | 167 | for (int x=0; x<CHUNK_WIDTH; x++) { |
143 | chunk.data[x+y*CHUNK_WIDTH] = loaded_[startX+x+(startY+y)*width_]; | 168 | chunk.data[x+y*CHUNK_WIDTH] = loaded_[startX+x+(startY+y)*width_]; |
144 | if (chunk.data[x+y*CHUNK_WIDTH].lit) { | 169 | if (chunk.data[x+y*CHUNK_WIDTH].lit) { |
@@ -169,6 +194,9 @@ public: | |||
169 | width_ = chunksHoriz_ * CHUNK_WIDTH; | 194 | width_ = chunksHoriz_ * CHUNK_WIDTH; |
170 | height_ = chunksVert_ * CHUNK_HEIGHT; | 195 | height_ = chunksVert_ * CHUNK_HEIGHT; |
171 | loaded_ = std::vector<MapData>(width_ * height_); | 196 | loaded_ = std::vector<MapData>(width_ * height_); |
197 | loadedTiles_ = std::vector<Tile>(width_ * height_, Tile::Floor); | ||
198 | dirtyTiles_.clear(); | ||
199 | dirtySet_ = std::vector<bool>(width_ * height_, false); | ||
172 | 200 | ||
173 | // Load in the requested chunks. | 201 | // Load in the requested chunks. |
174 | for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { | 202 | for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { |
@@ -190,14 +218,16 @@ public: | |||
190 | chunk.y = topmostChunk_ + chunkY; | 218 | chunk.y = topmostChunk_ + chunkY; |
191 | chunk.litTiles = 0; | 219 | chunk.litTiles = 0; |
192 | 220 | ||
193 | for (MapData& md : chunk.data) | 221 | for (Tile& tile : chunk.tiles) |
194 | { | 222 | { |
195 | if (std::bernoulli_distribution(0.5)(rng)) | 223 | if (std::bernoulli_distribution(0.5)(rng)) |
196 | { | 224 | { |
197 | md.tile = Tile::Wall; | 225 | tile = Tile::Wall; |
198 | } else { | 226 | } else { |
199 | md.tile = Tile::Floor; | 227 | tile = Tile::Floor; |
200 | } | 228 | } |
229 | } | ||
230 | for (MapData& md : chunk.data) { | ||
201 | md.dirtyRender = true; | 231 | md.dirtyRender = true; |
202 | } | 232 | } |
203 | } | 233 | } |
@@ -207,6 +237,10 @@ public: | |||
207 | 237 | ||
208 | for (int y = 0; y < CHUNK_HEIGHT; y++) { | 238 | for (int y = 0; y < CHUNK_HEIGHT; y++) { |
209 | std::copy( | 239 | std::copy( |
240 | std::next(std::begin(chunk.tiles), y*CHUNK_WIDTH), | ||
241 | std::next(std::begin(chunk.tiles), (y+1)*CHUNK_WIDTH), | ||
242 | std::next(std::begin(loadedTiles_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH)); | ||
243 | std::copy( | ||
210 | std::next(std::begin(chunk.data), y*CHUNK_WIDTH), | 244 | std::next(std::begin(chunk.data), y*CHUNK_WIDTH), |
211 | std::next(std::begin(chunk.data), (y+1)*CHUNK_WIDTH), | 245 | std::next(std::begin(chunk.data), (y+1)*CHUNK_WIDTH), |
212 | std::next(std::begin(loaded_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH)); | 246 | std::next(std::begin(loaded_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH)); |
@@ -215,7 +249,55 @@ public: | |||
215 | unloadedLitTiles_ -= chunk.litTiles; | 249 | unloadedLitTiles_ -= chunk.litTiles; |
216 | } | 250 | } |
217 | } | 251 | } |
252 | } | ||
218 | 253 | ||
254 | void markDirtyAround(int x, int y) { | ||
255 | if (x > left_) { | ||
256 | if (y > top_) { | ||
257 | markDirty(x-1, y-1); | ||
258 | } | ||
259 | markDirty(x-1, y ); | ||
260 | if (y < top_+height_-1) { | ||
261 | markDirty(x-1, y+1); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | if (y > top_) { | ||
266 | markDirty(x , y-1); | ||
267 | } | ||
268 | markDirty(x , y ); | ||
269 | if (y < top_+height_-1) { | ||
270 | markDirty(x , y+1); | ||
271 | } | ||
272 | |||
273 | if (x < left_+width_-1) { | ||
274 | if (y > top_) { | ||
275 | markDirty(x+1, y-1); | ||
276 | } | ||
277 | markDirty(x+1, y ); | ||
278 | if (y < top_+height_-1) { | ||
279 | markDirty(x+1, y+1); | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | void markDirty(int x, int y) { | ||
285 | size_t index = (x-left_)+(y-top_)*width_; | ||
286 | if (!dirtySet_[index]) { | ||
287 | dirtySet_[index] = true; | ||
288 | dirtyTiles_.emplace_back(x,y); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | const std::vector<coord> getDirty() const { | ||
293 | return dirtyTiles_; | ||
294 | } | ||
295 | |||
296 | void resetDirty() { | ||
297 | for (auto [x,y] : dirtyTiles_) { | ||
298 | dirtySet_[(x-left_)+(y-top_)*width_] = false; | ||
299 | } | ||
300 | dirtyTiles_.clear(); | ||
219 | } | 301 | } |
220 | 302 | ||
221 | private: | 303 | private: |
@@ -228,6 +310,7 @@ private: | |||
228 | int topmostChunk_; | 310 | int topmostChunk_; |
229 | int chunksHoriz_; | 311 | int chunksHoriz_; |
230 | int chunksVert_; | 312 | int chunksVert_; |
313 | std::vector<Tile> loadedTiles_; | ||
231 | std::vector<MapData> loaded_; | 314 | std::vector<MapData> loaded_; |
232 | 315 | ||
233 | std::vector<Chunk> chunks_; | 316 | std::vector<Chunk> chunks_; |
@@ -235,6 +318,9 @@ private: | |||
235 | std::map<int, std::map<int, size_t>> chunkByPos_; // chunkByPos_[X][Y] | 318 | std::map<int, std::map<int, size_t>> chunkByPos_; // chunkByPos_[X][Y] |
236 | 319 | ||
237 | int unloadedLitTiles_ = 0; | 320 | int unloadedLitTiles_ = 0; |
321 | |||
322 | std::vector<coord> dirtyTiles_; | ||
323 | std::vector<bool> dirtySet_; | ||
238 | }; | 324 | }; |
239 | 325 | ||
240 | #endif /* end of include guard: MAP_H_3AB00D12 */ | 326 | #endif /* end of include guard: MAP_H_3AB00D12 */ |
diff --git a/src/renderer.cpp b/src/renderer.cpp index c8c1746..9744e70 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp | |||
@@ -173,7 +173,7 @@ void Renderer::renderGame( | |||
173 | 173 | ||
174 | if (draw) | 174 | if (draw) |
175 | { | 175 | { |
176 | if (game.map.at(x,y).tile != Tile::Wall) { | 176 | if (game.map.tile(x,y) != Tile::Wall) { |
177 | SDL_Rect tileRect {17 * 16, 15 * 16, 16, 16}; | 177 | SDL_Rect tileRect {17 * 16, 15 * 16, 16, 16}; |
178 | SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect); | 178 | SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect); |
179 | 179 | ||
@@ -192,7 +192,7 @@ void Renderer::renderGame( | |||
192 | SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect); | 192 | SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect); |
193 | } | 193 | } |
194 | 194 | ||
195 | if (game.map.at(x,y).tile == Tile::Lamp) { | 195 | if (game.map.tile(x,y) == Tile::Lamp) { |
196 | SDL_RenderCopy(ren_.get(), lamp_.get(), nullptr, &rect); | 196 | SDL_RenderCopy(ren_.get(), lamp_.get(), nullptr, &rect); |
197 | } | 197 | } |
198 | 198 | ||