]> git.lizzy.rs Git - dragonblocks3d.git/blob - src/chunk.cpp
New structure
[dragonblocks3d.git] / src / chunk.cpp
1 #include <iostream>
2 #include <stdexcept>
3 #include "animations.hpp"
4 #include "block_def.hpp"
5 #include "box_vertices.hpp"
6 #include "chunk.hpp" 
7 #include "face_dir.hpp" 
8 #include "map.hpp" 
9 #include "mesh.hpp" 
10 #include "texture.hpp" 
11
12 #define SIZE DRAGONBLOCKS_CHUNK_SIZE
13
14 using namespace std;
15 using namespace glm;
16 using namespace dragonblocks;
17
18 bool Chunk::checkPos(const ivec3 &pos)
19 {
20         return pos.x >= 0 && pos.y >= 0 && pos.z >= 0 && pos.x < SIZE && pos.y < SIZE && pos.z < SIZE;
21 }
22
23 const Block *Chunk::getBlock(const ivec3 &pos) const
24 {
25         const Block *b = getBlockNoEx(pos);
26         if (! b) {
27                 throw out_of_range("Block position out of range");
28         }
29         return b;
30 }
31
32 const Block *Chunk::getBlockNoEx(const ivec3 &pos) const
33 {
34         return Chunk::checkPos(pos) ? &data.blocks[pos.x][pos.y][pos.z] : nullptr;
35 }
36
37 void Chunk::setBlock(const ivec3 &pos, const Block &block)
38 {
39         if (! Chunk::checkPos(pos)) {
40                 throw out_of_range("Block position out of range");
41         }
42         data.blocks[pos.x][pos.y][pos.z] = block;
43 }
44
45 void Chunk::setBlockNoEx(const ivec3 &pos, const Block &block)
46 {
47         try {
48                 setBlock(pos, block);
49         } catch (out_of_range &) {
50         }
51 }
52
53 void Chunk::addMeshUpdateTask()
54 {
55         async_mgr->addTask(this);
56 }
57
58 void Chunk::addMeshUpdateTaskWithEdge()
59 {
60         addMeshUpdateTask();
61         for (int i = 0; i < 6; i++) {
62                 if (Chunk *neighbor = map->getChunk(pos + face_dir[i])) {
63                         neighbor->addMeshUpdateTask();
64                 }
65         }
66 }
67
68 void Chunk::updateMesh()
69 {
70         cout << "Update Chunk Mesh at " << pos.x << " " << pos.y << " " << pos.z << endl;
71                 
72         if (mesh_created && ! animation_finished)
73                 return;
74         
75         bool mesh_created_before = mesh_created;
76         mesh_created = true;
77         
78         vector<GLfloat> vertices;
79         vector<Texture> textures;
80         bool any_drawable_block = false;
81         
82         for (int x = 0; x < SIZE; x++) {
83                 for (int y = 0; y < SIZE; y++) {
84                         for (int z = 0; z < SIZE; z++) {
85                                 Block *block = &data.blocks[x][y][z];
86                                 BlockDef *def = block->getDef();
87                                 if (! def->drawable)
88                                         continue;
89                                 ivec3 bpos(x, y, z);
90                                 vec3 pos_from_mesh_origin = vec3(bpos) - vec3(SIZE / 2 + 0.5);
91                                 for (int facenr = 0; facenr < 6; facenr++) {
92                                         ivec3 npos = bpos + face_dir[facenr];
93                                         const Block *neighbor_own, *neighbor;
94                                         neighbor_own = neighbor = getBlockNoEx(npos);
95                                         if (! neighbor)
96                                                 neighbor = map->getBlock(pos * SIZE + npos);
97                                         if (neighbor && ! neighbor->getDef()->drawable)
98                                                 any_drawable_block = true;
99                                         if (! mesh_created_before)
100                                                 neighbor = neighbor_own;
101                                         if (! mesh_created_before && ! neighbor || neighbor && ! neighbor->getDef()->drawable) {
102                                                 textures.push_back(def->tile_def.get(facenr));
103                                                 for (int vertex_index = 0; vertex_index < 6; vertex_index++) {
104                                                         for (int attribute_index = 0; attribute_index < 5; attribute_index++) {
105                                                                 GLdouble value = box_vertices[facenr][vertex_index][attribute_index];
106                                                                 switch (attribute_index) {
107                                                                         case 0:
108                                                                         value += pos_from_mesh_origin.x;
109                                                                         break;
110                                                                         case 1:
111                                                                         value += pos_from_mesh_origin.y;
112                                                                         break;
113                                                                         case 2:
114                                                                         value += pos_from_mesh_origin.z;
115                                                                         break;
116                                                                 }
117                                                                 vertices.push_back(value);
118                                                         }
119                                                 }
120                                         }
121                                 }
122                         }
123                 }
124         }
125         
126         if (! any_drawable_block) {
127                 if (! mesh_created_before) {
128                         afterAnimation();
129                 } else if (mesh) {
130                         mesh->die();
131                         mesh = nullptr;
132                 }
133                 return;
134         }
135         
136         Mesh *oldmesh = mesh;
137         
138         mesh = new Mesh(scene, shader_program, &vertices[0], vertices.size());
139         mesh->pos = pos * SIZE + SIZE / 2;
140         mesh->minp = vec3(- SIZE / 2);
141         mesh->maxp = vec3(+ SIZE / 2);
142         mesh->textures = textures;
143         mesh->vertices_per_texture = 6;
144         if (! mesh_created_before) {
145                 mesh->animation = new FlyInAnimation(0.4, 20.0, Chunk::staticAfterAnimation, this);
146         }
147         
148         if (oldmesh) {
149                 oldmesh->die();
150         }
151 }
152
153 void Chunk::doAsyncTask()
154 {
155         updateMesh();
156 }
157
158 Chunk::Chunk(Map *m, const ivec3 &p, const Data &d, AsyncMgr *a, Scene *s, ShaderProgram *sh) : map(m), data(d), pos(p), async_mgr(a), scene(s), shader_program(sh)
159 {
160         addMeshUpdateTask();
161 }
162
163 Chunk::~Chunk()
164 {
165         if (mesh) {
166                 mesh->die();
167         }
168 }
169
170 void Chunk::staticAfterAnimation(void *chunk)
171 {
172         if (chunk) {
173                 ((Chunk *)chunk)->afterAnimation();
174         }
175 }
176
177 void Chunk::afterAnimation()
178 {
179         animation_finished = true;
180         addMeshUpdateTaskWithEdge();
181 }