]> git.localhorst.tv Git - blank.git/blob - src/world.cpp
30e92297d7402d4b040f09eebc9053b872d1052f
[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(unsigned int seed)
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 , generate(seed)
15 , chunks(blockType, generate)
16 , player() {
17         BlockType::Faces block_fill = {  true,  true,  true,  true,  true,  true };
18         BlockType::Faces slab_fill  = { false,  true, false, false, false, false };
19         BlockType::Faces stair_fill = { false,  true, false, false, false,  true };
20
21         { // white block
22                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &blockShape);
23                 type.block_light = true;
24                 type.fill = block_fill;
25                 blockType.Add(type);
26         }
27         { // white slab
28                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &slabShape);
29                 type.block_light = true;
30                 type.fill = slab_fill;
31                 blockType.Add(type);
32         }
33         { // white stair
34                 BlockType type(true, { 1.0f, 1.0f, 1.0f }, &stairShape);
35                 type.block_light = true;
36                 type.fill = stair_fill;
37                 blockType.Add(type);
38         }
39
40         { // red block
41                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &blockShape);
42                 type.block_light = true;
43                 type.fill = block_fill;
44                 blockType.Add(type);
45         }
46         { // red slab
47                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &slabShape);
48                 type.block_light = true;
49                 type.fill = slab_fill;
50                 blockType.Add(type);
51         }
52         { // red stair
53                 BlockType type(true, { 1.0f, 0.0f, 0.0f }, &stairShape);
54                 type.block_light = true;
55                 type.fill = stair_fill;
56                 blockType.Add(type);
57         }
58
59         { // green block
60                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &blockShape);
61                 type.block_light = true;
62                 type.fill = block_fill;
63                 blockType.Add(type);
64         }
65         { // green slab
66                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &slabShape);
67                 type.block_light = true;
68                 type.fill = slab_fill;
69                 blockType.Add(type);
70         }
71         { // green stair
72                 BlockType type(true, { 0.0f, 1.0f, 0.0f }, &stairShape);
73                 type.block_light = true;
74                 type.fill = stair_fill;
75                 blockType.Add(type);
76         }
77
78         { // blue block
79                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &blockShape);
80                 type.block_light = true;
81                 type.fill = block_fill;
82                 blockType.Add(type);
83         }
84         { // blue slab
85                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &slabShape);
86                 type.block_light = true;
87                 type.fill = slab_fill;
88                 blockType.Add(type);
89         }
90         { // blue stair
91                 BlockType type(true, { 0.0f, 0.0f, 1.0f }, &stairShape);
92                 type.block_light = true;
93                 type.fill = stair_fill;
94                 blockType.Add(type);
95         }
96
97         { // glowing yellow block
98                 BlockType type(true, { 1.0f, 1.0f, 0.0f }, &blockShape);
99                 type.luminosity = 10;
100                 type.block_light = true;
101                 type.fill = block_fill;
102                 blockType.Add(type);
103         }
104
105         generate.Space(0);
106         generate.Light(13);
107         generate.Solids({ 1, 4, 7, 10 });
108
109         player = &AddEntity();
110         player->Position({ 4.0f, 4.0f, 4.0f });
111
112         chunks.GenerateSurrounding(player->ChunkCoords());
113 }
114
115
116 namespace {
117
118 struct Candidate {
119         Chunk *chunk;
120         float dist;
121 };
122
123 std::vector<Candidate> candidates;
124
125 }
126
127 bool World::Intersection(
128                 const Ray &ray,
129                 const glm::mat4 &M,
130                 Chunk **chunk,
131                 int *blkid,
132                 float *dist,
133                 glm::vec3 *normal) {
134         candidates.clear();
135
136         for (Chunk &cur_chunk : chunks.Loaded()) {
137                 float cur_dist;
138                 if (cur_chunk.Intersection(ray, M * cur_chunk.Transform(player->ChunkCoords()), cur_dist)) {
139                         candidates.push_back({ &cur_chunk, cur_dist });
140                 }
141         }
142
143         if (candidates.empty()) return false;
144
145         Chunk *closest_chunk = nullptr;
146         float closest_dist = std::numeric_limits<float>::infinity();
147         int closest_blkid = -1;
148         glm::vec3 closest_normal;
149
150         for (Candidate &cand : candidates) {
151                 if (cand.dist > closest_dist) continue;
152                 int cur_blkid;
153                 float cur_dist;
154                 glm::vec3 cur_normal;
155                 if (cand.chunk->Intersection(ray, M * cand.chunk->Transform(player->ChunkCoords()), cur_blkid, cur_dist, cur_normal)) {
156                         if (cur_dist < closest_dist) {
157                                 closest_chunk = cand.chunk;
158                                 closest_blkid = cur_blkid;
159                                 closest_dist = cur_dist;
160                                 closest_normal = cur_normal;
161                         }
162                 }
163         }
164
165         if (chunk) {
166                 *chunk = closest_chunk;
167         }
168         if (blkid) {
169                 *blkid = closest_blkid;
170         }
171         if (dist) {
172                 *dist = closest_dist;
173         }
174         if (normal) {
175                 *normal = closest_normal;
176         }
177         return closest_chunk;
178 }
179
180
181 Chunk &World::PlayerChunk() {
182         return chunks.ForceLoad(player->ChunkCoords());
183 }
184
185 Chunk &World::Next(const Chunk &to, const glm::tvec3<int> &dir) {
186         const Chunk::Pos tgt_pos = to.Position() + dir;
187         return chunks.ForceLoad(tgt_pos);
188 }
189
190
191 void World::Update(int dt) {
192         for (Entity &entity : entities) {
193                 entity.Update(dt);
194         }
195         chunks.Rebase(player->ChunkCoords());
196         chunks.Update();
197 }
198
199
200 void World::Render(DirectionalLighting &program) {
201         program.SetLightDirection({ -1.0f, -3.0f, -2.0f });
202         // fade out reaches 1/e (0.3679) at 1/fog_density,
203         // gets less than 0.01 at e/(2 * fog_density)
204         // I chose 0.011 because it yields 91 and 124 for those, so
205         // slightly less than 6 and 8 chunks
206         program.SetFogDensity(0.011f);
207         program.SetView(glm::inverse(player->Transform(player->ChunkCoords())));
208
209         for (Chunk &chunk : chunks.Loaded()) {
210                 glm::mat4 m(chunk.Transform(player->ChunkCoords()));
211                 program.SetM(m);
212                 glm::mat4 mvp(program.GetVP() * m);
213                 if (!CullTest(Chunk::Bounds(), mvp)) {
214                         chunk.Draw();
215                 }
216         }
217
218         for (Entity &entity : entities) {
219                 if (entity.HasShape()) {
220                         program.SetM(entity.Transform(player->ChunkCoords()));
221                         entity.Draw();
222                 }
223         }
224 }
225
226 }