#include "chunk.h" #include "block.h" #include "world.h" #include "cglm/cglm.h" #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, vec2 coord, struct chunk **chunk) { *chunk = malloc(sizeof(struct chunk)); memcpy((*chunk)->coord,coord, sizeof(vec2)); // struct chunk* neighbor_top = { 0 }; // struct chunk* neighbor_bottom = { 0 }; // struct chunk* neighbor_left = { 0 }; // struct chunk* neighbor_right = { 0 }; // vec2 top = { 0, 1 }; // vec2 bottom = { 0, -1 }; // vec2 left = { -1, 0 }; // vec2 right = { 1, 0 }; // glm_vec2_add(top, coord, top); // glm_vec2_add(bottom, coord, bottom); // glm_vec2_add(left, coord, left); // glm_vec2_add(right, coord, right); // world_get_chunk(world, top, &neighbor_top); // world_get_chunk(world, bottom, &neighbor_bottom); // world_get_chunk(world, left, &neighbor_left); // world_get_chunk(world, right, &neighbor_right); // 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_WIDTH; x++) { for (int y = 0; y < CHUNK_LENGTH; 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)); // Adjust block coordinates with global chunk coordinates vec3 pos = {x, h, -y }; block_init(pos, blk); chunk->blocks[x][y][h] = blk; } } } chunk->loaded = 1; } // Kind of like the block_update of chunks void chunk_load(struct chunk *chunk, int coord[2]) { vec3 translation = {CHUNK_WIDTH * coord[0], 0, - (CHUNK_LENGTH * coord[1])}; for (int x = 0; x < CHUNK_WIDTH; x++) { for (int y = 0; y < CHUNK_HEIGHT; y++) { for (int z = 0; z < CHUNK_LENGTH; z++) { struct block* blk = chunk->blocks[x][z][y]; if (blk != NULL) { // If chunk is unloaded, send block data to GPU if (chunk->loaded == 0) { // Add GPU data block_load_gpu(blk); } // Translate to world coordinates // First do block updates, set the position of the block in local // chunk coordinates block_update(blk); // Then translate them to world coordinates glm_translate(blk->model, translation); } } } } if (chunk->loaded == 0) { //We've reloaded all data - flip bit again chunk->loaded = 1; } } void chunk_draw(struct chunk* chunk, struct shader* shader) { 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; } block_draw(blk, shader); counter += 1; } } } } void chunk_unload(struct chunk* chunk) { 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; } block_unload(blk); } } } chunk->loaded = 0; }