]> git.localhorst.tv Git - blank.git/blob - src/world.cpp
decrease block id size
[blank.git] / src / world.cpp
1 #include "world.hpp"
2
3 #include <limits>
4 #include <glm/gtx/transform.hpp>
5
6
7 namespace blank {
8
9 World::World()
10 : blockType()
11 , blockShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }})
12 , stairShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}, { 0.0f, 0.0f })
13 , slabShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.0f, 0.5f }})
14 , blockNoise(0)
15 , colorNoise(1)
16 , player()
17 , player_chunk(0, 0, 0)
18 , loaded()
19 , to_generate()
20 , to_free() {
21         blockType.Add(BlockType{ true, { 1.0f, 1.0f, 1.0f }, &blockShape }); // white block
22         blockType.Add(BlockType{ true, { 1.0f, 1.0f, 1.0f }, &stairShape }); // white stair
23         blockType.Add(BlockType{ true, { 1.0f, 1.0f, 1.0f }, &slabShape }); // white slab
24         blockType.Add(BlockType{ true, { 1.0f, 0.0f, 0.0f }, &blockShape }); // red block
25         blockType.Add(BlockType{ true, { 1.0f, 0.0f, 0.0f }, &stairShape }); // red stair
26         blockType.Add(BlockType{ true, { 1.0f, 0.0f, 0.0f }, &slabShape }); // red slab
27         blockType.Add(BlockType{ true, { 0.0f, 1.0f, 0.0f }, &blockShape }); // green block
28         blockType.Add(BlockType{ true, { 0.0f, 1.0f, 0.0f }, &stairShape }); // green stair
29         blockType.Add(BlockType{ true, { 0.0f, 1.0f, 0.0f }, &slabShape }); // green slab
30         blockType.Add(BlockType{ true, { 0.0f, 0.0f, 1.0f }, &blockShape }); // blue block
31         blockType.Add(BlockType{ true, { 0.0f, 0.0f, 1.0f }, &stairShape }); // blue stair
32         blockType.Add(BlockType{ true, { 0.0f, 0.0f, 1.0f }, &slabShape }); // blue slab
33
34         player.Position({ 4.0f, 4.0f, 4.0f });
35 }
36
37
38 namespace {
39
40 bool ChunkLess(const Chunk &a, const Chunk &b) {
41         return
42                 a.Position().x * a.Position().x +
43                 a.Position().y * a.Position().y +
44                 a.Position().z * a.Position().z <
45                 b.Position().x * b.Position().x +
46                 b.Position().y * b.Position().y +
47                 b.Position().z * b.Position().z;
48 }
49
50 }
51
52 void World::Generate(const Chunk::Pos &from, const Chunk::Pos &to) {
53         for (int z = from.z; z < to.z; ++z) {
54                 for (int y = from.y; y < to.y; ++y) {
55                         for (int x = from.x; x < to.x; ++x) {
56                                 Block::Pos pos{float(x), float(y), float(z)};
57                                 if (ChunkAvailable(pos)) {
58                                         continue;
59                                 } else if (x == 0 && y == 0 && z == 0) {
60                                         loaded.emplace_back(blockType);
61                                         loaded.back().Position(pos);
62                                         Generate(loaded.back());
63                                 } else {
64                                         to_generate.emplace_back(blockType);
65                                         to_generate.back().Position(pos);
66                                 }
67                         }
68                 }
69         }
70         to_generate.sort(ChunkLess);
71 }
72
73 void World::Generate(Chunk &chunk) {
74         chunk.Allocate();
75         Chunk::Pos pos(chunk.Position());
76         glm::vec3 coords(pos * Chunk::Extent());
77         if (pos.x == 0 && pos.y == 0 && pos.z == 0) {
78                 for (size_t i = 1; i < blockType.Size(); ++i) {
79                         chunk.BlockAt(i) = Block(i);
80                         chunk.BlockAt(i + 257) = Block(i);
81                         chunk.BlockAt(i + 514) = Block(i);
82                 }
83         } else {
84                 for (int z = 0; z < Chunk::Depth(); ++z) {
85                         for (int y = 0; y < Chunk::Height(); ++y) {
86                                 for (int x = 0; x < Chunk::Width(); ++x) {
87                                         Block::Pos block_pos{float(x), float(y), float(z)};
88                                         glm::vec3 gen_pos = (coords + block_pos) / 64.0f;
89                                         float val = blockNoise(gen_pos);
90                                         if (val > 0.8f) {
91                                                 int col_val = int((colorNoise(gen_pos) + 1.0f) * 2.0f) % 4;
92                                                 chunk.BlockAt(block_pos) = Block(col_val * 3 + 1);
93                                         }
94                                 }
95                         }
96                 }
97         }
98         chunk.Invalidate();
99 }
100
101 bool World::Intersection(
102                 const Ray &ray,
103                 const glm::mat4 &M,
104                 Chunk **chunk,
105                 int *blkid,
106                 float *dist,
107                 glm::vec3 *normal) {
108         Chunk *closest_chunk = nullptr;
109         int closest_blkid = -1;
110         float closest_dist = std::numeric_limits<float>::infinity();
111         glm::vec3 closest_normal;
112
113         for (Chunk &cur_chunk : loaded) {
114                 int cur_blkid;
115                 float cur_dist;
116                 glm::vec3 cur_normal;
117                 if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(player.ChunkCoords()), &cur_blkid, &cur_dist, &cur_normal)) {
118                         if (cur_dist < closest_dist) {
119                                 closest_chunk = &cur_chunk;
120                                 closest_blkid = cur_blkid;
121                                 closest_dist = cur_dist;
122                                 closest_normal = cur_normal;
123                         }
124                 }
125         }
126
127         if (chunk) {
128                 *chunk = closest_chunk;
129         }
130         if (blkid) {
131                 *blkid = closest_blkid;
132         }
133         if (dist) {
134                 *dist = closest_dist;
135         }
136         if (normal) {
137                 *normal = closest_normal;
138         }
139         return closest_chunk;
140 }
141
142
143 Chunk *World::ChunkLoaded(const Chunk::Pos &pos) {
144         for (Chunk &chunk : loaded) {
145                 if (chunk.Position() == pos) {
146                         return &chunk;
147                 }
148         }
149         return nullptr;
150 }
151
152 Chunk *World::ChunkQueued(const Chunk::Pos &pos) {
153         for (Chunk &chunk : to_generate) {
154                 if (chunk.Position() == pos) {
155                         return &chunk;
156                 }
157         }
158         return nullptr;
159 }
160
161 Chunk *World::ChunkAvailable(const Chunk::Pos &pos) {
162         Chunk *chunk = ChunkLoaded(pos);
163         if (chunk) return chunk;
164
165         return ChunkQueued(pos);
166 }
167
168 Chunk &World::Next(const Chunk &to, const glm::tvec3<int> &dir) {
169         const Chunk::Pos tgt_pos = to.Position() + dir;
170
171         Chunk *chunk = ChunkLoaded(tgt_pos);
172         if (chunk) {
173                 return *chunk;
174         }
175
176         chunk = ChunkQueued(tgt_pos);
177         if (chunk) {
178                 Generate(*chunk);
179                 return *chunk;
180         }
181
182         loaded.emplace_back(blockType);
183         loaded.back().Position(tgt_pos);
184         Generate(loaded.back());
185         return loaded.back();
186 }
187
188
189 void World::Update(int dt) {
190         player.Update(dt);
191
192         CheckChunkGeneration();
193 }
194
195 void World::CheckChunkGeneration() {
196         if (player.ChunkCoords() != player_chunk) {
197                 player_chunk = player.ChunkCoords();
198
199                 constexpr int max_dist = 8;
200                 // unload far away chunks
201                 for (auto iter(loaded.begin()), end(loaded.end()); iter != end;) {
202                         if (std::abs(player_chunk.x - iter->Position().x) > max_dist
203                                         || std::abs(player_chunk.y - iter->Position().y) > max_dist
204                                         || std::abs(player_chunk.z - iter->Position().z) > max_dist) {
205                                 auto saved = iter;
206                                 ++iter;
207                                 to_free.splice(to_free.end(), loaded, saved);
208                         } else {
209                                 ++iter;
210                         }
211                 }
212                 // abort far away queued chunks
213                 for (auto iter(to_generate.begin()), end(to_generate.end()); iter != end;) {
214                         if (std::abs(player_chunk.x - iter->Position().x) > max_dist
215                                         || std::abs(player_chunk.y - iter->Position().y) > max_dist
216                                         || std::abs(player_chunk.z - iter->Position().z) > max_dist) {
217                                 iter = to_generate.erase(iter);
218                         } else {
219                                 ++iter;
220                         }
221                 }
222                 // add missing new chunks
223                 const Chunk::Pos offset(max_dist, max_dist, max_dist);
224                 Generate(player_chunk - offset, player_chunk + offset);
225         }
226
227         if (!to_generate.empty()) {
228                 Generate(to_generate.front());
229                 loaded.splice(loaded.end(), to_generate, to_generate.begin());
230         }
231
232         if (!to_free.empty()) {
233                 to_free.pop_front();
234         }
235 }
236
237
238 void World::Render(DirectionalLighting &program) {
239         program.SetLightDirection({ -1.0f, -3.0f, -2.0f });
240         program.SetView(glm::inverse(player.Transform(player.ChunkCoords())));
241
242         for (Chunk &chunk : LoadedChunks()) {
243                 glm::mat4 m(chunk.Transform(player.ChunkCoords()));
244                 program.SetM(m);
245                 glm::mat4 mvp(program.GetVP() * m);
246                 if (!CullTest(Chunk::Bounds(), mvp)) {
247                         chunk.Draw();
248                 }
249         }
250 }
251
252 }