summary refs log tree commit diff stats
path: root/src/game.cpp
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2022-03-17 15:28:22 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2022-03-17 15:28:22 -0400
commit5324adfe51f1348fc97fe2ee0ca4e4bbd2a6ad64 (patch)
tree6b3ff32f9ad2764405fd73a70e15c960a076ed00 /src/game.cpp
parente0fd87411eb5368fee47e268ae03d073293e58c3 (diff)
downloadether-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.
Diffstat (limited to 'src/game.cpp')
-rw-r--r--src/game.cpp195
1 files changed, 105 insertions, 90 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
36inline bool isTileSetOrNotLit(const Map& map, int x, int y) 36inline 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
41inline bool isTileSet(const Map& map, int x, int y, Tile val = Tile::Wall) 41inline 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
46inline void incrementIfSet(const Game& game, int& count, int x, int y, Tile val = Tile::Wall) 46inline 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
58inline 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
96void 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
58void Game::tick( 108void 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
117void Game::tick(bool onlyDark) 135void Game::tick(bool onlyDark)
@@ -127,11 +145,11 @@ void Game::tick(bool onlyDark)
127 145
128bool Game::movePlayer(int x, int y) 146bool 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
573void Game::performDash() { 592void 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);