terrain

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

chunk_manager.c (5440B)


      1 #include "chunk_manager.h"
      2 
      3 #include <math.h>
      4 #include <stdlib.h>
      5 
      6 static void ChunkManager_setChunkCount(ChunkManager *cm)
      7 {
      8     cm->chunk_count = 0;
      9     for (i32 x = -cm->radius; x <= cm->radius; x++)
     10     {
     11         for (i32 y = -cm->radius; y <= cm->radius; y++)
     12         {
     13             for (i32 z = -cm->radius; z <= cm->radius; z++)
     14             {
     15                 cm->chunk_count += 1;
     16             }
     17         }
     18     }
     19 }
     20 
     21 static void ChunkManager_createOffsets(ChunkManager *cm)
     22 {
     23     cm->offsets = malloc(sizeof *cm->offsets * cm->chunk_count);
     24     for (i32 i = 0, x = -cm->radius; x <= cm->radius; x++)
     25     {
     26         for (i32 y = -cm->radius; y <= cm->radius; y++)
     27         {
     28             for (i32 z = -cm->radius; z <= cm->radius; z++, i++)
     29             {
     30                 cm->offsets[i][0] = x;
     31                 cm->offsets[i][1] = y;
     32                 cm->offsets[i][2] = z;
     33             }
     34         }
     35     }
     36 }
     37 
     38 static void ChunkManager_createChunks(ChunkManager *cm)
     39 {
     40     cm->chunks = malloc(sizeof *cm->chunks * cm->chunk_count);
     41     for (u32 i = 0; i < cm->chunk_count; i++)
     42     {
     43         Chunk_init(&cm->chunks[i]);
     44 
     45         IVec3 chunk_origin = {
     46             cm->origin[0] + cm->offsets[i][0],
     47             cm->origin[1] + cm->offsets[i][1],
     48             cm->origin[2] + cm->offsets[i][2]
     49         };
     50         Chunk_updateOrigin(&cm->chunks[i], chunk_origin);
     51         Chunk_updateMesh(&cm->chunks[i], cm->f, cm->isolevel, cm->pool);
     52     }
     53 }
     54 
     55 static void ChunkManager_resetFlags(ChunkManager *cm)
     56 {
     57     for (u32 i = 0; i < cm->chunk_count; i++)
     58     {
     59         cm->is_new_offset[i] = true;
     60         cm->is_old_chunk[i] = true;
     61     }
     62 }
     63 
     64 static void ChunkManager_updateFlags(ChunkManager *cm)
     65 {
     66     for (u32 i = 0; i < cm->chunk_count; i++)
     67     {
     68         IVec3 chunk_origin = {
     69             cm->origin[0] + cm->offsets[i][0],
     70             cm->origin[1] + cm->offsets[i][1],
     71             cm->origin[2] + cm->offsets[i][2]
     72         };
     73         for (u32 j = 0; j < cm->chunk_count; j++)
     74         {
     75             if (IVec3_equal(chunk_origin, cm->chunks[j].origin))
     76             {
     77                 cm->is_new_offset[i] = false;
     78                 cm->is_old_chunk[j] = false;
     79                 break;
     80             }
     81         }
     82     }
     83 }
     84 
     85 static void ChunkManager_updateChunkMeshes(ChunkManager *cm)
     86 {
     87     for (u32 i = 0; i < cm->chunk_count; i++)
     88     {
     89         if (cm->is_new_offset[i])
     90         {
     91             for (u32 j = 0; j < cm->chunk_count; j++)
     92             {
     93                 if (cm->is_old_chunk[j])
     94                 {
     95                     IVec3 chunk_origin = {
     96                         cm->origin[0] + cm->offsets[i][0],
     97                         cm->origin[1] + cm->offsets[i][1],
     98                         cm->origin[2] + cm->offsets[i][2]
     99                     };
    100                     Chunk_updateOrigin(&cm->chunks[j], chunk_origin);
    101                     Chunk_updateMesh(&cm->chunks[j], cm->f, cm->isolevel,
    102                             cm->pool);
    103 
    104                     cm->is_new_offset[i] = false;
    105                     cm->is_old_chunk[j] = false;
    106                     break;
    107                 }
    108             }
    109         }
    110     }
    111 }
    112 
    113 static void ChunkManager_updateChunks(ChunkManager *cm)
    114 {
    115     ChunkManager_resetFlags(cm);
    116     ChunkManager_updateFlags(cm);
    117     ChunkManager_updateChunkMeshes(cm);
    118 }
    119 
    120 static void ChunkManager_worldToChunk(const Vec3 src, IVec3 dst)
    121 {
    122     dst[0] = (i32)floorf(src[0] / CHUNK_WIDTH);
    123     dst[1] = (i32)floorf(src[1] / CHUNK_WIDTH);
    124     dst[2] = (i32)floorf(src[2] / CHUNK_WIDTH);
    125 }
    126 
    127 static void ChunkManager_chunkToWorld(const IVec3 src, Vec3 dst)
    128 {
    129     dst[0] = src[0] * CHUNK_WIDTH;
    130     dst[1] = src[1] * CHUNK_WIDTH;
    131     dst[2] = src[2] * CHUNK_WIDTH;
    132 }
    133 
    134 ChunkManager ChunkManager_create(
    135         const Vec3 target,
    136         i32 radius,
    137         SDF f,
    138         f32 isolevel
    139 )
    140 {
    141     ChunkManager cm;
    142 
    143     cm.pool = ThreadPool_make(5);
    144 
    145     ChunkManager_worldToChunk(target, cm.origin);
    146     cm.radius = radius;
    147 
    148     cm.f = f;
    149     cm.isolevel = isolevel;
    150     
    151     ChunkManager_setChunkCount(&cm);
    152     ChunkManager_createOffsets(&cm);
    153     ChunkManager_createChunks(&cm);
    154 
    155     cm.is_new_offset = malloc(sizeof *cm.is_new_offset * cm.chunk_count);
    156     cm.is_old_chunk = malloc(sizeof *cm.is_old_chunk * cm.chunk_count);
    157 
    158     return cm;
    159 }
    160 
    161 void ChunkManager_free(ChunkManager *cm)
    162 {
    163     free(cm->offsets);
    164 
    165     ThreadPool_free(cm->pool);
    166 
    167     for (u32 i = 0; i < cm->chunk_count; i++)
    168     {
    169         Chunk_free(&cm->chunks[i]);
    170     }
    171     free(cm->chunks);
    172 
    173     free(cm->is_new_offset);
    174     free(cm->is_old_chunk);
    175 
    176     cm->chunk_count = 0;
    177 }
    178 
    179 void ChunkManager_recenter(ChunkManager *cm, const Vec3 target)
    180 {
    181     IVec3 new_origin;
    182     ChunkManager_worldToChunk(target, new_origin);
    183     if (!IVec3_equal(new_origin, cm->origin))
    184     {
    185         cm->origin[0] = new_origin[0];
    186         cm->origin[1] = new_origin[1];
    187         cm->origin[2] = new_origin[2];
    188         ChunkManager_updateChunks(cm);
    189     }
    190 }
    191 
    192 void ChunkManager_drawChunks(const ChunkManager *cm, const Camera *camera)
    193 {
    194     for (u32 i = 0; i < cm->chunk_count; i++)
    195     {
    196         Vec3 chunk_center;
    197         ChunkManager_chunkToWorld(cm->chunks[i].origin, chunk_center);
    198         chunk_center[0] += CHUNK_WIDTH / 2;
    199         chunk_center[1] += CHUNK_WIDTH / 2;
    200         chunk_center[2] += CHUNK_WIDTH / 2;
    201 
    202         f32 chunk_radius = CHUNK_WIDTH * 0.866025f;
    203 
    204         if (Camera_sphereInFrustum(camera, chunk_center, chunk_radius))
    205         {
    206             Chunk_drawMesh(&cm->chunks[i]);
    207         }
    208     }
    209 }