diff options
Diffstat (limited to 'src/map.h')
-rw-r--r-- | src/map.h | 184 |
1 files changed, 160 insertions, 24 deletions
diff --git a/src/map.h b/src/map.h index 329553c..d28b8d4 100644 --- a/src/map.h +++ b/src/map.h | |||
@@ -3,23 +3,62 @@ | |||
3 | 3 | ||
4 | #include <vector> | 4 | #include <vector> |
5 | #include <algorithm> | 5 | #include <algorithm> |
6 | #include <array> | ||
7 | #include <list> | ||
8 | #include <map> | ||
9 | #include <random> | ||
10 | #include "consts.h" | ||
6 | 11 | ||
7 | template <typename T> | 12 | using coord = std::tuple<int, int>; |
8 | class Map { | ||
9 | public: | ||
10 | 13 | ||
11 | Map( | 14 | enum class Tile { |
12 | int left, | 15 | Floor, |
13 | int top, | 16 | Wall, |
14 | int width, | 17 | Dust, |
15 | int height) : | 18 | Lamp |
16 | left_(left), | 19 | }; |
17 | top_(top), | 20 | |
18 | width_(width), | 21 | enum class Source { |
19 | height_(height), | 22 | None, |
20 | data_(width_*height_) | 23 | Dust, |
21 | { | 24 | Lamp, |
25 | Player | ||
26 | }; | ||
27 | |||
28 | struct MapData { | ||
29 | Tile tile = Tile::Floor; | ||
30 | bool lit = false; | ||
31 | bool wasLit = false; | ||
32 | size_t dustLife = 0; | ||
33 | Source lightType = Source::None; | ||
34 | int lightRadius = 0; | ||
35 | std::set<coord> litTiles; | ||
36 | int renderId = -1; | ||
37 | bool dirtyRender = true; | ||
38 | }; | ||
39 | |||
40 | struct Chunk { | ||
41 | std::array<MapData, CHUNK_WIDTH*CHUNK_HEIGHT> data; | ||
42 | int litTiles = 0; | ||
43 | int x; | ||
44 | int y; | ||
45 | }; | ||
46 | |||
47 | inline void toChunkPos(int x, int y, int& cx, int& cy) { | ||
48 | cx = x / CHUNK_WIDTH; | ||
49 | cy = y / CHUNK_HEIGHT; | ||
50 | if (x < 0) { | ||
51 | cx *= -1; | ||
52 | cx--; | ||
53 | } | ||
54 | if (y < 0) { | ||
55 | cy *= -1; | ||
56 | cy--; | ||
22 | } | 57 | } |
58 | } | ||
59 | |||
60 | class Map { | ||
61 | public: | ||
23 | 62 | ||
24 | inline int getLeft() const | 63 | inline int getLeft() const |
25 | { | 64 | { |
@@ -69,27 +108,27 @@ public: | |||
69 | (y < top_ + height_); | 108 | (y < top_ + height_); |
70 | } | 109 | } |
71 | 110 | ||
72 | inline const T& at(int x, int y) const | 111 | inline const MapData& at(int x, int y) const |
73 | { | 112 | { |
74 | return data_.at((x - left_) + width_ * (y - top_)); | 113 | return loaded_.at((x - left_) + width_ * (y - top_)); |
75 | } | 114 | } |
76 | 115 | ||
77 | inline T& at(int x, int y) | 116 | inline MapData& at(int x, int y) |
78 | { | 117 | { |
79 | return const_cast<T&>(static_cast<const Map&>(*this).at(x, y)); | 118 | return const_cast<MapData&>(static_cast<const Map&>(*this).at(x, y)); |
80 | } | 119 | } |
81 | 120 | ||
82 | inline const std::vector<T>& data() const | 121 | inline const std::vector<MapData>& data() const |
83 | { | 122 | { |
84 | return data_; | 123 | return loaded_; |
85 | } | 124 | } |
86 | 125 | ||
87 | inline std::vector<T>& data() | 126 | inline std::vector<MapData>& data() |
88 | { | 127 | { |
89 | return data_; | 128 | return loaded_; |
90 | } | 129 | } |
91 | 130 | ||
92 | void resize(int newLeft, int newTop, int newWidth, int newHeight) | 131 | /*void resize(int newLeft, int newTop, int newWidth, int newHeight) |
93 | { | 132 | { |
94 | std::vector<T> newData(newWidth * newHeight); | 133 | std::vector<T> newData(newWidth * newHeight); |
95 | 134 | ||
@@ -112,6 +151,96 @@ public: | |||
112 | width_ = newWidth; | 151 | width_ = newWidth; |
113 | height_ = newHeight; | 152 | height_ = newHeight; |
114 | data_.swap(newData); | 153 | data_.swap(newData); |
154 | }*/ | ||
155 | |||
156 | void load(int newLeftChunk, int newTopChunk, int newWidthChunks, int newHeightChunks, std::mt19937& rng) { | ||
157 | // Flush the currently loaded data as long as there is any (this isn't the first load). | ||
158 | if (!loaded_.empty()) { | ||
159 | std::vector<size_t> touchedChunks; | ||
160 | |||
161 | for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { | ||
162 | for (int chunkX = 0; chunkX < chunksHoriz_; chunkX++) { | ||
163 | size_t chunkIndex = chunkByPos_.at(leftmostChunk_ + chunkX).at(topmostChunk_ + chunkY); | ||
164 | touchedChunks.push_back(chunkIndex); | ||
165 | |||
166 | Chunk& chunk = chunks_.at(chunkIndex); | ||
167 | chunk.litTiles = 0; | ||
168 | |||
169 | int startX = chunkX * CHUNK_WIDTH; | ||
170 | int startY = chunkY * CHUNK_HEIGHT; | ||
171 | for (int y=0; y<CHUNK_HEIGHT; y++) { | ||
172 | for (int x=0; x<CHUNK_WIDTH; x++) { | ||
173 | chunk.data[x+y*CHUNK_WIDTH] = loaded_[startX+x+(startY+y)*width_]; | ||
174 | if (chunk.data[x+y*CHUNK_WIDTH].lit) { | ||
175 | chunk.litTiles++; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // Destroy any completely unlit chunks. | ||
183 | for (size_t chunkIndex : touchedChunks) { | ||
184 | if (chunks_[chunkIndex].litTiles == 0) { | ||
185 | chunkByPos_[chunks_[chunkIndex].x].erase(chunks_[chunkIndex].y); | ||
186 | freeList_.push_back(chunkIndex); | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | leftmostChunk_ = newLeftChunk; | ||
192 | topmostChunk_ = newTopChunk; | ||
193 | chunksHoriz_ = newWidthChunks; | ||
194 | chunksVert_ = newHeightChunks; | ||
195 | left_ = newLeftChunk * CHUNK_WIDTH; | ||
196 | top_ = newTopChunk * CHUNK_HEIGHT; | ||
197 | width_ = chunksHoriz_ * CHUNK_WIDTH; | ||
198 | height_ = chunksVert_ * CHUNK_HEIGHT; | ||
199 | loaded_ = std::vector<MapData>(width_ * height_); | ||
200 | |||
201 | // Load in the requested chunks. | ||
202 | for (int chunkY = 0; chunkY < chunksVert_; chunkY++) { | ||
203 | for (int chunkX = 0; chunkX < chunksHoriz_; chunkX++) { | ||
204 | // Instantiate a new chunk if necessary. | ||
205 | if (!chunkByPos_[leftmostChunk_ + chunkX].count(topmostChunk_ + chunkY)) { | ||
206 | size_t chunkIndex; | ||
207 | if (!freeList_.empty()) { | ||
208 | chunkIndex = freeList_.front(); | ||
209 | freeList_.pop_front(); | ||
210 | } else { | ||
211 | chunkIndex = chunks_.size(); | ||
212 | chunks_.emplace_back(); | ||
213 | } | ||
214 | chunkByPos_[leftmostChunk_ + chunkX][topmostChunk_ + chunkY] = chunkIndex; | ||
215 | |||
216 | Chunk& chunk = chunks_[chunkIndex]; | ||
217 | chunk.x = leftmostChunk_ + chunkX; | ||
218 | chunk.y = topmostChunk_ + chunkY; | ||
219 | |||
220 | for (MapData& md : chunk.data) | ||
221 | { | ||
222 | if (std::bernoulli_distribution(0.5)(rng)) | ||
223 | { | ||
224 | md.tile = Tile::Wall; | ||
225 | } else { | ||
226 | md.tile = Tile::Floor; | ||
227 | } | ||
228 | md.dirtyRender = true; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | size_t chunkIndex = chunkByPos_[leftmostChunk_ + chunkX][topmostChunk_ + chunkY]; | ||
233 | Chunk& chunk = chunks_[chunkIndex]; | ||
234 | |||
235 | for (int y = 0; y < CHUNK_HEIGHT; y++) { | ||
236 | std::copy( | ||
237 | std::next(std::begin(chunk.data), y*CHUNK_WIDTH), | ||
238 | std::next(std::begin(chunk.data), (y+1)*CHUNK_WIDTH), | ||
239 | std::next(std::begin(loaded_), (chunkY*CHUNK_HEIGHT + y)*width_ + chunkX*CHUNK_WIDTH)); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
115 | } | 244 | } |
116 | 245 | ||
117 | private: | 246 | private: |
@@ -120,8 +249,15 @@ private: | |||
120 | int top_; | 249 | int top_; |
121 | int width_; | 250 | int width_; |
122 | int height_; | 251 | int height_; |
252 | int leftmostChunk_; | ||
253 | int topmostChunk_; | ||
254 | int chunksHoriz_; | ||
255 | int chunksVert_; | ||
256 | std::vector<MapData> loaded_; | ||
123 | 257 | ||
124 | std::vector<T> data_; | 258 | std::vector<Chunk> chunks_; |
259 | std::list<size_t> freeList_; | ||
260 | std::map<int, std::map<int, size_t>> chunkByPos_; // chunkByPos_[X][Y] | ||
125 | }; | 261 | }; |
126 | 262 | ||
127 | #endif /* end of include guard: MAP_H_3AB00D12 */ | 263 | #endif /* end of include guard: MAP_H_3AB00D12 */ |