]> git.localhorst.tv Git - blank.git/blob - src/world.cpp
world class for multiple chunks
[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 const BlockType BlockType::DEFAULT;
10
11 void BlockType::FillVBO(
12         const glm::vec3 &pos,
13         std::vector<glm::vec3> &vertices,
14         std::vector<glm::vec3> &colors,
15         std::vector<glm::vec3> &normals
16 ) const {
17         vertices.emplace_back(pos.x    , pos.y    , pos.z + 1); // front
18         vertices.emplace_back(pos.x + 1, pos.y    , pos.z + 1);
19         vertices.emplace_back(pos.x    , pos.y + 1, pos.z + 1);
20         vertices.emplace_back(pos.x + 1, pos.y    , pos.z + 1);
21         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z + 1);
22         vertices.emplace_back(pos.x    , pos.y + 1, pos.z + 1);
23         vertices.emplace_back(pos.x    , pos.y    , pos.z    ); // back
24         vertices.emplace_back(pos.x    , pos.y + 1, pos.z    );
25         vertices.emplace_back(pos.x + 1, pos.y    , pos.z    );
26         vertices.emplace_back(pos.x + 1, pos.y    , pos.z    );
27         vertices.emplace_back(pos.x    , pos.y + 1, pos.z    );
28         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z    );
29         vertices.emplace_back(pos.x    , pos.y + 1, pos.z    ); // top
30         vertices.emplace_back(pos.x    , pos.y + 1, pos.z + 1);
31         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z    );
32         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z    );
33         vertices.emplace_back(pos.x    , pos.y + 1, pos.z + 1);
34         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z + 1);
35         vertices.emplace_back(pos.x    , pos.y    , pos.z    ); // bottom
36         vertices.emplace_back(pos.x + 1, pos.y    , pos.z    );
37         vertices.emplace_back(pos.x    , pos.y    , pos.z + 1);
38         vertices.emplace_back(pos.x + 1, pos.y    , pos.z    );
39         vertices.emplace_back(pos.x + 1, pos.y    , pos.z + 1);
40         vertices.emplace_back(pos.x    , pos.y    , pos.z + 1);
41         vertices.emplace_back(pos.x    , pos.y    , pos.z    ); // left
42         vertices.emplace_back(pos.x    , pos.y    , pos.z + 1);
43         vertices.emplace_back(pos.x    , pos.y + 1, pos.z    );
44         vertices.emplace_back(pos.x    , pos.y + 1, pos.z    );
45         vertices.emplace_back(pos.x    , pos.y    , pos.z + 1);
46         vertices.emplace_back(pos.x    , pos.y + 1, pos.z + 1);
47         vertices.emplace_back(pos.x + 1, pos.y    , pos.z    ); // right
48         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z    );
49         vertices.emplace_back(pos.x + 1, pos.y    , pos.z + 1);
50         vertices.emplace_back(pos.x + 1, pos.y    , pos.z + 1);
51         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z    );
52         vertices.emplace_back(pos.x + 1, pos.y + 1, pos.z + 1);
53
54         colors.insert(colors.end(), 6 * 6, color);
55
56         normals.insert(normals.end(), 6, glm::vec3( 0.0f,  0.0f,  1.0f)); // front
57         normals.insert(normals.end(), 6, glm::vec3( 0.0f,  0.0f, -1.0f)); // back
58         normals.insert(normals.end(), 6, glm::vec3( 0.0f,  1.0f,  0.0f)); // top
59         normals.insert(normals.end(), 6, glm::vec3( 0.0f, -1.0f,  0.0f)); // bottom
60         normals.insert(normals.end(), 6, glm::vec3(-1.0f,  0.0f,  0.0f)); // left
61         normals.insert(normals.end(), 6, glm::vec3( 1.0f,  0.0f,  0.0f)); // right
62 }
63
64
65 BlockTypeRegistry::BlockTypeRegistry() {
66         Add(BlockType::DEFAULT);
67 }
68
69 int BlockTypeRegistry::Add(const BlockType &t) {
70         int id = types.size();
71         types.push_back(t);
72         types.back().id = id;
73         return id;
74 }
75
76
77 Chunk::Chunk()
78 : blocks(Size())
79 , model()
80 , transform(1.0f)
81 , dirty(false) {
82
83 }
84
85 Chunk::Chunk(Chunk &&other)
86 : blocks(std::move(other.blocks))
87 , model(std::move(other.model))
88 , transform(other.transform)
89 , dirty(other.dirty) {
90
91 }
92
93 Chunk &Chunk::operator =(Chunk &&other) {
94         blocks = std::move(other.blocks);
95         model = std::move(other.model);
96         transform = other.transform;
97         dirty = other.dirty;
98         return *this;
99 }
100
101
102 void Chunk::Draw() {
103         if (dirty) {
104                 Update();
105         }
106         model.Draw();
107 }
108
109
110 bool Chunk::Intersection(
111         const Ray &ray,
112         const glm::mat4 &M,
113         int *blkid,
114         float *dist,
115         glm::vec3 *normal) const {
116         { // rough check
117                 const AABB bb{{0, 0, 0}, {Width(), Height(), Depth()}};
118                 if (!blank::Intersection(ray, bb, M)) {
119                         return false;
120                 }
121         }
122
123         if (!blkid && !dist && !normal) {
124                 return true;
125         }
126
127         // TODO: should be possible to heavily optimize this
128         int id = 0;
129         int closest_id = -1;
130         float closest_dist = std::numeric_limits<float>::infinity();
131         glm::vec3 closest_normal(0, 1, 0);
132         for (int z = 0; z < Depth(); ++z) {
133                 for (int y = 0; y < Height(); ++y) {
134                         for (int x = 0; x < Width(); ++x, ++id) {
135                                 if (!blocks[id].type->visible) {
136                                         continue;
137                                 }
138                                 const AABB bb{{x, y, z}, {x+1, y+1, z+1}};
139                                 float cur_dist;
140                                 glm::vec3 cur_norm;
141                                 if (blank::Intersection(ray, bb, M, &cur_dist, &cur_norm)) {
142                                         if (cur_dist < closest_dist) {
143                                                 closest_id = id;
144                                                 closest_dist = cur_dist;
145                                                 closest_normal = cur_norm;
146                                         }
147                                 }
148                         }
149                 }
150         }
151
152         if (closest_id < 0) {
153                 return false;
154         }
155
156         if (blkid) {
157                 *blkid = closest_id;
158         }
159         if (dist) {
160                 *dist = closest_dist;
161         }
162         if (normal) {
163                 *normal = closest_normal;
164         }
165         return true;
166 }
167
168 void Chunk::Position(const glm::vec3 &pos) {
169         position = pos;
170         transform = glm::translate(pos * Extent());
171 }
172
173
174 int Chunk::VertexCount() const {
175         // TODO: query blocks as soon as type shapes are implemented
176         return Size() * 6 * 6;
177 }
178
179 void Chunk::Update() {
180         model.Clear();
181         model.Reserve(VertexCount());
182
183         for (int i = 0; i < Size(); ++i) {
184                 if (blocks[i].type->visible) {
185                         blocks[i].type->FillModel(ToCoords(i), model);
186                 }
187         }
188
189         model.Invalidate();
190         dirty = false;
191 }
192
193
194 World::World()
195 : blockType()
196 , chunks() {
197         blockType.Add(BlockType(true, glm::vec3(1, 1, 1)));
198         blockType.Add(BlockType(true, glm::vec3(1, 0, 0)));
199         blockType.Add(BlockType(true, glm::vec3(0, 1, 0)));
200         blockType.Add(BlockType(true, glm::vec3(0, 0, 1)));
201 }
202
203
204 void World::Generate() {
205         for (int z = -1; z < 2; ++z) {
206                 for (int y = -1; y < 2; ++y) {
207                         for (int x = -1; x < 2; ++x) {
208                                 Generate(glm::vec3(x, y, z));
209                         }
210                 }
211         }
212 }
213
214 Chunk &World::Generate(const glm::vec3 &pos) {
215         chunks.emplace_back();
216         Chunk &chunk = chunks.back();
217         chunk.Position(pos);
218         chunk.BlockAt(glm::vec3(0, 0, 0)) = Block(blockType[4]);
219         chunk.BlockAt(glm::vec3(0, 0, 1)) = Block(blockType[1]);
220         chunk.BlockAt(glm::vec3(1, 0, 0)) = Block(blockType[2]);
221         chunk.BlockAt(glm::vec3(1, 0, 1)) = Block(blockType[3]);
222         chunk.BlockAt(glm::vec3(2, 0, 0)) = Block(blockType[4]);
223         chunk.BlockAt(glm::vec3(2, 0, 1)) = Block(blockType[1]);
224         chunk.BlockAt(glm::vec3(3, 0, 0)) = Block(blockType[2]);
225         chunk.BlockAt(glm::vec3(3, 0, 1)) = Block(blockType[3]);
226         chunk.BlockAt(glm::vec3(2, 0, 2)) = Block(blockType[4]);
227         chunk.BlockAt(glm::vec3(2, 0, 3)) = Block(blockType[1]);
228         chunk.BlockAt(glm::vec3(3, 0, 2)) = Block(blockType[2]);
229         chunk.BlockAt(glm::vec3(3, 0, 3)) = Block(blockType[3]);
230         chunk.BlockAt(glm::vec3(1, 1, 0)) = Block(blockType[1]);
231         chunk.BlockAt(glm::vec3(1, 1, 1)) = Block(blockType[4]);
232         chunk.BlockAt(glm::vec3(2, 1, 1)) = Block(blockType[3]);
233         chunk.BlockAt(glm::vec3(2, 2, 1)) = Block(blockType[2]);
234         chunk.Invalidate();
235         return chunk;
236 }
237
238 bool World::Intersection(
239                 const Ray &ray,
240                 const glm::mat4 &M,
241                 Chunk **chunk,
242                 int *blkid,
243                 float *dist,
244                 glm::vec3 *normal) {
245         Chunk *closest_chunk = nullptr;
246         int closest_blkid = -1;
247         float closest_dist = std::numeric_limits<float>::infinity();
248         glm::vec3 closest_normal;
249
250         for (Chunk &cur_chunk : chunks) {
251                 int cur_blkid;
252                 float cur_dist;
253                 glm::vec3 cur_normal;
254                 if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(), &cur_blkid, &cur_dist, &cur_normal)) {
255                         if (cur_dist < closest_dist) {
256                                 closest_chunk = &cur_chunk;
257                                 closest_blkid = cur_blkid;
258                                 closest_dist = cur_dist;
259                                 closest_normal = cur_normal;
260                         }
261                 }
262         }
263
264         if (chunk) {
265                 *chunk = closest_chunk;
266         }
267         if (blkid) {
268                 *blkid = closest_blkid;
269         }
270         if (dist) {
271                 *dist = closest_dist;
272         }
273         if (normal) {
274                 *normal = closest_normal;
275         }
276         return closest_chunk;
277 }
278
279
280 Chunk &World::Next(const Chunk &to, const glm::vec3 &dir) {
281         const glm::vec3 tgt_pos = to.Position() + dir;
282         for (Chunk &chunk : chunks) {
283                 if (chunk.Position() == tgt_pos) {
284                         return chunk;
285                 }
286         }
287         return Generate(tgt_pos);
288 }
289
290 }