chunk.c (4773B)
1 #include "chunk.h" 2 3 #include "marching_cubes.h" 4 #include "threadpool.h" 5 #include "memory.h" 6 7 #include <stdlib.h> 8 9 struct UpdateArgs { 10 Chunk *chunk; 11 SDF f; 12 f32 isolevel; 13 }; 14 15 static UpdateArgs *UpdateArgs_make(Chunk *c) 16 { 17 UpdateArgs *args = s_alloc(sizeof *args, MEMORY_TAG_JOB); 18 args->chunk = c; 19 args->f = NULL; 20 args->isolevel = 0.0f; 21 return args; 22 } 23 24 static void UpdateArgs_free(UpdateArgs *args) 25 { 26 if (args) 27 { 28 free(args); 29 } 30 } 31 32 void Chunk_init(Chunk *c) 33 { 34 Mesh_init(&c->mesh, CHUNK_PVOLUME * 3, CHUNK_VOLUME * 15); 35 36 c->update_args = UpdateArgs_make(c); 37 pthread_mutex_init(&c->mesh_mutex, NULL); 38 c->mesh_update_count = 0; 39 } 40 41 void Chunk_free(Chunk *c) 42 { 43 Mesh_free(&c->mesh); 44 UpdateArgs_free(c->update_args); 45 } 46 47 static void worldOrigin(const IVec3 chunk_origin, Vec3 world_origin) 48 { 49 world_origin[0] = chunk_origin[0] * CHUNK_WIDTH; 50 world_origin[1] = chunk_origin[1] * CHUNK_WIDTH; 51 world_origin[2] = chunk_origin[2] * CHUNK_WIDTH; 52 } 53 54 static void cubeCorners(const Vec3 origin, f32 width, Vec3 corners[8]) 55 { 56 corners[0][0] = origin[0]; 57 corners[0][1] = origin[1]; 58 corners[0][2] = origin[2]; 59 60 corners[1][0] = origin[0] + width; 61 corners[1][1] = origin[1]; 62 corners[1][2] = origin[2]; 63 64 corners[2][0] = origin[0] + width; 65 corners[2][1] = origin[1]; 66 corners[2][2] = origin[2] + width; 67 68 corners[3][0] = origin[0]; 69 corners[3][1] = origin[1]; 70 corners[3][2] = origin[2] + width; 71 72 corners[4][0] = origin[0]; 73 corners[4][1] = origin[1] + width; 74 corners[4][2] = origin[2]; 75 76 corners[5][0] = origin[0] + width; 77 corners[5][1] = origin[1] + width; 78 corners[5][2] = origin[2]; 79 80 corners[6][0] = origin[0] + width; 81 corners[6][1] = origin[1] + width; 82 corners[6][2] = origin[2] + width; 83 84 corners[7][0] = origin[0]; 85 corners[7][1] = origin[1] + width; 86 corners[7][2] = origin[2] + width; 87 } 88 89 const static u32 EDGE_OFFSETS[] = { 90 0, 91 4, 92 3 * CHUNK_PWIDTH, 93 1, 94 3 * CHUNK_PWIDTH * CHUNK_PWIDTH, 95 3 * CHUNK_PWIDTH * CHUNK_PWIDTH + 4, 96 3 * CHUNK_PWIDTH * CHUNK_PWIDTH + 3 * CHUNK_PWIDTH, 97 3 * CHUNK_PWIDTH * CHUNK_PWIDTH + 1, 98 2, 99 5, 100 3 * CHUNK_PWIDTH + 5, 101 3 * CHUNK_PWIDTH + 2 102 }; 103 104 static void Chunk_updateMeshData(Chunk *c, SDF f, f32 isolevel) 105 { 106 c->mesh.vertex_count = 0; 107 c->mesh.index_count = 0; 108 109 Vec3 mesh_origin; 110 worldOrigin(c->origin, mesh_origin); 111 112 for (u32 i = 0; i < CHUNK_PWIDTH; i++) 113 { 114 for (u32 j = 0; j < CHUNK_PWIDTH; j++) 115 { 116 for (u32 k = 0; k < CHUNK_PWIDTH; k++) 117 { 118 Vec3 cell_origin = { 119 mesh_origin[0] + k, 120 mesh_origin[1] + i, 121 mesh_origin[2] + j 122 }; 123 124 Vec3 cell_corners[8]; 125 cubeCorners(cell_origin, 1, cell_corners); 126 127 u32 mc_index = MC_index(cell_corners, f, isolevel); 128 129 if (i < CHUNK_WIDTH && j < CHUNK_WIDTH && k < CHUNK_WIDTH) 130 { 131 c->mesh.index_count += MC_indices(mc_index, 132 c->mesh.vertex_count, EDGE_OFFSETS, 133 &c->mesh.indices[c->mesh.index_count]); 134 } 135 136 c->mesh.vertex_count += MC_vertices(cell_corners, f, isolevel, 137 mc_index, &c->mesh.vertices[c->mesh.vertex_count]); 138 } 139 } 140 } 141 } 142 143 static void Chunk_updateMeshFunc(void *arg) 144 { 145 UpdateArgs *args = (UpdateArgs*)arg; 146 147 pthread_mutex_lock(&args->chunk->mesh_mutex); 148 149 Chunk_updateMeshData(args->chunk, args->f, args->isolevel); 150 151 args->chunk->mesh_update_count -= 1; 152 153 pthread_mutex_unlock(&args->chunk->mesh_mutex); 154 } 155 156 void Chunk_updateMesh(Chunk *c, SDF f, f32 isolevel, ThreadPool *pool) 157 { 158 c->update_args->chunk = c; 159 c->update_args->f = f; 160 c->update_args->isolevel = isolevel; 161 162 pthread_mutex_lock(&c->mesh_mutex); 163 164 if (c->mesh_update_count == 0 && !c->mesh.buffers_mapped) 165 { 166 Mesh_mapBuffers(&c->mesh); 167 } 168 c->mesh_update_count += 1; 169 170 pthread_mutex_unlock(&c->mesh_mutex); 171 172 ThreadPool_addWork(pool, Chunk_updateMeshFunc, c->update_args); 173 } 174 175 void Chunk_updateOrigin(Chunk *c, IVec3 origin) 176 { 177 pthread_mutex_lock(&c->mesh_mutex); 178 c->origin[0] = origin[0]; 179 c->origin[1] = origin[1]; 180 c->origin[2] = origin[2]; 181 pthread_mutex_unlock(&c->mesh_mutex); 182 } 183 184 void Chunk_drawMesh(Chunk *c) 185 { 186 if (pthread_mutex_trylock(&c->mesh_mutex) == 0) 187 { 188 if (c->mesh_update_count == 0 && c->mesh.buffers_mapped) 189 { 190 Mesh_unmapBuffers(&c->mesh); 191 } 192 pthread_mutex_unlock(&c->mesh_mutex); 193 } 194 Mesh_draw(&c->mesh); 195 }