gutter_runner/game/physics/immediate.odin

224 lines
4.6 KiB
Odin

package physics
import "core:log"
import "libs:tracy"
_ :: log
Body_Config_Inertia_Mode :: enum {
From_Shape,
Explicit,
}
Immedate_State :: struct($T: typeid) {
handle: T,
// When was this referenced last time (frame number)
last_ref: u32,
}
Immediate_Container :: struct($T: typeid) {
items: map[u32]Immedate_State(T),
num_items: i32,
}
// When ok = true, it means we found an existing item
immediate_container_find_or_add :: proc(
c: $T/^Immediate_Container($E),
simulation_frame: u32,
id: u32,
) -> (
handle: ^E,
ok: bool,
) {
if id in c.items {
item := &c.items[id]
if item.last_ref != simulation_frame {
item.last_ref = simulation_frame
c.num_items += 1
}
handle = &item.handle
ok = true
} else {
c.num_items += 1
c.items[id] = {
handle = {},
last_ref = simulation_frame,
}
item := &c.items[id]
handle = &item.handle
ok = false
}
return
}
// Returns removed handles, allocated using allocator
immediate_container_prune :: proc(
c: $T/^Immediate_Container($E),
simulation_frame: u32,
allocator := context.temp_allocator,
) -> (
removed_handles: []E,
) {
if int(c.num_items) == len(c.items) {
return
}
num_unreferenced := len(c.items) - int(c.num_items)
assert(num_unreferenced >= 0)
removed_handles = make([]E, num_unreferenced, allocator)
items_to_remove := make([]u32, num_unreferenced, context.temp_allocator)
i := 0
for k, &v in c.items {
if v.last_ref != simulation_frame {
items_to_remove[i] = k
removed_handles[i] = v.handle
i += 1
}
}
assert(i == len(items_to_remove))
for k in items_to_remove {
delete_key(&c.items, k)
}
return
}
copy_map :: proc(dst, src: $T/^map[$K]$V) {
clear(dst)
reserve_map(dst, len(src))
for k, v in src {
dst[k] = v
}
}
immediate_container_copy :: proc(dst, src: $T/^Immediate_Container($E)) {
copy_map(&dst.items, &src.items)
dst.num_items = src.num_items
}
immediate_container_destroy :: proc(c: $T/^Immediate_Container($E)) {
delete_map(c.items)
}
immediate_body :: proc(scene: ^Scene, id: u32, config: Body_Config) -> (handle: Body_Handle) {
state := &scene.solver_state
sim_state := get_sim_state(scene)
h, ok := immediate_container_find_or_add(&state.immediate_bodies, state.simulation_frame, id)
if ok {
update_body_from_config(sim_state, get_body(sim_state, h^), config)
} else {
h^ = add_body(sim_state, config)
}
handle = h^
return
}
immediate_suspension_constraint :: proc(
scene: ^Scene,
id: u32,
config: Suspension_Constraint_Config,
) -> (
handle: Suspension_Constraint_Handle,
) {
state := &scene.solver_state
h, ok := immediate_container_find_or_add(
&state.immediate_suspension_constraints,
state.simulation_frame,
id,
)
if !ok {
h^ = add_suspension_constraint(get_sim_state(scene), {})
}
handle = h^
update_suspension_constraint_from_config(
get_suspension_constraint(get_sim_state(scene), handle),
config,
)
return
}
immediate_engine :: proc(
scene: ^Scene,
id: u32,
config: Engine_Config,
) -> (
handle: Engine_Handle,
) {
state := &scene.solver_state
sim_state := get_sim_state(scene)
h, ok := immediate_container_find_or_add(&state.immediate_engines, state.simulation_frame, id)
if ok {
update_engine_from_config(sim_state, get_engine(sim_state, h^), config)
} else {
h^ = add_engine(sim_state, config)
}
handle = h^
return
}
immediate_level_geom :: proc(
scene: ^Scene,
id: u32,
config: Level_Geom_Config,
) -> (
handle: Level_Geom_Handle,
) {
state := &scene.solver_state
sim_state := get_sim_state(scene)
h, ok := immediate_container_find_or_add(
&state.immediate_level_geoms,
state.simulation_frame,
id,
)
if ok {
update_level_geom_from_config(sim_state, get_level_geom(sim_state, h^), config)
} else {
h^ = add_level_geom(sim_state, config)
}
return
}
prune_immediate :: proc(scene: ^Scene) {
tracy.Zone()
sim_state := get_sim_state(scene)
state := &scene.solver_state
removed_bodies := immediate_container_prune(&state.immediate_bodies, state.simulation_frame)
removed_wheels := immediate_container_prune(
&state.immediate_suspension_constraints,
state.simulation_frame,
)
removed_engines := immediate_container_prune(&state.immediate_engines, state.simulation_frame)
removed_level_geoms := immediate_container_prune(
&state.immediate_level_geoms,
state.simulation_frame,
)
for handle in removed_bodies {
remove_body(sim_state, handle)
}
for handle in removed_wheels {
remove_suspension_constraint(sim_state, handle)
}
for handle in removed_engines {
remove_engine(sim_state, handle)
}
for handle in removed_level_geoms {
remove_level_geom(sim_state, handle)
}
}