2025-10-17 17:54:33 -05:00
|
|
|
#include <stdlib.h>
|
2025-10-07 10:32:48 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "pxl8_bsp.h"
|
|
|
|
|
#include "pxl8_macros.h"
|
2025-11-09 06:30:17 -06:00
|
|
|
#include "pxl8_procgen.h"
|
2025-10-07 10:32:48 -05:00
|
|
|
#include "pxl8_world.h"
|
|
|
|
|
|
|
|
|
|
struct pxl8_world {
|
|
|
|
|
pxl8_bsp bsp;
|
|
|
|
|
bool loaded;
|
2025-11-09 06:30:17 -06:00
|
|
|
bool wireframe;
|
2025-10-07 10:32:48 -05:00
|
|
|
u32 wireframe_color;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pxl8_world* pxl8_world_create(void) {
|
2025-10-17 17:54:33 -05:00
|
|
|
pxl8_world* world = (pxl8_world*)calloc(1, sizeof(pxl8_world));
|
2025-10-07 10:32:48 -05:00
|
|
|
if (!world) {
|
|
|
|
|
pxl8_error("Failed to allocate world");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
world->loaded = false;
|
|
|
|
|
world->wireframe_color = 15;
|
|
|
|
|
|
|
|
|
|
return world;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pxl8_world_destroy(pxl8_world* world) {
|
|
|
|
|
if (!world) return;
|
|
|
|
|
|
|
|
|
|
if (world->loaded) {
|
|
|
|
|
pxl8_bsp_destroy(&world->bsp);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-17 17:54:33 -05:00
|
|
|
free(world);
|
2025-10-07 10:32:48 -05:00
|
|
|
}
|
|
|
|
|
|
2025-11-09 06:30:17 -06:00
|
|
|
pxl8_result pxl8_world_generate(pxl8_world* world, const pxl8_procgen_params* params) {
|
|
|
|
|
if (!world || !params) return PXL8_ERROR_INVALID_ARGUMENT;
|
|
|
|
|
|
|
|
|
|
if (world->loaded) {
|
|
|
|
|
pxl8_bsp_destroy(&world->bsp);
|
|
|
|
|
world->loaded = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&world->bsp, 0, sizeof(pxl8_bsp));
|
|
|
|
|
|
|
|
|
|
pxl8_result result = pxl8_procgen(&world->bsp, params);
|
|
|
|
|
if (result != PXL8_OK) {
|
|
|
|
|
pxl8_error("Failed to generate world");
|
|
|
|
|
pxl8_bsp_destroy(&world->bsp);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
world->loaded = true;
|
|
|
|
|
pxl8_info("Generated world");
|
|
|
|
|
|
|
|
|
|
return PXL8_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-07 10:32:48 -05:00
|
|
|
pxl8_result pxl8_world_load(pxl8_world* world, const char* path) {
|
|
|
|
|
if (!world || !path) return PXL8_ERROR_INVALID_ARGUMENT;
|
|
|
|
|
|
|
|
|
|
if (world->loaded) {
|
|
|
|
|
pxl8_bsp_destroy(&world->bsp);
|
|
|
|
|
world->loaded = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&world->bsp, 0, sizeof(pxl8_bsp));
|
|
|
|
|
|
|
|
|
|
pxl8_result result = pxl8_bsp_load(path, &world->bsp);
|
|
|
|
|
if (result != PXL8_OK) {
|
|
|
|
|
pxl8_error("Failed to load world: %s", path);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
world->loaded = true;
|
|
|
|
|
pxl8_info("Loaded world: %s", path);
|
|
|
|
|
|
|
|
|
|
return PXL8_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
|
|
|
|
if (!world || !gfx || !world->loaded) return;
|
|
|
|
|
|
2025-11-09 06:30:17 -06:00
|
|
|
static bool texture_generated = false;
|
|
|
|
|
static u32 wall_texture_id = 0;
|
|
|
|
|
if (!texture_generated) {
|
|
|
|
|
u8 texture_data[64 * 64];
|
|
|
|
|
|
|
|
|
|
pxl8_procgen_tex_params tex_params = {
|
|
|
|
|
.seed = 12345,
|
|
|
|
|
.width = 64,
|
|
|
|
|
.height = 64,
|
|
|
|
|
.scale = 0.25f,
|
|
|
|
|
.roughness = 0.5f,
|
|
|
|
|
.base_color = 1,
|
|
|
|
|
.variation = 3
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pxl8_procgen_tex(texture_data, &tex_params);
|
|
|
|
|
|
|
|
|
|
pxl8_result result = pxl8_gfx_create_texture(gfx, texture_data, 64, 64);
|
|
|
|
|
if (result >= 0) {
|
|
|
|
|
wall_texture_id = (u32)result;
|
|
|
|
|
pxl8_gfx_upload_atlas(gfx);
|
|
|
|
|
texture_generated = true;
|
|
|
|
|
pxl8_info("Generated stone texture with ID: %u", wall_texture_id);
|
|
|
|
|
} else {
|
|
|
|
|
pxl8_error("Failed to create wall texture: %d", result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (world->wireframe) {
|
|
|
|
|
pxl8_bsp_render_wireframe(gfx, &world->bsp, camera_pos, world->wireframe_color);
|
|
|
|
|
} else {
|
|
|
|
|
pxl8_bsp_render_solid(gfx, &world->bsp, camera_pos, wall_texture_id);
|
|
|
|
|
}
|
2025-10-07 10:32:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pxl8_world_unload(pxl8_world* world) {
|
|
|
|
|
if (!world || !world->loaded) return;
|
|
|
|
|
|
|
|
|
|
pxl8_bsp_destroy(&world->bsp);
|
|
|
|
|
world->loaded = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool pxl8_world_is_loaded(const pxl8_world* world) {
|
|
|
|
|
return world && world->loaded;
|
|
|
|
|
}
|