major gfx refactor
This commit is contained in:
parent
0c0aa792c1
commit
3c3e961995
58 changed files with 3681 additions and 2982 deletions
|
|
@ -30,13 +30,14 @@ struct pxl8_world {
|
|||
pxl8_entity_pool* entities;
|
||||
pxl8_bsp_render_state* bsp_render_state;
|
||||
pxl8_vxl_render_state* vxl_render_state;
|
||||
pxl8_sdf sdf;
|
||||
i32 render_distance;
|
||||
i32 sim_distance;
|
||||
|
||||
pxl8_sim_entity local_player;
|
||||
u64 client_tick;
|
||||
|
||||
pxl8_vec2 pointer_motion;
|
||||
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
pxl8_sim_entity render_state[2];
|
||||
atomic_uint active_buffer;
|
||||
|
|
@ -187,100 +188,6 @@ static void userdata_to_entity(const u8* userdata, pxl8_sim_entity* ent) {
|
|||
memcpy(&ent->kind, p, 2);
|
||||
}
|
||||
|
||||
static void update_sdf(pxl8_world* world, pxl8_vec3 center, f32 cell_size) {
|
||||
if (!world) return;
|
||||
|
||||
world->sdf.cell = cell_size;
|
||||
world->sdf.origin.x = center.x - (PXL8_SDF_X / 2) * cell_size;
|
||||
world->sdf.origin.y = center.y - (PXL8_SDF_Y / 2) * cell_size;
|
||||
world->sdf.origin.z = center.z - (PXL8_SDF_Z / 2) * cell_size;
|
||||
|
||||
i16 seed_x[PXL8_SDF_SIZE];
|
||||
i16 seed_y[PXL8_SDF_SIZE];
|
||||
i16 seed_z[PXL8_SDF_SIZE];
|
||||
|
||||
for (i32 iy = 0; iy < PXL8_SDF_Y; iy++) {
|
||||
f32 wy = world->sdf.origin.y + (iy + 0.5f) * cell_size;
|
||||
for (i32 iz = 0; iz < PXL8_SDF_Z; iz++) {
|
||||
f32 wz = world->sdf.origin.z + (iz + 0.5f) * cell_size;
|
||||
for (i32 ix = 0; ix < PXL8_SDF_X; ix++) {
|
||||
f32 wx = world->sdf.origin.x + (ix + 0.5f) * cell_size;
|
||||
i32 idx = iy * PXL8_SDF_Z * PXL8_SDF_X + iz * PXL8_SDF_X + ix;
|
||||
|
||||
if (pxl8_world_point_solid(world, wx, wy, wz)) {
|
||||
seed_x[idx] = (i16)ix;
|
||||
seed_y[idx] = (i16)iy;
|
||||
seed_z[idx] = (i16)iz;
|
||||
} else {
|
||||
seed_x[idx] = -1;
|
||||
seed_y[idx] = -1;
|
||||
seed_z[idx] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i32 step = 16; step >= 1; step /= 2) {
|
||||
for (i32 iy = 0; iy < PXL8_SDF_Y; iy++) {
|
||||
for (i32 iz = 0; iz < PXL8_SDF_Z; iz++) {
|
||||
for (i32 ix = 0; ix < PXL8_SDF_X; ix++) {
|
||||
i32 idx = iy * PXL8_SDF_Z * PXL8_SDF_X + iz * PXL8_SDF_X + ix;
|
||||
i32 best_dist_sq = (seed_x[idx] >= 0)
|
||||
? (ix - seed_x[idx]) * (ix - seed_x[idx]) +
|
||||
(iy - seed_y[idx]) * (iy - seed_y[idx]) +
|
||||
(iz - seed_z[idx]) * (iz - seed_z[idx])
|
||||
: 0x7FFFFFFF;
|
||||
|
||||
for (i32 dy = -step; dy <= step; dy += step) {
|
||||
i32 ny = iy + dy;
|
||||
if (ny < 0 || ny >= PXL8_SDF_Y) continue;
|
||||
for (i32 dz = -step; dz <= step; dz += step) {
|
||||
i32 nz = iz + dz;
|
||||
if (nz < 0 || nz >= PXL8_SDF_Z) continue;
|
||||
for (i32 dx = -step; dx <= step; dx += step) {
|
||||
if (dx == 0 && dy == 0 && dz == 0) continue;
|
||||
i32 nx = ix + dx;
|
||||
if (nx < 0 || nx >= PXL8_SDF_X) continue;
|
||||
|
||||
i32 nidx = ny * PXL8_SDF_Z * PXL8_SDF_X + nz * PXL8_SDF_X + nx;
|
||||
if (seed_x[nidx] < 0) continue;
|
||||
|
||||
i32 dist_sq = (ix - seed_x[nidx]) * (ix - seed_x[nidx]) +
|
||||
(iy - seed_y[nidx]) * (iy - seed_y[nidx]) +
|
||||
(iz - seed_z[nidx]) * (iz - seed_z[nidx]);
|
||||
|
||||
if (dist_sq < best_dist_sq) {
|
||||
best_dist_sq = dist_sq;
|
||||
seed_x[idx] = seed_x[nidx];
|
||||
seed_y[idx] = seed_y[nidx];
|
||||
seed_z[idx] = seed_z[nidx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < PXL8_SDF_SIZE; i++) {
|
||||
if (seed_x[i] < 0) {
|
||||
world->sdf.data[i] = 127;
|
||||
} else {
|
||||
i32 idx_x = i % PXL8_SDF_X;
|
||||
i32 idx_z = (i / PXL8_SDF_X) % PXL8_SDF_Z;
|
||||
i32 idx_y = i / (PXL8_SDF_X * PXL8_SDF_Z);
|
||||
i32 dx = idx_x - seed_x[i];
|
||||
i32 dy = idx_y - seed_y[i];
|
||||
i32 dz = idx_z - seed_z[i];
|
||||
f32 dist = sqrtf((f32)(dx * dx + dy * dy + dz * dz));
|
||||
i32 d = (i32)(dist * cell_size);
|
||||
if (d > 127) d = 127;
|
||||
world->sdf.data[i] = (i8)d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pxl8_world_point_solid(const pxl8_world* world, f32 x, f32 y, f32 z) {
|
||||
if (!world) return false;
|
||||
|
||||
|
|
@ -395,18 +302,22 @@ void pxl8_world_update(pxl8_world* world, const pxl8_input_state* input, f32 dt)
|
|||
msg.look_dx = (f32)pxl8_mouse_dx(input);
|
||||
msg.look_dy = (f32)pxl8_mouse_dy(input);
|
||||
msg.buttons = pxl8_key_down(input, "space") ? 1 : 0;
|
||||
msg.tick = world->client_tick;
|
||||
msg.timestamp = pxl8_get_ticks_ns();
|
||||
|
||||
if (world->net) {
|
||||
pxl8_net_send_input(world->net, &msg);
|
||||
}
|
||||
|
||||
pxl8_sim_world sim = make_sim_world(world, world->local_player.pos);
|
||||
pxl8_sim_move_player(&world->local_player, &msg, &sim, dt);
|
||||
world->client_tick++;
|
||||
}
|
||||
}
|
||||
|
||||
void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
||||
if (!world || !gfx) return;
|
||||
|
||||
update_sdf(world, camera_pos, PXL8_SDF_CELL);
|
||||
pxl8_3d_set_sdf(gfx, &world->sdf);
|
||||
|
||||
if (world->active_chunk) {
|
||||
if (world->active_chunk->type == PXL8_WORLD_CHUNK_BSP && world->active_chunk->bsp) {
|
||||
pxl8_3d_set_bsp(gfx, world->active_chunk->bsp);
|
||||
|
|
@ -421,13 +332,10 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos) {
|
|||
|
||||
const pxl8_frustum* frustum = pxl8_3d_get_frustum(gfx);
|
||||
|
||||
bool wireframe = world->vxl_render_state && world->vxl_render_state->wireframe;
|
||||
pxl8_gfx_material mat = {
|
||||
.texture_id = 0,
|
||||
.dynamic_lighting = true,
|
||||
.vertex_color_passthrough = true,
|
||||
.alpha = 255,
|
||||
.wireframe = wireframe,
|
||||
};
|
||||
|
||||
i32 r = world->render_distance;
|
||||
|
|
@ -481,16 +389,27 @@ void pxl8_world_sync(pxl8_world* world, pxl8_net* net) {
|
|||
world->active_chunk = chunk;
|
||||
pxl8_debug("[CLIENT] Synced BSP chunk id=%u as active (verts=%u faces=%u)",
|
||||
chunk_id, chunk->bsp->num_vertices, chunk->bsp->num_faces);
|
||||
|
||||
if (world->bsp_render_state) {
|
||||
pxl8_bsp_render_state_destroy(world->bsp_render_state);
|
||||
world->bsp_render_state = NULL;
|
||||
}
|
||||
world->bsp_render_state = pxl8_bsp_render_state_create(chunk->bsp->num_faces);
|
||||
}
|
||||
}
|
||||
} else if (chunk_id == 0 && world->active_chunk != NULL) {
|
||||
world->active_chunk = NULL;
|
||||
if (world->bsp_render_state) {
|
||||
pxl8_bsp_render_state_destroy(world->bsp_render_state);
|
||||
world->bsp_render_state = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_bsp_render_state(pxl8_world* world) {
|
||||
if (!world || world->bsp_render_state) return;
|
||||
if (!world->active_chunk || world->active_chunk->type != PXL8_WORLD_CHUNK_BSP) return;
|
||||
if (!world->active_chunk) return;
|
||||
if (world->active_chunk->type != PXL8_WORLD_CHUNK_BSP) return;
|
||||
if (!world->active_chunk->bsp) return;
|
||||
|
||||
world->bsp_render_state = pxl8_bsp_render_state_create(world->active_chunk->bsp->num_faces);
|
||||
|
|
@ -505,18 +424,6 @@ void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_
|
|||
pxl8_bsp_set_material(world->bsp_render_state, material_id, material);
|
||||
}
|
||||
|
||||
void pxl8_world_set_wireframe(pxl8_world* world, bool enabled) {
|
||||
if (!world) return;
|
||||
|
||||
ensure_bsp_render_state(world);
|
||||
if (world->bsp_render_state) {
|
||||
pxl8_bsp_set_wireframe(world->bsp_render_state, enabled);
|
||||
}
|
||||
if (world->vxl_render_state) {
|
||||
pxl8_vxl_set_wireframe(world->vxl_render_state, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
i32 pxl8_world_get_render_distance(const pxl8_world* world) {
|
||||
if (!world) return 3;
|
||||
return world->render_distance;
|
||||
|
|
@ -559,8 +466,15 @@ void pxl8_world_init_local_player(pxl8_world* world, f32 x, f32 y, f32 z) {
|
|||
|
||||
pxl8_sim_entity* pxl8_world_local_player(pxl8_world* world) {
|
||||
if (!world) return NULL;
|
||||
#ifdef PXL8_ASYNC_THREADS
|
||||
const pxl8_sim_entity* state = pxl8_world_get_render_state(world);
|
||||
if (!state) return NULL;
|
||||
if (!(state->flags & PXL8_SIM_FLAG_ALIVE)) return NULL;
|
||||
return (pxl8_sim_entity*)state;
|
||||
#else
|
||||
if (!(world->local_player.flags & PXL8_SIM_FLAG_ALIVE)) return NULL;
|
||||
return &world->local_player;
|
||||
#endif
|
||||
}
|
||||
|
||||
void pxl8_world_predict(pxl8_world* world, pxl8_net* net, const pxl8_input_msg* input, f32 dt) {
|
||||
|
|
@ -585,7 +499,14 @@ void pxl8_world_reconcile(pxl8_world* world, pxl8_net* net, f32 dt) {
|
|||
const u8* server_state = pxl8_net_entity_userdata(net, player_id);
|
||||
if (!server_state) return;
|
||||
|
||||
userdata_to_entity(server_state, &world->local_player);
|
||||
pxl8_sim_entity server_player = {0};
|
||||
userdata_to_entity(server_state, &server_player);
|
||||
|
||||
if (!(server_player.flags & PXL8_SIM_FLAG_ALIVE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
world->local_player = server_player;
|
||||
|
||||
const pxl8_snapshot_header* snap = pxl8_net_snapshot(net);
|
||||
u64 server_tick = snap ? snap->tick : 0;
|
||||
|
|
@ -606,11 +527,9 @@ void pxl8_world_reconcile(pxl8_world* world, pxl8_net* net, f32 dt) {
|
|||
#define SIM_TIMESTEP (1.0f / 60.0f)
|
||||
|
||||
static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
||||
if (!(world->local_player.flags & PXL8_SIM_FLAG_ALIVE)) return;
|
||||
|
||||
bool alive = (world->local_player.flags & PXL8_SIM_FLAG_ALIVE) != 0;
|
||||
pxl8_input_msg merged = {0};
|
||||
pxl8_input_msg* input = NULL;
|
||||
bool has_input = false;
|
||||
|
||||
while ((input = pxl8_queue_pop(&world->input_queue))) {
|
||||
merged.look_dx += input->look_dx;
|
||||
|
|
@ -618,16 +537,31 @@ static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
|||
merged.move_x = input->move_x;
|
||||
merged.move_y = input->move_y;
|
||||
merged.buttons |= input->buttons;
|
||||
has_input = true;
|
||||
pxl8_free(input);
|
||||
}
|
||||
|
||||
if (!alive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const f32 MAX_LOOK_DELTA = 100.0f;
|
||||
if (merged.look_dx > MAX_LOOK_DELTA) merged.look_dx = MAX_LOOK_DELTA;
|
||||
if (merged.look_dx < -MAX_LOOK_DELTA) merged.look_dx = -MAX_LOOK_DELTA;
|
||||
if (merged.look_dy > MAX_LOOK_DELTA) merged.look_dy = MAX_LOOK_DELTA;
|
||||
if (merged.look_dy < -MAX_LOOK_DELTA) merged.look_dy = -MAX_LOOK_DELTA;
|
||||
|
||||
merged.tick = world->client_tick;
|
||||
merged.timestamp = pxl8_get_ticks_ns();
|
||||
merged.yaw = world->pointer_motion.yaw;
|
||||
if (world->net) {
|
||||
pxl8_net_send_input(world->net, &merged);
|
||||
}
|
||||
|
||||
world->local_player.yaw = world->pointer_motion.yaw;
|
||||
world->local_player.pitch = world->pointer_motion.pitch;
|
||||
merged.look_dx = 0;
|
||||
merged.look_dy = 0;
|
||||
|
||||
pxl8_sim_world sim = make_sim_world(world, world->local_player.pos);
|
||||
pxl8_sim_move_player(&world->local_player, &merged, &sim, dt);
|
||||
|
||||
|
|
@ -637,7 +571,6 @@ static void pxl8_world_sim_tick(pxl8_world* world, f32 dt) {
|
|||
}
|
||||
|
||||
world->client_tick++;
|
||||
(void)has_input;
|
||||
}
|
||||
|
||||
static void pxl8_world_swap_buffers(pxl8_world* world) {
|
||||
|
|
@ -737,6 +670,12 @@ void pxl8_world_pause_sim(pxl8_world* world, bool paused) {
|
|||
void pxl8_world_push_input(pxl8_world* world, const pxl8_input_msg* input) {
|
||||
if (!world || !input) return;
|
||||
|
||||
world->pointer_motion.yaw -= input->look_dx * 0.008f;
|
||||
f32 pitch = world->pointer_motion.pitch - input->look_dy * 0.008f;
|
||||
if (pitch > PXL8_SIM_MAX_PITCH) pitch = PXL8_SIM_MAX_PITCH;
|
||||
if (pitch < -PXL8_SIM_MAX_PITCH) pitch = -PXL8_SIM_MAX_PITCH;
|
||||
world->pointer_motion.pitch = pitch;
|
||||
|
||||
pxl8_input_msg* copy = pxl8_malloc(sizeof(pxl8_input_msg));
|
||||
if (copy) {
|
||||
*copy = *input;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ void pxl8_world_render(pxl8_world* world, pxl8_gfx* gfx, pxl8_vec3 camera_pos);
|
|||
void pxl8_world_sync(pxl8_world* world, pxl8_net* net);
|
||||
|
||||
void pxl8_world_set_bsp_material(pxl8_world* world, u16 material_id, const pxl8_gfx_material* material);
|
||||
void pxl8_world_set_wireframe(pxl8_world* world, bool enabled);
|
||||
|
||||
i32 pxl8_world_get_render_distance(const pxl8_world* world);
|
||||
void pxl8_world_set_render_distance(pxl8_world* world, i32 distance);
|
||||
|
|
|
|||
|
|
@ -409,8 +409,7 @@ pxl8_result pxl8_world_chunk_cache_receive(pxl8_world_chunk_cache* cache,
|
|||
(hdr->chunk_type == PXL8_CHUNK_TYPE_BSP && a->id != hdr->id) ||
|
||||
(hdr->chunk_type == PXL8_CHUNK_TYPE_VXL &&
|
||||
(a->cx != hdr->cx || a->cy != hdr->cy || a->cz != hdr->cz)) ||
|
||||
a->version != hdr->version ||
|
||||
hdr->fragment_idx == 0;
|
||||
a->version != hdr->version;
|
||||
|
||||
if (new_assembly) {
|
||||
assembly_init(a, hdr);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define PXL8_WORLD_CHUNK_CACHE_SIZE 512
|
||||
#define PXL8_WORLD_CHUNK_MAX_FRAGMENTS 64
|
||||
#define PXL8_WORLD_CHUNK_MAX_FRAGMENTS 255
|
||||
#define PXL8_WORLD_CHUNK_MAX_DATA_SIZE 131072
|
||||
|
||||
typedef struct pxl8_world_chunk_cache_entry {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue