diff --git a/demo3d/client/bsp/demo3d_bsp_render.c b/demo3d/client/bsp/demo3d_bsp_render.c index 284c61e..993ed39 100644 --- a/demo3d/client/bsp/demo3d_bsp_render.c +++ b/demo3d/client/bsp/demo3d_bsp_render.c @@ -104,10 +104,18 @@ demo3d_bsp_render_state* demo3d_bsp_render_state_create(u32 num_faces) { pxl8_free(state); return NULL; } + + state->visible_faces = pxl8_malloc(num_faces * sizeof(u32)); + if (!state->visible_faces) { + pxl8_free(state->render_face_flags); + pxl8_free(state); + return NULL; + } } state->mesh = pxl8_mesh_create(8192, 16384); if (!state->mesh) { + pxl8_free(state->visible_faces); pxl8_free(state->render_face_flags); pxl8_free(state); return NULL; @@ -120,6 +128,9 @@ void demo3d_bsp_render_state_destroy(demo3d_bsp_render_state* state) { if (!state) return; pxl8_free(state->materials); pxl8_mesh_destroy(state->mesh); + pxl8_free(state->mat_write_pos); + pxl8_free(state->mat_offsets); + pxl8_free(state->visible_faces); pxl8_free(state->render_face_flags); pxl8_free(state); } @@ -140,18 +151,38 @@ void demo3d_bsp_render(pxl8_gfx* gfx, const demo3d_bsp* bsp, u8 ambient = pxl8_gfx_get_ambient(gfx); pxl8_mat4 identity = pxl8_mat4_identity(); - u8 mat_has_faces[256] = {0}; - for (u32 face_id = 0; face_id < bsp->num_faces; face_id++) { + u32 mat_count = state->num_materials; + if (!state->mat_offsets || !state->mat_write_pos) return; + + memset(state->mat_offsets, 0, (mat_count + 1) * sizeof(u32)); + + for (u32 face_id = 0; face_id < bsp->num_faces && face_id < state->num_faces; face_id++) { if (!state->render_face_flags[face_id]) continue; u16 mid = bsp->faces[face_id].material_id; - if (mid < state->num_materials) mat_has_faces[mid] = 1; + if (mid < mat_count) state->mat_offsets[mid]++; } - for (u32 mat = 0; mat < state->num_materials; mat++) { - if (!mat_has_faces[mat]) continue; - for (u32 face_id = 0; face_id < bsp->num_faces; face_id++) { - if (!state->render_face_flags[face_id]) continue; - if (bsp->faces[face_id].material_id != mat) continue; + u32 running = 0; + for (u32 i = 0; i < mat_count; i++) { + u32 c = state->mat_offsets[i]; + state->mat_offsets[i] = running; + running += c; + } + state->mat_offsets[mat_count] = running; + + memcpy(state->mat_write_pos, state->mat_offsets, mat_count * sizeof(u32)); + + for (u32 face_id = 0; face_id < bsp->num_faces && face_id < state->num_faces; face_id++) { + if (!state->render_face_flags[face_id]) continue; + u16 mid = bsp->faces[face_id].material_id; + if (mid < mat_count) { + state->visible_faces[state->mat_write_pos[mid]++] = face_id; + } + } + + for (u32 mat = 0; mat < mat_count; mat++) { + for (u32 i = state->mat_offsets[mat]; i < state->mat_offsets[mat + 1]; i++) { + u32 face_id = state->visible_faces[i]; if (!face_in_frustum(bsp, face_id, frustum)) continue; collect_face_to_mesh(bsp, state, face_id, mesh, ambient); } @@ -184,6 +215,9 @@ void demo3d_bsp_set_material(demo3d_bsp_render_state* state, u16 material_id, co state->materials = new_materials; state->num_materials = new_count; + + state->mat_offsets = pxl8_realloc(state->mat_offsets, (new_count + 1) * sizeof(u32)); + state->mat_write_pos = pxl8_realloc(state->mat_write_pos, new_count * sizeof(u32)); } pxl8_vec3 u_axis = state->materials[material_id].u_axis; diff --git a/demo3d/client/bsp/demo3d_bsp_render.h b/demo3d/client/bsp/demo3d_bsp_render.h index 9e19e65..658aa54 100644 --- a/demo3d/client/bsp/demo3d_bsp_render.h +++ b/demo3d/client/bsp/demo3d_bsp_render.h @@ -12,6 +12,9 @@ typedef struct demo3d_bsp_render_state { pxl8_gfx_material* materials; pxl8_mesh* mesh; u8* render_face_flags; + u32* visible_faces; + u32* mat_offsets; + u32* mat_write_pos; u32 num_materials; u32 num_faces; bool exterior; diff --git a/src/gfx/pxl8_particles.c b/src/gfx/pxl8_particles.c index 19a62c0..8947998 100644 --- a/src/gfx/pxl8_particles.c +++ b/src/gfx/pxl8_particles.c @@ -64,12 +64,7 @@ void pxl8_particles_destroy(pxl8_particles* ps) { } void pxl8_particles_clear(pxl8_particles* ps) { - if (!ps || !ps->particles) return; - - for (u32 i = 0; i < ps->max_count; i++) { - ps->particles[i].life = 0; - ps->particles[i].flags = 0; - } + if (!ps) return; ps->alive_count = 0; ps->spawn_timer = 0; } @@ -78,63 +73,56 @@ void pxl8_particles_emit(pxl8_particles* ps, u32 count) { if (!ps || !ps->particles) return; for (u32 i = 0; i < count && ps->alive_count < ps->max_count; i++) { - for (u32 j = 0; j < ps->max_count; j++) { - if (ps->particles[j].life <= 0) { - pxl8_particle* p = &ps->particles[j]; + pxl8_particle* p = &ps->particles[ps->alive_count]; - f32 life = ps->life_min + pxl8_rng_f32(ps->rng) * (ps->life_max - ps->life_min); - p->life = life; - p->max_life = life; + f32 life = ps->life_min + pxl8_rng_f32(ps->rng) * (ps->life_max - ps->life_min); + p->life = life; + p->max_life = life; - p->x = ps->x + (pxl8_rng_f32(ps->rng) - 0.5f) * ps->spread_x; - p->y = ps->y + (pxl8_rng_f32(ps->rng) - 0.5f) * ps->spread_y; - p->z = 0; + p->x = ps->x + (pxl8_rng_f32(ps->rng) - 0.5f) * ps->spread_x; + p->y = ps->y + (pxl8_rng_f32(ps->rng) - 0.5f) * ps->spread_y; + p->z = 0; - p->vx = ps->vx_min + pxl8_rng_f32(ps->rng) * (ps->vx_max - ps->vx_min); - p->vy = ps->vy_min + pxl8_rng_f32(ps->rng) * (ps->vy_max - ps->vy_min); - p->vz = 0; + p->vx = ps->vx_min + pxl8_rng_f32(ps->rng) * (ps->vx_max - ps->vx_min); + p->vy = ps->vy_min + pxl8_rng_f32(ps->rng) * (ps->vy_max - ps->vy_min); + p->vz = 0; - p->ax = ps->gravity_x; - p->ay = ps->gravity_y; - p->az = 0; + p->ax = ps->gravity_x; + p->ay = ps->gravity_y; + p->az = 0; - u8 ramp_range = ps->color_max - ps->color_min + 1; - u8 ramp_pos = ps->color_min + (pxl8_rng_next(ps->rng) % ramp_range); - u8 color = ps->palette - ? pxl8_palette_ramp_index(ps->palette, ramp_pos) - : ramp_pos; - p->color = p->start_color = p->end_color = color; + u8 ramp_range = ps->color_max - ps->color_min + 1; + u8 ramp_pos = ps->color_min + (pxl8_rng_next(ps->rng) % ramp_range); + u8 color = ps->palette + ? pxl8_palette_ramp_index(ps->palette, ramp_pos) + : ramp_pos; + p->color = p->start_color = p->end_color = color; - p->size = ps->size_min + pxl8_rng_f32(ps->rng) * (ps->size_max - ps->size_min); - p->angle = 0; - p->spin = 0; - p->flags = 1; + p->size = ps->size_min + pxl8_rng_f32(ps->rng) * (ps->size_max - ps->size_min); + p->angle = 0; + p->spin = 0; + p->flags = 1; - if (ps->spawn_fn) { - ps->spawn_fn(ps, p); - } - - ps->alive_count++; - break; - } + if (ps->spawn_fn) { + ps->spawn_fn(ps, p); } + + ps->alive_count++; } } void pxl8_particles_render(pxl8_particles* ps, pxl8_gfx* gfx) { if (!ps || !ps->particles || !gfx) return; - for (u32 i = 0; i < ps->max_count; i++) { + for (u32 i = 0; i < ps->alive_count; i++) { pxl8_particle* p = &ps->particles[i]; - if (p->life > 0 && p->flags) { - if (ps->render_fn) { - ps->render_fn(gfx, p, ps->userdata); - } else { - i32 x = (i32)p->x; - i32 y = (i32)p->y; - if (x >= 0 && x < pxl8_gfx_get_width(gfx) && y >= 0 && y < pxl8_gfx_get_height(gfx)) { - pxl8_2d_pixel(gfx, x, y, p->color); - } + if (ps->render_fn) { + ps->render_fn(gfx, p, ps->userdata); + } else { + i32 x = (i32)p->x; + i32 y = (i32)p->y; + if (x >= 0 && x < pxl8_gfx_get_width(gfx) && y >= 0 && y < pxl8_gfx_get_height(gfx)) { + pxl8_2d_pixel(gfx, x, y, p->color); } } } @@ -150,38 +138,44 @@ void pxl8_particles_update(pxl8_particles* ps, f32 dt) { if (max_spawns_per_frame < 1) max_spawns_per_frame = 1; u32 spawn_count = 0; while (ps->spawn_timer >= spawn_interval && spawn_count < max_spawns_per_frame) { - pxl8_particles_emit(ps, 1); ps->spawn_timer -= spawn_interval; spawn_count++; } + if (spawn_count > 0) { + pxl8_particles_emit(ps, spawn_count); + } } - for (u32 i = 0; i < ps->max_count; i++) { + u32 i = 0; + while (i < ps->alive_count) { pxl8_particle* p = &ps->particles[i]; - if (p->life > 0) { - if (ps->update_fn) { - ps->update_fn(p, dt, ps->userdata); - } else { - p->vx += p->ax * dt; - p->vy += p->ay * dt; - p->vz += p->az * dt; - p->vx *= ps->drag; - p->vy *= ps->drag; - p->vz *= ps->drag; + if (ps->update_fn) { + ps->update_fn(p, dt, ps->userdata); + } else { + p->vx += p->ax * dt; + p->vy += p->ay * dt; + p->vz += p->az * dt; - p->x += p->vx * dt; - p->y += p->vy * dt; - p->z += p->vz * dt; + p->vx *= ps->drag; + p->vy *= ps->drag; + p->vz *= ps->drag; - p->angle += p->spin * dt; - } - - p->life -= dt / p->max_life; - if (p->life <= 0) { - p->flags = 0; - ps->alive_count--; + p->x += p->vx * dt; + p->y += p->vy * dt; + p->z += p->vz * dt; + + p->angle += p->spin * dt; + } + + p->life -= dt / p->max_life; + if (p->life <= 0) { + ps->alive_count--; + if (i < ps->alive_count) { + ps->particles[i] = ps->particles[ps->alive_count]; } + } else { + i++; } } }