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
}