dynamis-world 0.6.0

GPU-driven physics engine
Documentation
use dynamis_layout::{
    BODY_CCD, BODY_KINEMATIC, COLLIDER_EVENT_BEGIN_END, COLLIDER_EVENT_PERSIST, COLLIDER_SENSOR,
    CONSTRAINT_BALL, CONSTRAINT_CONE, CONSTRAINT_DISABLE_COLLISIONS, CONSTRAINT_DISTANCE,
    CONSTRAINT_GEAR, CONSTRAINT_HAS_BREAK, CONSTRAINT_HAS_LIMIT, CONSTRAINT_HAS_MOTOR,
    CONSTRAINT_HAS_SWING, CONSTRAINT_IS_SPRING, CONSTRAINT_PRISMATIC, CONSTRAINT_PULLEY,
    CONSTRAINT_REVOLUTE, CONSTRAINT_SIXDOF, CONSTRAINT_WARM_START, CONTACT_MAX_POINTS,
    COUNTER_ACTIVE, COUNTER_BLOCKS, COUNTER_CONTACTS, COUNTER_ENTRIES, COUNTER_EVENTS,
    COUNTER_JOINTS, COUNTER_LARGE, COUNTER_PAIRS, COUNTER_RESTING, COUNTER_RESTING_GATHER,
    COUNTER_SLEPT, COUNTER_SPILLOVER_ENTRIES, COUNTER_SPILLOVER_EVENTS, COUNTER_SPILLOVER_PAIRS,
    COUNTER_SPILLOVER_RESTING, COUNTER_STRIDE, COUNTER_WOKE, COUNTER_WOKE_DEFERRED, DOF_FREE,
    DOF_LIMITED, DOF_LOCKED, EDIT_ANGULAR_IMPULSE, EDIT_FORCE, EDIT_FORCE_AT_POINT, EDIT_IMPULSE,
    EDIT_IMPULSE_AT_POINT, EDIT_PATCH, EDIT_SLEEP, EDIT_TORQUE, EDIT_WAKE, EVENT_BEGIN, EVENT_END,
    EVENT_PERSIST, FILTER_IGNORE_KINEMATIC, FILTER_IGNORE_SENSORS, FILTER_IGNORE_SLEEPING,
    FILTER_IGNORE_STATIC, ISLAND_ACTIVE, ISLAND_WAKE, MAX_HITS_PER_QUERY, NO_BODY,
    NO_COLLISION_FILTER, NO_HIT, NO_SLOT, OVERRIDE_SLEEP_ANGULAR, OVERRIDE_SLEEP_LINEAR,
    PATCH_ANGULAR_VELOCITY, PATCH_ORIENTATION, PATCH_POSITION, PATCH_VELOCITY, QUERY_POINT,
    QUERY_RAY, QUERY_SPHERE, QUERY_SWEEP, SHAPE_CAPSULE, SHAPE_CUBOID, SHAPE_CYLINDER,
    SHAPE_HEIGHTFIELD, SHAPE_HULL, SHAPE_MESH, SHAPE_NONE, SHAPE_PLANE, SHAPE_SPHERE,
    SHAPE_TRIANGLE, SOLVER_BLOCK_CONSTRAINT, SOLVER_BLOCK_CONTACT,
};
use dynamis_model::MAX_COLLIDERS_PER_BODY;

pub(super) const WORKGROUP_SIZE: u32 = 64;

pub(super) const CORE_FRAGMENT: &str = include_str!("shaders/core.wgsl");
pub(super) const IDENTITY_FRAGMENT: &str = include_str!("shaders/identity.wgsl");
pub(super) const EVENTS_FRAGMENT: &str = include_str!("shaders/events.wgsl");
pub(super) const CONVEX_FRAGMENT: &str = include_str!("shaders/convex.wgsl");
pub(super) const SCENE_FRAGMENT: &str = include_str!("shaders/scene.wgsl");
pub(super) const CONTACT_BLOCK_FRAGMENT: &str = include_str!("shaders/solver_contact_block.wgsl");
pub(super) const CONSTRAINT_BLOCK_FRAGMENT: &str =
    include_str!("shaders/solver_constraint_block.wgsl");
pub(super) const CONTACT_CORRECTION_FRAGMENT: &str =
    include_str!("shaders/position_contact_block.wgsl");
