]> git.localhorst.tv Git - blank.git/blob - World.cpp
cb8186d5f1f10ce27e337030215d060fbe1ee931
[blank.git] / World.cpp
1 #include "World.hpp"
2
3 #include "WorldCollision.hpp"
4 #include "../graphics/BlockLighting.hpp"
5 #include "../graphics/DirectionalLighting.hpp"
6
7 #include <iostream>
8 #include <limits>
9 #include <glm/gtx/transform.hpp>
10
11
12 namespace blank {
13
14 World::World(const Config &config)
15 : blockType()
16 , blockShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }})
17 , stairShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }}, { 0.0f, 0.0f })
18 , slabShape({{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.0f, 0.5f }})
19 , generate(config.gen)
20 , chunks(config.load, blockType, generate)
21 , player()
22 , entities()
23 , light_direction(config.light_direction)
24 , fog_density(config.fog_density) {
25         BlockType::Faces block_fill = {  true,  true,  true,  true,  true,  true };
26         BlockType::Faces slab_fill  = { false,  true, false, false, false, false };
27         BlockType::Faces stair_fill = { false,  true, false, false, false,  true };
28
29         { // white block
30                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &blockShape);
31                 type.block_light = true;
32                 type.fill = block_fill;
33                 blockType.Add(type);
34         }
35         { // white slab
36                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &slabShape);
37                 type.block_light = true;
38                 type.fill = slab_fill;
39                 blockType.Add(type);
40         }
41         { // white stair
42                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &stairShape);
43                 type.block_light = true;
44                 type.fill = stair_fill;
45                 blockType.Add(type);
46         }
47
48         { // red block
49                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &blockShape);
50                 type.block_light = true;
51                 type.fill = block_fill;
52                 blockType.Add(type);
53         }
54         { // red slab
55                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &slabShape);
56                 type.block_light = true;
57                 type.fill = slab_fill;
58                 blockType.Add(type);
59         }
60         { // red stair
61                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &stairShape);
62                 type.block_light = true;
63                 type.fill = stair_fill;
64                 blockType.Add(type);
65         }
66
67         { // green block
68                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &blockShape);
69                 type.block_light = true;
70                 type.fill = block_fill;
71                 blockType.Add(type);
72         }
73         { // green slab
74                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &slabShape);
75                 type.block_light = true;
76                 type.fill = slab_fill;
77                 blockType.Add(type);
78         }
79         { // green stair
80                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &stairShape);
81                 type.block_light = true;
82                 type.fill = stair_fill;
83                 blockType.Add(type);
84         }
85
86         { // blue block
87                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &blockShape);
88                 type.block_light = true;
89                 type.fill = block_fill;
90                 blockType.Add(type);
91         }
92         { // blue slab
93                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &slabShape);
94                 type.block_light = true;
95                 type.fill = slab_fill;
96                 blockType.Add(type);
97         }
98         { // blue stair
99                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &stairShape);
100                 type.block_light = true;
101                 type.fill = stair_fill;
102                 blockType.Add(type);
103         }
104
105         { // glowing yellow block
106                 BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape);
107                 type.luminosity = 15;
108                 type.block_light = true;
109                 type.fill = block_fill;
110                 blockType.Add(type);
111         }
112
113         generate.Space(0);
114         generate.Light(13);
115         generate.Solids({ 1, 4, 7, 10 });
116
117         player = &AddEntity();
118         player->Name("player");
119         player->Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
120         player->WorldCollidable(true);
121         player->Position(config.spawn);
122
123         chunks.GenerateSurrounding(player->ChunkCoords());
124 }
125
126
127 namespace {
128
129 struct Candidate {
130         Chunk *chunk;
131         float dist;
132 };
133
134 std::vector<Candidate> candidates;
135
136 }
137
138 bool World::Intersection(
139         const Ray &ray,
140         const glm::mat4 &M,
141         Chunk *&chunk,
142         int &blkid,
143         float &dist,
144         glm::vec3 &normal
145 ) {
146         candidates.clear();
147
148         for (Chunk &cur_chunk : chunks.Loaded()) {
149                 float cur_dist;
150                 if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(player->ChunkCoords()), cur_dist)) {
151                         candidates.push_back({ &cur_chunk, cur_dist });
152                 }
153         }
154
155         if (candidates.empty()) return false;
156
157         chunk = nullptr;
158         dist = std::numeric_limits<float>::infinity();
159         blkid = -1;
160
161         for (Candidate &cand : candidates) {
162                 if (cand.dist > dist) continue;
163                 int cur_blkid;
164                 float cur_dist;
165                 glm::vec3 cur_normal;
166                 if (cand.chunk->Intersection(ray, M * cand.chunk->Transform(player->ChunkCoords()), cur_blkid, cur_dist, cur_normal)) {
167                         if (cur_dist < dist) {
168                                 chunk = cand.chunk;
169                                 blkid = cur_blkid;
170                                 dist = cur_dist;
171                                 normal = cur_normal;
172                         }
173                 }
174         }
175
176         return chunk;
177 }
178
179 bool World::Intersection(const Entity &e, std::vector<WorldCollision> &col) {
180         AABB box = e.Bounds();
181         glm::mat4 M = e.Transform(player->ChunkCoords());
182         // TODO: this only needs to check the chunks surrounding the entity's chunk position
183         //       need find out if that is quicker than the rough chunk bounds test
184         for (Chunk &cur_chunk : chunks.Loaded()) {
185                 if (cur_chunk.Intersection(box, M, cur_chunk.Transform(player->ChunkCoords()), col)) {
186                         return true;
187                 }
188         }
189         return false;
190 }
191
192
193 Chunk &World::PlayerChunk() {
194         return chunks.ForceLoad(player->ChunkCoords());
195 }
196
197 Chunk &World::Next(const Chunk &to, const glm::tvec3<int> &dir) {
198         const Chunk::Pos tgt_pos = to.Position() + dir;
199         return chunks.ForceLoad(tgt_pos);
200 }
201
202
203 namespace {
204
205 std::vector<WorldCollision> col;
206
207 }
208
209 void World::Update(int dt) {
210         for (Entity &entity : entities) {
211                 entity.Update(dt);
212         }
213         for (Entity &entity : entities) {
214                 col.clear();
215                 if (entity.WorldCollidable() && Intersection(entity, col)) {
216                         // entity collides with the world
217                         Resolve(entity, col);
218                 }
219         }
220         chunks.Rebase(player->ChunkCoords());
221         chunks.Update(dt);
222 }
223
224 void World::Resolve(const Entity &e, std::vector<WorldCollision> &col) {
225         std::cout << e.Name() << " entity intersects world at " << col.size() << " blocks" << std::endl;
226 }
227
228
229 void World::Render(BlockLighting &chunk_prog, DirectionalLighting &entity_prog) {
230         chunk_prog.Activate();
231         chunk_prog.SetFogDensity(fog_density);
232         chunk_prog.SetView(glm::inverse(player->Transform(player->ChunkCoords())));
233
234         for (Chunk &chunk : chunks.Loaded()) {
235                 glm::mat4 m(chunk.Transform(player->ChunkCoords()));
236                 chunk_prog.SetM(m);
237                 glm::mat4 mvp(chunk_prog.GetVP() * m);
238                 if (!CullTest(Chunk::Bounds(), mvp)) {
239                         chunk.Draw();
240                 }
241         }
242
243         entity_prog.Activate();
244         entity_prog.SetLightDirection(light_direction);
245         entity_prog.SetFogDensity(fog_density);
246         entity_prog.SetView(glm::inverse(player->Transform(player->ChunkCoords())));
247
248         for (Entity &entity : entities) {
249                 if (entity.HasShape()) {
250                         entity_prog.SetM(entity.Transform(player->ChunkCoords()));
251                         entity.Draw();
252                 }
253         }
254 }
255
256 }