#include "zpl.h" #include #include #include "world/world.h" #include "world/blocks.h" #include "world/perlin.h" #include "ecs/components.h" #include "ents/entity.h" #include "ents/vehicle.h" #include "ents/items.h" #include "world/blocks_info.h" #define WORLD_BLOCK_OBSERVER(name) block_id name(block_id *data, block_id id, uint32_t block_idx) typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc); #define WORLD_PERLIN_FREQ 100 #define WORLD_PERLIN_OCTAVES 1 #define BLOCK_INVALID 0xF int eco_incircle(int x, int y, int radius) { return (zpl_pow(x, 2) + zpl_pow(y, 2)) < zpl_pow(radius, 2); } block_id worldgen_biome_find(uint32_t biome, uint32_t kind) { asset_id asset = ASSET_INVALID; switch (biome) { case BLOCK_BIOME_DEV: { switch (kind) { case BLOCK_KIND_GROUND: asset = ASSET_GROUND; break; case BLOCK_KIND_DIRT: asset = ASSET_DIRT; break; case BLOCK_KIND_WALL: asset = ASSET_WALL; break; case BLOCK_KIND_HILL_SNOW: case BLOCK_KIND_HILL: asset = ASSET_HILL; break; case BLOCK_KIND_WATER: asset = ASSET_WATER; break; case BLOCK_KIND_LAVA: asset = ASSET_LAVA; break; } } } return blocks_find(asset); } static world_data *world; static void world_fill_rect(block_id *data, block_id id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { for (uint32_t cy=y; cy= world->dim) continue; if (cy < 0 || cy >= world->dim) continue; uint32_t i = (cy*world->dim) + cx; if (proc) { block_id new_id = (*proc)(data, id, i); if (new_id != BLOCK_INVALID) { id = new_id; } else continue; } data[i] = id; } } } static void world_fill_circle(block_id *data, block_id id, uint32_t cx, uint32_t cy, uint32_t radius, world_block_observer_proc *proc) { for (int x = -(int32_t)(radius); x < (int32_t)radius; ++x) { for (int y = -(int32_t)(radius); y < (int32_t)radius; ++y) { if (eco_incircle(x, y, radius)) { int fx = x + cx; int fy = y + cy; uint32_t i = (fy*world->dim) + fx; if (proc) { block_id new_id = (*proc)(data, id, i); if (new_id != BLOCK_INVALID) { id = new_id; } else continue; } data[i] = id; } } } } static void world_fill_rect_anchor(block_id *data, block_id id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) { uint32_t w2 = (uint32_t)floorf(w*ax); uint32_t h2 = (uint32_t)floorf(h*ay); world_fill_rect(data, id, x-w2, y-h2, w, h, proc); } static WORLD_BLOCK_OBSERVER(shaper) { uint32_t kind = id; uint32_t old_kind = data[block_idx]; if (kind == BLOCK_KIND_WALL && kind == old_kind) { return worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_HILL); } if (kind == BLOCK_KIND_HILL && kind == old_kind) { return worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_HILL_SNOW); } return id; } static block_id world_perlin_cond_offset(uint32_t block_idx, double chance, uint32_t ofx, uint32_t ofy) { uint32_t x = block_idx % world->dim + ofx; uint32_t y = block_idx / world->dim + ofy; return perlin_fbm(world->seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance; } static block_id world_perlin_cond(uint32_t block_idx, double chance) { return world_perlin_cond_offset(block_idx, chance, 0, 0); } #if 1 static WORLD_BLOCK_OBSERVER(shaper_noise80) { return world_perlin_cond(block_idx, 0.80) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise50) { return world_perlin_cond(block_idx, 0.50) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise33) { return world_perlin_cond(block_idx, 0.33) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise05) { return world_perlin_cond(block_idx, 0.05) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise05b) { return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise01b) { return world_perlin_cond_offset(block_idx, 0.01, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; } #else static WORLD_BLOCK_OBSERVER(shaper_noise80) { return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise50) { return rand()%10 < 5 ? shaper(id, block_idx) : BLOCK_INVALID; } static WORLD_BLOCK_OBSERVER(shaper_noise33) { return rand()%10 < 3 ? shaper(id, block_idx) : BLOCK_INVALID; } #endif #if 0 static void world_fill_mountain(uint32_t x, uint32_t y) { } #endif #define RAND_RANGE(x,y) (x + (int)rand()%(y-(x))) #define RAND_RANGEF(x,y) ((float)RAND_RANGE(x,y)) int32_t worldgen_build(world_data *wld) { // TODO(zaklaus): pass world as an arg instead world = wld; // TODO: perform world gen // atm, we will fill the world with ground and surround it by walls block_id wall_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_WALL); block_id grnd_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_GROUND); block_id dirt_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_DIRT); block_id watr_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER); block_id lava_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_LAVA); block_id tree_id = blocks_find(ASSET_TREE); srand(world->seed); // walls world_fill_rect(world->data, wall_id, 0, 0, world->dim, world->dim, NULL); // ground world_fill_rect(world->data, watr_id, 1, 1, world->dim-2, world->dim-2, NULL); int radius = 25; // wide boy circle world_fill_circle(world->data, dirt_id, world->dim / 2, world->dim / 2, radius, NULL); // narrow boy cirlce world_fill_circle(world->data, grnd_id, world->dim / 2, world->dim / 2, radius * 0.7f, NULL); return WORLD_ERROR_NONE; }