extern fn log_f32(value: f32);
struct SimContext {
sphere: Sphere,
water: Water,
gravity: f32,
}
struct Sphere {
radius: f32,
mass: f32, // density: f32,
height: f32,
velocity: f32,
}
struct Water {
density: f32,
}
pub fn new_sim() -> SimContext {
SimContext {
sphere: new_sphere(),
water: new_water(),
gravity: 9.81,
}
}
fn new_sphere() -> Sphere {
let radius = 1.0;
let density = 250.0;
let volume = calc_sphere_volume(radius);
let mass = density * volume;
Sphere {
radius,
mass,
height: 1.0,
velocity: 0.0,
}
}
fn new_water() -> Water {
Water {
density: 1000.0,
}
}
fn calc_submerged_ratio(s: Sphere) -> f32 {
let bottom = s.height - s.radius;
let diameter = 2.0 * s.radius;
if bottom >= 0.0 {
0.0
} else if bottom <= -diameter {
1.0
} else {
-bottom / diameter
}
}
fn calc_sphere_volume(radius: f32) -> f32 {
let pi = 3.1415926535897;
let r = radius;
3.0/4.0 * pi * r * r * r
}
fn calc_buoyancy_force(s: Sphere, w: Water, gravity: f32, submerged_ratio: f32) -> f32 {
let volume = calc_sphere_volume(s.radius);
volume * submerged_ratio * w.density * gravity
}
pub fn sim_update(ctx: SimContext, elapsed_secs: f32) {
let submerged_ratio = calc_submerged_ratio(ctx.sphere);
if submerged_ratio > 0.0 {
let buoyancy_force = calc_buoyancy_force(
ctx.sphere,
ctx.water,
ctx.gravity,
submerged_ratio
);
let buoyancy_acc = buoyancy_force / ctx.sphere.mass;
ctx.sphere.velocity += buoyancy_acc * elapsed_secs;
}
ctx.sphere.velocity -= ctx.gravity * elapsed_secs;
ctx.sphere.height += ctx.sphere.velocity * elapsed_secs;
log_f32(ctx.sphere.height);
}