pub(super) const SHAPES_FRAGMENT: &str = include_str!("shaders/shapes.wgsl");

pub(super) fn assemble_shader(body: &str, per_row: u32, fragments: &[&str]) -> String {
    let mut source = String::from(CORE_FRAGMENT);
    source.push('\n');
    for fragment in fragments {
        source.push_str(fragment);
        source.push('\n');
    }
    source.push_str(body);
    source.push('\n');
    source.push_str(SHAPES_FRAGMENT);
    source.push('\n');
    source.push_str(&shader_constants(per_row));
    source
}

fn shader_constants(per_row: u32) -> String {
    let mut source = String::new();
    let mut emit = |name: &str, value: u32| {
        source.push_str(&format!("const {name}: u32 = {value}u;\n"));
    };
    emit("WORKGROUP_SIZE", WORKGROUP_SIZE);
    emit("WORKGROUPS_PER_ROW", per_row);
    emit("EDIT_PATCH", EDIT_PATCH);
    emit("EDIT_FORCE", EDIT_FORCE);
    emit("EDIT_FORCE_AT_POINT", EDIT_FORCE_AT_POINT);
    emit("EDIT_TORQUE", EDIT_TORQUE);
    emit("EDIT_IMPULSE", EDIT_IMPULSE);
    emit("EDIT_IMPULSE_AT_POINT", EDIT_IMPULSE_AT_POINT);
    emit("EDIT_ANGULAR_IMPULSE", EDIT_ANGULAR_IMPULSE);
    emit("EDIT_SLEEP", EDIT_SLEEP);
    emit("EDIT_WAKE", EDIT_WAKE);
    emit("PATCH_POSITION", PATCH_POSITION);
    emit("PATCH_VELOCITY", PATCH_VELOCITY);
    emit("PATCH_ORIENTATION", PATCH_ORIENTATION);
    emit("PATCH_ANGULAR_VELOCITY", PATCH_ANGULAR_VELOCITY);
    emit("NO_COLLISION_FILTER", NO_COLLISION_FILTER);
    emit("SHAPE_NONE", SHAPE_NONE);
    emit("SHAPE_SPHERE", SHAPE_SPHERE);
    emit("SHAPE_CUBOID", SHAPE_CUBOID);
    emit("SHAPE_CAPSULE", SHAPE_CAPSULE);
    emit("SHAPE_CYLINDER", SHAPE_CYLINDER);
    emit("SHAPE_HULL", SHAPE_HULL);
    emit("SHAPE_MESH", SHAPE_MESH);
    emit("SHAPE_HEIGHTFIELD", SHAPE_HEIGHTFIELD);
    emit("SHAPE_PLANE", SHAPE_PLANE);
    emit("SHAPE_TRIANGLE", SHAPE_TRIANGLE);
    emit("BODY_KINEMATIC", BODY_KINEMATIC);
    emit("BODY_CCD", BODY_CCD);
    emit("OVERRIDE_SLEEP_LINEAR", OVERRIDE_SLEEP_LINEAR);
    emit("OVERRIDE_SLEEP_ANGULAR", OVERRIDE_SLEEP_ANGULAR);
    emit("COLLIDER_SENSOR", COLLIDER_SENSOR);
    emit("COLLIDER_EVENT_BEGIN_END", COLLIDER_EVENT_BEGIN_END);
    emit("COLLIDER_EVENT_PERSIST", COLLIDER_EVENT_PERSIST);
    emit("ISLAND_WAKE", ISLAND_WAKE);
    emit("ISLAND_ACTIVE", ISLAND_ACTIVE);
    emit("CONTACT_MAX_POINTS", CONTACT_MAX_POINTS);
    emit("CONSTRAINT_BALL", CONSTRAINT_BALL);
    emit("CONSTRAINT_DISTANCE", CONSTRAINT_DISTANCE);
    emit("CONSTRAINT_REVOLUTE", CONSTRAINT_REVOLUTE);
    emit("CONSTRAINT_PRISMATIC", CONSTRAINT_PRISMATIC);
    emit("CONSTRAINT_GEAR", CONSTRAINT_GEAR);
    emit("CONSTRAINT_PULLEY", CONSTRAINT_PULLEY);
    emit("CONSTRAINT_CONE", CONSTRAINT_CONE);
    emit("CONSTRAINT_SIXDOF", CONSTRAINT_SIXDOF);
    emit(
        "CONSTRAINT_DISABLE_COLLISIONS",
        CONSTRAINT_DISABLE_COLLISIONS,
    );
    emit("CONSTRAINT_HAS_LIMIT", CONSTRAINT_HAS_LIMIT);
    emit("CONSTRAINT_HAS_MOTOR", CONSTRAINT_HAS_MOTOR);
    emit("CONSTRAINT_IS_SPRING", CONSTRAINT_IS_SPRING);
    emit("CONSTRAINT_HAS_SWING", CONSTRAINT_HAS_SWING);
    emit("CONSTRAINT_HAS_BREAK", CONSTRAINT_HAS_BREAK);
    emit("CONSTRAINT_WARM_START", CONSTRAINT_WARM_START);
    emit("DOF_FREE", DOF_FREE);
    emit("DOF_LOCKED", DOF_LOCKED);
    emit("DOF_LIMITED", DOF_LIMITED);
    emit("QUERY_RAY", QUERY_RAY);
    emit("QUERY_SPHERE", QUERY_SPHERE);
    emit("QUERY_SWEEP", QUERY_SWEEP);
    emit("QUERY_POINT", QUERY_POINT);
    emit("FILTER_IGNORE_SENSORS", FILTER_IGNORE_SENSORS);
    emit("FILTER_IGNORE_SLEEPING", FILTER_IGNORE_SLEEPING);
    emit("FILTER_IGNORE_STATIC", FILTER_IGNORE_STATIC);
    emit("FILTER_IGNORE_KINEMATIC", FILTER_IGNORE_KINEMATIC);
    emit("EVENT_BEGIN", EVENT_BEGIN);
    emit("EVENT_END", EVENT_END);
    emit("EVENT_PERSIST", EVENT_PERSIST);
    emit("NO_BODY", NO_BODY);
    emit("NO_SLOT", NO_SLOT);
    emit("SOLVER_BLOCK_CONTACT", SOLVER_BLOCK_CONTACT);
    emit("SOLVER_BLOCK_CONSTRAINT", SOLVER_BLOCK_CONSTRAINT);
    emit("MAX_COLLIDERS_PER_BODY", MAX_COLLIDERS_PER_BODY as u32);
    emit("MAX_HITS_PER_QUERY", MAX_HITS_PER_QUERY);
    emit("EVENT_SLOTS", crate::dynamics::buffers::EVENT_SLOTS);
    emit("COUNTER_STRIDE_WORDS", (COUNTER_STRIDE / 4) as u32);
    emit("COUNTER_ENTRIES", COUNTER_ENTRIES as u32);
    emit("COUNTER_PAIRS", COUNTER_PAIRS as u32);
    emit("COUNTER_LARGE", COUNTER_LARGE as u32);
    emit("COUNTER_CONTACTS", COUNTER_CONTACTS as u32);
    emit("COUNTER_BLOCKS", COUNTER_BLOCKS as u32);
    emit("COUNTER_JOINTS", COUNTER_JOINTS as u32);
    emit("COUNTER_RESTING", COUNTER_RESTING as u32);
    emit("COUNTER_RESTING_GATHER", COUNTER_RESTING_GATHER as u32);
    emit("COUNTER_WOKE_DEFERRED", COUNTER_WOKE_DEFERRED as u32);
    emit("COUNTER_SLEPT", COUNTER_SLEPT as u32);
    emit("COUNTER_WOKE", COUNTER_WOKE as u32);
    emit("COUNTER_ACTIVE", COUNTER_ACTIVE as u32);
    emit("COUNTER_EVENTS", COUNTER_EVENTS as u32);
    emit("COUNTER_SPILLOVER_PAIRS", COUNTER_SPILLOVER_PAIRS as u32);
    emit(
        "COUNTER_SPILLOVER_RESTING",
        COUNTER_SPILLOVER_RESTING as u32,
    );
    emit("COUNTER_SPILLOVER_EVENTS", COUNTER_SPILLOVER_EVENTS as u32);
    emit(
        "COUNTER_SPILLOVER_ENTRIES",
        COUNTER_SPILLOVER_ENTRIES as u32,
    );
    source.push_str(&format!("const NO_HIT: f32 = {NO_HIT:e};\n"));
    source
}