terrain

Real-time terrain generation using marching cubes
git clone git://git.christianermann.dev/terrain
Log | Files | Refs | README | LICENSE

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 }