From de3c9942416382aae0f2f2aac3b67c1e8b4d71f1 Mon Sep 17 00:00:00 2001 From: Aaditya Dhruv Date: Tue, 27 Jan 2026 20:10:55 -0600 Subject: Add support for chunk and world - Chunk is a array of blocks - World is a array of chunks - Basic chunk plains generation based on simple linear functions - Bunch of functions still not implemented, in design phase --- src/CMakeLists.txt | 1 + src/chunk.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/chunk.h | 21 +++++++++++ src/engine.c | 27 ++++++++------ src/world.h | 13 +++++++ 5 files changed, 157 insertions(+), 12 deletions(-) create mode 100644 src/chunk.c create mode 100644 src/chunk.h create mode 100644 src/world.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7b88ab5..34e23b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,4 +6,5 @@ add_executable(junkcraft util.c window.c engine.c + chunk.c ) diff --git a/src/chunk.c b/src/chunk.c new file mode 100644 index 0000000..77c2301 --- /dev/null +++ b/src/chunk.c @@ -0,0 +1,107 @@ +#include "chunk.h" +#include "block.h" +#include "cglm/io.h" +#include "cglm/util.h" +#include "cglm/vec2.h" +#include "cglm/vec3.h" +#include "world.h" +#include +#include +#include +#include +#include + + +#define MIN(x, y) (x < y) ? x : y +#define MAX(x, y) (x > y) ? x : y + +void _chunk_plains_gen(struct chunk* chunk); + +int chunk_gen(struct world* world, struct chunk *chunk) { + // struct chunk neighbor = {0}; + // world_get_chunk(world, chunk->coord, &neighbor); + _chunk_plains_gen(chunk); + // switch (chunk->biome) { + // case JUNK_BIOME_PLAINS: + // _ + // break; + // default: + // break; + // } + return 0; +} + +float _chunk_plains_get_z(vec2 target, vec3 poi, float m, int base_z) { + vec2 unit = { (target[0] - poi[0]), (target[1] - poi[1]) }; + glm_vec2_normalize(unit); + // Line direction vector + vec3 r = { unit[0], unit[1], m }; + // r*t + poi = { x, y, z }, solve first for t, then get z + float t = 0; + // Parallel to X-axis + if (r[0] == 0.0f && r[1] != 0.0f) { + t = (target[1] - poi[1]) / r[1]; + } + // Parallel to Y-axis + else if (r[1] == 0.0f && r[0] != 0.0f) { + t = (target[0] - poi[0]) / r[0]; + } + else if (r[0] != 0.0f && r[1] != 0.0f) { + // Non-parallel line, either X or y works + t = (target[0] - poi[0]) / r[0]; + } + else { + //Else we are POI itself, no need to do anything. t will be zero and + //the value of z == poi[2]. We subtract -1 from base_z because + //otherwise the POI will be a single block at it's z, all others will + //always be strictly less than it. This levels the plains + base_z -= 1; + } + float z_off = poi[2] + t * r[2]; + + return MAX(base_z, base_z + z_off); +} + +/** + * Basic Plains chunk generation + * Algorithm: Pick 2 points of interest (POI). These points will either be elevations or depressions. + * Each block will get a invisible "offset" value based on their distance from the chosen point. + * Chosen point height itself will range from some non zero value to another, plus in negative. + * The offset value determines how block heights are created + * + */ +void _chunk_plains_gen(struct chunk* chunk) { + // ============ KNOBS ============ + // Minimum ground + int z = 2; + // Min POI block height + int poi_min = 3; + // Max POI block height + int poi_max = 5; + // Descent/Ascent rate + float m = -.5; + memset(chunk->blocks, 0, CHUNK_HEIGHT * CHUNK_LENGTH * CHUNK_WIDTH * sizeof(struct block*)); + // X, Y, POI Height + vec3 poi1 = { rand() % CHUNK_WIDTH, rand() % CHUNK_LENGTH, poi_min + (rand() % (poi_max - poi_min))}; + vec3 poi2 = { rand() % CHUNK_WIDTH, rand() % CHUNK_LENGTH, -poi_min + (rand() % (poi_max - poi_min))}; + + for (int x = 0; x < CHUNK_LENGTH; x++) { + for (int y = 0; y < CHUNK_WIDTH; y++) { + // Minimum z height + // Interpolation formula - simple linear + vec2 target = { x, y }; + float z1 = _chunk_plains_get_z(target, poi1, m, z); + float z2 = _chunk_plains_get_z(target, poi2, -m, z); + int z_final = (z1 + z2) / 2; + for (int h = 0; h < z_final; h++) { + struct block* blk = malloc(sizeof(struct block)); + vec3 pos = {x, h, -y - 1}; + block_init(pos, blk); + chunk->blocks[x][y][h] = blk; + } + } + } + fprintf(stderr, "POI Coords\n"); + glm_vec3_print(poi1, stderr); + glm_vec3_print(poi2, stderr); +} diff --git a/src/chunk.h b/src/chunk.h new file mode 100644 index 0000000..87c33fa --- /dev/null +++ b/src/chunk.h @@ -0,0 +1,21 @@ +#pragma once +#include "block.h" +#include "world.h" +#include "junk/vector.h" +#include +enum biome { + JUNK_BIOME_PLAINS, +}; +#define CHUNK_WIDTH 16 +#define CHUNK_LENGTH 16 +#define CHUNK_HEIGHT 128 + +struct chunk { + struct block* blocks[CHUNK_WIDTH][CHUNK_LENGTH][CHUNK_HEIGHT]; + enum biome biome; + vec2 coord; +}; + +int chunk_gen(struct world* world, struct chunk* chunk); +int chunk_gen_structures(void* neighbor_data, struct chunk* chunk); +int chunk_gen_terrain(void* neighbor_data, struct chunk* chunk); diff --git a/src/engine.c b/src/engine.c index ec1fdcd..d8df9b3 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1,5 +1,6 @@ #include "engine.h" #include "block.h" +#include "chunk.h" #include "window.h" #include @@ -25,20 +26,22 @@ int engine_init(struct engine *engine) { // Setup Objects to draw vector_init(&engine->objects); + // Setup root chunk + struct chunk* chunk = malloc(sizeof(struct chunk)); + chunk_gen(NULL, chunk); - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - fprintf(stderr, "Creating block %d\n", i + j); - struct block* blk = malloc(sizeof(struct block)); - memset(blk, 0, sizeof(struct block)); - vec3 pos = { 0.5f * ((float)i - 1), 0.5f * ((float)j - 1), 0.0f}; - if (block_init(pos, blk) != 0) { - //TODO: Fix frees here - return -1; + int counter = 0; + for (int i = 0; i < CHUNK_WIDTH; i++) { + for (int j = 0; j < CHUNK_LENGTH; j++) { + for (int k = 0; k < CHUNK_HEIGHT; k++) { + struct block* blk = chunk->blocks[i][j][k]; + if (blk == NULL) { + continue; + } + if (VECTOR_INSERT(engine->objects, (void*)blk) == -1) exit(1); + // block_debug(blk); + counter += 1; } - fprintf(stderr, "Inserting block %d\n", i + j); - if (VECTOR_INSERT(engine->objects, (void*)blk) == -1) exit(1); - fprintf(stderr, "Done block %d\n", i + j); } } diff --git a/src/world.h b/src/world.h new file mode 100644 index 0000000..5be1cf2 --- /dev/null +++ b/src/world.h @@ -0,0 +1,13 @@ +#pragma once +#include "chunk.h" +#include +#define WORLD_LENGTH 32 +#define WORLD_WIDTH 32 +struct world { + struct chunk* chunks[WORLD_WIDTH][WORLD_LENGTH]; + int32_t seed; +}; + +int world_init(int32_t seed); +int world_save(int32_t seed); +int world_get_chunk(struct world* world, vec2 coord, struct chunk* chunk); -- cgit