power_play/src/phys.h

253 lines
6.9 KiB
C

#ifndef PHYS_H
#define PHYS_H
#include "collider.h"
#include "math.h"
struct space;
struct sim_ent_lookup;
struct sim_step_ctx;
struct phys_contact_constraint;
struct phys_collision_data {
struct sim_ent_id e0;
struct sim_ent_id e1;
struct v2 point;
struct v2 normal; /* Normal of the collision from e0 to e1 */
struct v2 vrel; /* Relative velocity at point of collision */
b32 is_start; /* Did this collision just begin */
f32 dt; /* How much time elapsed in the step when this event occurred (this will equal the physics timestep unless an early time of impact occurred) */
};
/* Callback can return true to prevent the physics system from resolving */
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_sim_step_ctx) b32 name(struct phys_collision_data *arg_collision_data, struct sim_step_ctx *arg_sim_step_ctx)
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision_data, ctx);
/* Structure containing data used for a single physics step */
struct phys_step_ctx {
struct sim_step_ctx *sim_step_ctx;
phys_collision_callback_func *collision_callback;
};
/* ========================== *
* Contact
* ========================== */
struct phys_contact_point {
/* Contact point relative to the center of each entity.
*
* NOTE: We use fixed (non-rotated) points relative to the entities
* rather than points fully in local space because contact manifolds
* shouldn't really be affected by rotation accross substeps
* (imagine re-building the manifold of a rotated shape, it would still be
* on the same side of the shape that it originally occured on) */
struct v2 vcp0;
struct v2 vcp1;
u32 id; /* ID generated during clipping */
f32 starting_separation; /* How far are original points along normal */
f32 normal_impulse; /* Accumulated impulse along normal */
f32 tangent_impulse; /* Accumulated impulse along tangent */
f32 inv_normal_mass;
f32 inv_tangent_mass;
/* Debugging */
#if DEVELOPER
struct v2 dbg_pt;
#endif
};
struct phys_contact_constraint {
u64 last_phys_iteration; /* To avoid checking collisions for the same constraint twice in one tick */
b32 skip_solve;
b32 wrong_dir;
struct sim_ent_id e0;
struct sim_ent_id e1;
f32 inv_m0;
f32 inv_m1;
f32 inv_i0;
f32 inv_i1;
struct v2 normal; /* Normal vector of collision from e0 -> e1 */
u64 last_iteration;
struct phys_contact_point points[2];
u32 num_points;
f32 friction;
f32 pushout_velocity;
};
struct phys_collision_debug {
struct sim_ent_id e0;
struct sim_ent_id e1;
struct collider_collision_points_result res;
struct phys_contact_point points[2];
u32 num_points;
struct v2 closest0;
struct v2 closest1;
struct xform xf0;
struct xform xf1;
};
void phys_create_and_update_contacts(struct phys_step_ctx *ctx, f32 elapsed_dt, u64 phys_iteration);
void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration);
void phys_warm_start_contacts(struct phys_step_ctx *ctx);
void phys_solve_contacts(struct phys_step_ctx *ctx, f32 dt, b32 apply_bias);
/* ========================== *
* Motor joint
* ========================== */
struct phys_motor_joint_def {
struct sim_ent_id e0;
struct sim_ent_id e1;
f32 correction_rate;
f32 max_force;
f32 max_torque;
};
struct phys_motor_joint {
struct sim_ent_id e0;
struct sim_ent_id e1;
f32 correction_rate;
f32 max_force;
f32 max_torque;
f32 inv_m0;
f32 inv_m1;
f32 inv_i0;
f32 inv_i1;
struct v2 linear_impulse;
f32 angular_impulse;
struct v2 point_local_e0;
struct v2 point_local_e1;
struct xform linear_mass_xf;
f32 angular_mass;
};
struct phys_motor_joint_def phys_motor_joint_def_init(void);
struct phys_motor_joint phys_motor_joint_from_def(struct phys_motor_joint_def def);
void phys_prepare_motor_joints(struct phys_step_ctx *ctx);
void phys_warm_start_motor_joints(struct phys_step_ctx *ctx);
void phys_solve_motor_joints(struct phys_step_ctx *ctx, f32 dt);
/* ========================== *
* Mouse joint
* ========================== */
struct phys_mouse_joint_def {
struct sim_ent_id target;
struct v2 point_local_start;
struct v2 point_end;
f32 linear_spring_hz;
f32 linear_spring_damp;
f32 angular_spring_hz;
f32 angular_spring_damp;
f32 max_force;
};
struct phys_mouse_joint {
struct sim_ent_id target;
struct v2 point_local_start;
struct v2 point_end;
f32 linear_spring_hz;
f32 linear_spring_damp;
f32 angular_spring_hz;
f32 angular_spring_damp;
f32 max_force;
f32 inv_m;
f32 inv_i;
struct v2 linear_impulse;
f32 angular_impulse;
struct xform linear_mass_xf;
};
struct phys_mouse_joint_def phys_mouse_joint_def_init(void);
struct phys_mouse_joint phys_mouse_joint_from_def(struct phys_mouse_joint_def def);
void phys_prepare_mouse_joints(struct phys_step_ctx *ctx);
void phys_warm_start_mouse_joints(struct phys_step_ctx *ctx);
void phys_solve_mouse_joints(struct phys_step_ctx *ctx, f32 dt);
/* ========================== *
* Weld joint
* ========================== */
struct phys_weld_joint_def {
struct sim_ent_id e0;
struct sim_ent_id e1;
/* The xform that transforms a point in e0's space into the desired e1 space
* (IE `xf` * V2(0, 0) should evaluate to the local point that e1's origin will lie) */
struct xform xf;
f32 linear_spring_hz;
f32 linear_spring_damp;
f32 angular_spring_hz;
f32 angular_spring_damp;
};
struct phys_weld_joint {
struct sim_ent_id e0;
struct sim_ent_id e1;
struct xform xf0_to_xf1;
f32 linear_spring_hz;
f32 linear_spring_damp;
f32 angular_spring_hz;
f32 angular_spring_damp;
f32 inv_m0;
f32 inv_m1;
f32 inv_i0;
f32 inv_i1;
struct v2 linear_impulse0;
struct v2 linear_impulse1;
f32 angular_impulse0;
f32 angular_impulse1;
};
struct phys_weld_joint_def phys_weld_joint_def_init(void);
struct phys_weld_joint phys_weld_joint_from_def(struct phys_weld_joint_def def);
void phys_prepare_weld_joints(struct phys_step_ctx *ctx);
void phys_warm_start_weld_joints(struct phys_step_ctx *ctx);
void phys_solve_weld_joints(struct phys_step_ctx *ctx, f32 dt);
/* ========================== *
* Integration
* ========================== */
void phys_integrate_forces(struct phys_step_ctx *ctx, f32 dt);
void phys_integrate_velocities(struct phys_step_ctx *ctx, f32 dt);
/* ========================== *
* Earliest time of impact
* ========================== */
f32 phys_determine_earliest_toi(struct phys_step_ctx *ctx, f32 step_dt, f32 tolerance, u32 max_iterations);
/* ========================== *
* Space
* ========================== */
void phys_update_aabbs(struct phys_step_ctx *ctx);
/* ========================== *
* Step
* ========================== */
void phys_step(struct phys_step_ctx *ctx, f32 timestep);
#endif