/** * Per-body reference poses for contact reuse: a body that has moved or turned beyond the * tolerance since its reference pose takes its current pose as the new reference and records * the step in inertialPos.w. A pair whose contact points were computed no earlier than both * bodies' last move can keep them (narrowphase, FLAG_REUSE_CONTACTS). */ export declare const refsWGSL = "\n\n// Shared by every 3D module (avbd3d/gpu/layout.ts)\n\nconst T_NONE = 0;\n\nconst MAX_COLORS = 64u;\nconst NO_COLOR = 255u;\nconst PENDING = 256u;\n\nconst C_PAIRS = 0u;\nconst C_CONTACTS = 1u;\nconst C_PREV_CONTACTS = 2u;\nconst C_OVERFLOW = 3u;\nconst C_CLASHES = 4u;\nconst C_NUM_COLORS = 5u;\n\nconst IA_PAIRS = 0u;\nconst IA_CONTACTS = 3u;\nconst IA_PREV = 6u;\nconst IA_CONSTRAINTS = 9u;\nconst IA_COLOR = 12u;\n\nconst WG = 64u;\nconst COLOR_WG = 256u;\n\nconst BIG = 3e38;\nconst HARD = 1e30;\n\nfn groupsFor(n: u32) -> u32 {\n return (n + WG - 1u) / WG;\n}\n\n/** lowbias32 integer hash (same as the CPU colouring priorities). */\nfn hash32(v: u32) -> u32 {\n var x = v;\n x ^= x >> 16u;\n x *= 0x7feb352du;\n x ^= x >> 15u;\n x *= 0x846ca68bu;\n x ^= x >> 16u;\n return x;\n}\n\nconst T_JOINT = 1;\nconst T_SPRING = 2;\n\nconst PENALTY_MIN = 1.0;\nconst PENALTY_MAX = 1e10;\n// Least LDL\u1D40 pivot of the primal solve, relative to its diagonal (wgsl-solve.ts finishBody)\nconst PIVOT_FLOOR = 1e-5;\nconst COLLISION_MARGIN = 0.01;\nconst STICK_THRESH = 0.00001;\n\nconst SHAPE_SPHERE = 1.0;\nconst SHAPE_SAIL = 2.0;\nconst SHAPE_HULL = 3.0;\nconst STICK_BIT = 2147483648u;\nconst C_MANIFOLDS = 6u;\nconst C_PREV_MANIFOLDS = 7u;\n/** Feature key of every contact involving a sphere (one contact per pair). */\nconst SPHERE_FEATURE = 3u << 24u;\n\nconst FLAG_MATCH_NEAREST = 1u;\nconst FLAG_FACE_BIAS = 2u;\nconst FLAG_REUSE_CONTACTS = 4u;\nconst FLAG_START_AT_REST = 8u;\nconst FLAG_MASS_PENALTY = 16u;\nconst REST_SPEED = 0.1;\nconst NEAREST_FRACTION = 0.05;\n\nstruct Body {\n pos: vec4f, // xyz, w: friction\n rot: vec4f, // orientation quaternion (x, y, z, w)\n initialPos: vec4f, // pose at the start of the step (x-)\n initialRot: vec4f,\n size: vec4f, // full widths, w: mass (0 = static)\n moment: vec4f, // principal moments, w: bounding radius\n inertialPos: vec4f, // inertial target y, w: step it last moved from its reference pose (u32)\n inertialRot: vec4f,\n vel: vec4f, // xyz, w: previous step's velocity along up (adaptive warm start)\n angVel: vec4f, // xyz, w: shape (SHAPE_BOX, SHAPE_SPHERE, SHAPE_SAIL, or SHAPE_HULL + hull offset)\n}\n\nstruct Joint {\n penLin: vec4f, // xyz, w: linear stiffness (>= HARD: hard); spring: its stiffness\n penAng: vec4f, // xyz, w: angular stiffness\n lamLin: vec4f, // xyz, w: fracture threshold on |lamAng| (negative: on |lamLin| too)\n lamAng: vec4f, // xyz, w: torque arm\n c0Lin: vec4f, // C(x-)\n c0Ang: vec4f, // xyz: C(x-), w: yield threshold on |lamAng| (BIG: never yields)\n rA: vec4f, // xyz: anchor on A (world point when A is the world), w: spring rest length\n rB: vec4f, // xyz: anchor on B, w: bend limit in radians (BIG: a plastic joint never breaks on it)\n rest: vec4f, // the relative rotation the angle lock holds: rotB = rotA\u00B7rest (quaternion x, y, z, w)\n restStart: vec4f, // the rest it was made with: its bend is the turn from this to rest\n}\n\nstruct Manifold {\n ids: vec4u, // bodyA, bodyB (A > B), first contact, count | generation step << 4\n geo: vec4f, // normal (B to A), friction\n}\n\nfn pairCount(m: Manifold) -> u32 {\n return m.ids.w & 15u;\n}\n\nstruct Contact {\n rA: vec3f, // body-local anchors\n key: u32, // feature | STICK_BIT\n rB: vec3f,\n c0x: f32, // C(x-) in the pair's basis, including the collision margin\n pen: vec3f, // normal, tangent, tangent\n c0y: f32,\n lam: vec3f,\n c0z: f32,\n}\n\nstruct Params {\n dt: f32,\n gravity: f32, // acceleration along up (m/s\u00B2, negative: down)\n betaLin: f32,\n betaAng: f32,\n gamma: f32,\n alpha: f32,\n flags: u32,\n bodyCount: u32,\n jointCount: u32,\n colorCap: u32,\n cellSize: f32,\n tableMask: u32,\n maxSmallRadius: f32,\n largeCount: u32,\n noCollideCount: u32,\n pairCapacity: u32,\n contactCapacity: u32,\n hashMask: u32,\n adjFillOffset: u32,\n adjListOffset: u32,\n gridCursorOffset: u32,\n gridSortedOffset: u32,\n gridCellOffset: u32,\n stateBOffset: u32,\n colorHistOffset: u32,\n colorStartOffset: u32,\n colorGroups: u32,\n colorBodiesOffset: u32,\n rounds: u32,\n manifoldCapacity: u32,\n step: u32, // steps since the solver was created (from 1)\n primalLanes: u32, // bytes 0-2: log2 of the colour sizes from which 1, 2, 4 lanes per body suffice\n wind: vec4f, // xyz: wind velocity (m/s), w: air pressure coefficient \u00BD\u03C1C_d\n gust: vec4f, // x: gust strength (fraction of the wind)\n up: vec4f, // xyz: which way is up (unit)\n}\n\nfn qmul(a: vec4f, b: vec4f) -> vec4f {\n return vec4f(\n a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,\n a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,\n a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,\n a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z);\n}\n\nfn qconj(q: vec4f) -> vec4f {\n return vec4f(-q.xyz, q.w);\n}\n\n/** The demo's quat - quat: 2\u00B7vec(a\u00B7b\u207B\u00B9), a small-angle rotation vector. */\nfn qsub(a: vec4f, b: vec4f) -> vec3f {\n return qmul(a, qconj(b) / dot(b, b)).xyz * 2.0;\n}\n\n/** The demo's quat + float3: integrate a rotation vector, normalize(a + (v, 0)\u00B7a\u00B7\u00BD). */\nfn qadd(a: vec4f, v: vec3f) -> vec4f {\n return normalize(a + qmul(vec4f(v, 0.0), a) * 0.5);\n}\n\nfn qrotate(q: vec4f, v: vec3f) -> vec3f {\n let t = cross(q.xyz, v) * 2.0;\n return v + t * q.w + cross(q.xyz, t);\n}\n\n/** Contact basis rows (n, t1, t2), as maths.h orthonormal(). */\nfn orthonormal(n: vec3f) -> mat3x3f {\n var t1 = select(vec3f(0.0, -n.z, n.y), vec3f(-n.y, n.x, 0.0), abs(n.x) > abs(n.z));\n t1 = normalize(t1);\n // Columns of the WGSL matrix are the basis rows\n return mat3x3f(n, t1, cross(n, t1));\n}\n\n\nstruct RefPose {\n pos: vec4f,\n rot: vec4f,\n}\n\n@group(0) @binding(0) var params: Params;\n@group(0) @binding(1) var bodies: array;\n@group(0) @binding(2) var refs: array;\n\n@compute @workgroup_size(64)\nfn updateRefs(@builtin(global_invocation_id) gid: vec3u) {\n let i = gid.x;\n if (i >= params.bodyCount) { return; }\n let pos = bodies[i].pos.xyz;\n let rot = bodies[i].rot;\n let last = refs[i];\n // A zero quaternion marks a body without a reference yet\n let moved = dot(last.rot, last.rot) == 0.0\n || length(pos - last.pos.xyz) > 0.002\n || length(qsub(rot, last.rot)) > 0.002;\n if (moved) {\n refs[i] = RefPose(vec4f(pos, 0.0), rot);\n bodies[i].inertialPos.w = bitcast(params.step);\n }\n}\n"; export declare const broadphaseWGSL = "\n\n// Shared by every 3D module (avbd3d/gpu/layout.ts)\n\nconst T_NONE = 0;\n\nconst MAX_COLORS = 64u;\nconst NO_COLOR = 255u;\nconst PENDING = 256u;\n\nconst C_PAIRS = 0u;\nconst C_CONTACTS = 1u;\nconst C_PREV_CONTACTS = 2u;\nconst C_OVERFLOW = 3u;\nconst C_CLASHES = 4u;\nconst C_NUM_COLORS = 5u;\n\nconst IA_PAIRS = 0u;\nconst IA_CONTACTS = 3u;\nconst IA_PREV = 6u;\nconst IA_CONSTRAINTS = 9u;\nconst IA_COLOR = 12u;\n\nconst WG = 64u;\nconst COLOR_WG = 256u;\n\nconst BIG = 3e38;\nconst HARD = 1e30;\n\nfn groupsFor(n: u32) -> u32 {\n return (n + WG - 1u) / WG;\n}\n\n/** lowbias32 integer hash (same as the CPU colouring priorities). */\nfn hash32(v: u32) -> u32 {\n var x = v;\n x ^= x >> 16u;\n x *= 0x7feb352du;\n x ^= x >> 15u;\n x *= 0x846ca68bu;\n x ^= x >> 16u;\n return x;\n}\n\nconst T_JOINT = 1;\nconst T_SPRING = 2;\n\nconst PENALTY_MIN = 1.0;\nconst PENALTY_MAX = 1e10;\n// Least LDL\u1D40 pivot of the primal solve, relative to its diagonal (wgsl-solve.ts finishBody)\nconst PIVOT_FLOOR = 1e-5;\nconst COLLISION_MARGIN = 0.01;\nconst STICK_THRESH = 0.00001;\n\nconst SHAPE_SPHERE = 1.0;\nconst SHAPE_SAIL = 2.0;\nconst SHAPE_HULL = 3.0;\nconst STICK_BIT = 2147483648u;\nconst C_MANIFOLDS = 6u;\nconst C_PREV_MANIFOLDS = 7u;\n/** Feature key of every contact involving a sphere (one contact per pair). */\nconst SPHERE_FEATURE = 3u << 24u;\n\nconst FLAG_MATCH_NEAREST = 1u;\nconst FLAG_FACE_BIAS = 2u;\nconst FLAG_REUSE_CONTACTS = 4u;\nconst FLAG_START_AT_REST = 8u;\nconst FLAG_MASS_PENALTY = 16u;\nconst REST_SPEED = 0.1;\nconst NEAREST_FRACTION = 0.05;\n\nstruct Body {\n pos: vec4f, // xyz, w: friction\n rot: vec4f, // orientation quaternion (x, y, z, w)\n initialPos: vec4f, // pose at the start of the step (x-)\n initialRot: vec4f,\n size: vec4f, // full widths, w: mass (0 = static)\n moment: vec4f, // principal moments, w: bounding radius\n inertialPos: vec4f, // inertial target y, w: step it last moved from its reference pose (u32)\n inertialRot: vec4f,\n vel: vec4f, // xyz, w: previous step's velocity along up (adaptive warm start)\n angVel: vec4f, // xyz, w: shape (SHAPE_BOX, SHAPE_SPHERE, SHAPE_SAIL, or SHAPE_HULL + hull offset)\n}\n\nstruct Joint {\n penLin: vec4f, // xyz, w: linear stiffness (>= HARD: hard); spring: its stiffness\n penAng: vec4f, // xyz, w: angular stiffness\n lamLin: vec4f, // xyz, w: fracture threshold on |lamAng| (negative: on |lamLin| too)\n lamAng: vec4f, // xyz, w: torque arm\n c0Lin: vec4f, // C(x-)\n c0Ang: vec4f, // xyz: C(x-), w: yield threshold on |lamAng| (BIG: never yields)\n rA: vec4f, // xyz: anchor on A (world point when A is the world), w: spring rest length\n rB: vec4f, // xyz: anchor on B, w: bend limit in radians (BIG: a plastic joint never breaks on it)\n rest: vec4f, // the relative rotation the angle lock holds: rotB = rotA\u00B7rest (quaternion x, y, z, w)\n restStart: vec4f, // the rest it was made with: its bend is the turn from this to rest\n}\n\nstruct Manifold {\n ids: vec4u, // bodyA, bodyB (A > B), first contact, count | generation step << 4\n geo: vec4f, // normal (B to A), friction\n}\n\nfn pairCount(m: Manifold) -> u32 {\n return m.ids.w & 15u;\n}\n\nstruct Contact {\n rA: vec3f, // body-local anchors\n key: u32, // feature | STICK_BIT\n rB: vec3f,\n c0x: f32, // C(x-) in the pair's basis, including the collision margin\n pen: vec3f, // normal, tangent, tangent\n c0y: f32,\n lam: vec3f,\n c0z: f32,\n}\n\nstruct Params {\n dt: f32,\n gravity: f32, // acceleration along up (m/s\u00B2, negative: down)\n betaLin: f32,\n betaAng: f32,\n gamma: f32,\n alpha: f32,\n flags: u32,\n bodyCount: u32,\n jointCount: u32,\n colorCap: u32,\n cellSize: f32,\n tableMask: u32,\n maxSmallRadius: f32,\n largeCount: u32,\n noCollideCount: u32,\n pairCapacity: u32,\n contactCapacity: u32,\n hashMask: u32,\n adjFillOffset: u32,\n adjListOffset: u32,\n gridCursorOffset: u32,\n gridSortedOffset: u32,\n gridCellOffset: u32,\n stateBOffset: u32,\n colorHistOffset: u32,\n colorStartOffset: u32,\n colorGroups: u32,\n colorBodiesOffset: u32,\n rounds: u32,\n manifoldCapacity: u32,\n step: u32, // steps since the solver was created (from 1)\n primalLanes: u32, // bytes 0-2: log2 of the colour sizes from which 1, 2, 4 lanes per body suffice\n wind: vec4f, // xyz: wind velocity (m/s), w: air pressure coefficient \u00BD\u03C1C_d\n gust: vec4f, // x: gust strength (fraction of the wind)\n up: vec4f, // xyz: which way is up (unit)\n}\n\nfn qmul(a: vec4f, b: vec4f) -> vec4f {\n return vec4f(\n a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,\n a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,\n a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,\n a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z);\n}\n\nfn qconj(q: vec4f) -> vec4f {\n return vec4f(-q.xyz, q.w);\n}\n\n/** The demo's quat - quat: 2\u00B7vec(a\u00B7b\u207B\u00B9), a small-angle rotation vector. */\nfn qsub(a: vec4f, b: vec4f) -> vec3f {\n return qmul(a, qconj(b) / dot(b, b)).xyz * 2.0;\n}\n\n/** The demo's quat + float3: integrate a rotation vector, normalize(a + (v, 0)\u00B7a\u00B7\u00BD). */\nfn qadd(a: vec4f, v: vec3f) -> vec4f {\n return normalize(a + qmul(vec4f(v, 0.0), a) * 0.5);\n}\n\nfn qrotate(q: vec4f, v: vec3f) -> vec3f {\n let t = cross(q.xyz, v) * 2.0;\n return v + t * q.w + cross(q.xyz, t);\n}\n\n/** Contact basis rows (n, t1, t2), as maths.h orthonormal(). */\nfn orthonormal(n: vec3f) -> mat3x3f {\n var t1 = select(vec3f(0.0, -n.z, n.y), vec3f(-n.y, n.x, 0.0), abs(n.x) > abs(n.z));\n t1 = normalize(t1);\n // Columns of the WGSL matrix are the basis rows\n return mat3x3f(n, t1, cross(n, t1));\n}\n\n\n@group(0) @binding(0) var params: Params;\n@group(0) @binding(1) var bodies: array;\n// Grid: bucketStart[tableMask + 2] | cursor[tableMask + 1] | sorted[bodies] | cell[3 * bodies]\n@group(0) @binding(2) var grid: array>;\n@group(0) @binding(3) var pairs: array;\n@group(0) @binding(4) var counters: array>;\n// Static: large body indices[largeCount] | noCollide (hi, lo, joint) triples, sorted by (hi, lo)\n@group(0) @binding(5) var statics: array;\n@group(0) @binding(6) var joints: array;\n// Per body: its collision groups and the groups it collides with (GpuSolver3D.setFilters)\n@group(0) @binding(7) var filters: array;\n\n@compute @workgroup_size(1)\nfn beginFrame() {\n // Last step's pairs and contacts become \"previous\" (they sit in the other ping-pong buffers)\n atomicStore(&counters[C_PREV_MANIFOLDS], min(atomicLoad(&counters[C_MANIFOLDS]), params.manifoldCapacity));\n atomicStore(&counters[C_PREV_CONTACTS], min(atomicLoad(&counters[C_CONTACTS]), params.contactCapacity));\n atomicStore(&counters[C_MANIFOLDS], 0u);\n atomicStore(&counters[C_CONTACTS], 0u);\n atomicStore(&counters[C_PAIRS], 0u);\n atomicStore(&counters[C_OVERFLOW], 0u);\n atomicStore(&counters[C_CLASHES], 0u);\n atomicStore(&counters[C_NUM_COLORS], 0u);\n}\n\nfn radius(i: u32) -> f32 {\n return bodies[i].moment.w;\n}\n\nfn isLarge(i: u32) -> bool {\n return radius(i) > params.maxSmallRadius;\n}\n\nfn cellOf(i: u32) -> vec3i {\n return vec3i(floor(bodies[i].pos.xyz / params.cellSize));\n}\n\nfn cellHash(c: vec3i) -> u32 {\n return ((u32(c.x) * 73856093u) ^ (u32(c.y) * 19349663u) ^ (u32(c.z) * 83492791u)) & params.tableMask;\n}\n\n@compute @workgroup_size(64)\nfn gridCount(@builtin(global_invocation_id) gid: vec3u) {\n let i = gid.x;\n if (i >= params.bodyCount || isLarge(i)) { return; }\n let c = cellOf(i);\n for (var k = 0u; k < 3u; k++) { atomicStore(&grid[params.gridCellOffset + 3u * i + k], bitcast(c[k])); }\n atomicAdd(&grid[cellHash(c)], 1u);\n}\n\n@compute @workgroup_size(64)\nfn gridScatter(@builtin(global_invocation_id) gid: vec3u) {\n let i = gid.x;\n if (i >= params.bodyCount || isLarge(i)) { return; }\n let h = cellHash(cellOf(i));\n let slot = atomicLoad(&grid[h]) + atomicAdd(&grid[params.gridCursorOffset + h], 1u);\n atomicStore(&grid[params.gridSortedOffset + slot], i);\n}\n\n/** Binary search of the (hi, lo) no-collide list; false if every connecting joint has broken. */\nfn ignored(hi: u32, lo: u32) -> bool {\n let base = params.largeCount;\n var first = 0u;\n var count = params.noCollideCount;\n while (count > 0u) {\n let step = count / 2u;\n let mid = first + step;\n let mh = statics[base + 3u * mid];\n let ml = statics[base + 3u * mid + 1u];\n if (mh < hi || (mh == hi && ml < lo)) {\n first = mid + 1u;\n count -= step + 1u;\n } else {\n count = step;\n }\n }\n for (var k = first; k < params.noCollideCount; k++) {\n if (statics[base + 3u * k] != hi || statics[base + 3u * k + 1u] != lo) { break; }\n let j = statics[base + 3u * k + 2u];\n if (j == 0xffffffffu) { return true; }\n if (joints[j].penLin.w != 0.0 || joints[j].penAng.w != 0.0) { return true; }\n }\n return false;\n}\n\n/** Body i as the broadphase sees it: world axes and half extents (a sphere: its radius). */\nstruct Shape {\n ax: array,\n h: vec3f,\n sphere: bool,\n}\n\nfn shapeOf(i: u32) -> Shape {\n let q = bodies[i].rot;\n var s: Shape;\n s.h = bodies[i].size.xyz * 0.5;\n s.sphere = bodies[i].angVel.w == SHAPE_SPHERE;\n s.ax[0] = qrotate(q, vec3f(1.0, 0.0, 0.0));\n s.ax[1] = qrotate(q, vec3f(0.0, 1.0, 0.0));\n s.ax[2] = qrotate(q, vec3f(0.0, 0.0, 1.0));\n return s;\n}\n\n/** Half width of a shape along unit axis n. */\nfn extent(s: Shape, n: vec3f) -> f32 {\n if (s.sphere) { return s.h.x; }\n return s.h.x * abs(dot(n, s.ax[0])) + s.h.y * abs(dot(n, s.ax[1])) + s.h.z * abs(dot(n, s.ax[2]));\n}\n\n/** Half extents of a shape's world-space bounding box. */\nfn aabbHalf(s: Shape) -> vec3f {\n if (s.sphere) { return vec3f(s.h.x); }\n return abs(s.ax[0]) * s.h.x + abs(s.ax[1]) * s.h.y + abs(s.ax[2]) * s.h.z;\n}\n\n/**\n * A face axis of either shape separates them by more than 1 mm (d: centre A minus centre B).\n * The narrowphase rejects any pair a separating axis finds (it tests these axes and the edge\n * axes), so this only drops pairs it would drop; the millimetre keeps round-off out of it.\n */\nfn faceSeparated(A: Shape, B: Shape, d: vec3f) -> bool {\n for (var k = 0u; k < 3u; k++) {\n if (abs(dot(d, A.ax[k])) - extent(A, A.ax[k]) - extent(B, A.ax[k]) > 1e-3) { return true; }\n if (abs(dot(d, B.ax[k])) - extent(A, B.ax[k]) - extent(B, B.ax[k]) > 1e-3) { return true; }\n }\n return false;\n}\n\n/** What the pair tests need of the body a findPairs thread starts from, loaded once. */\nstruct Probe {\n index: u32,\n pos: vec3f,\n radius: f32,\n aabb: vec3f,\n dynamic: bool,\n shape: Shape,\n}\n\nfn probeOf(i: u32) -> Probe {\n let shape = shapeOf(i);\n return Probe(i, bodies[i].pos.xyz, radius(i), aabbHalf(shape), bodies[i].size.w > 0.0, shape);\n}\n\nfn testPair(P: Probe, j: u32) {\n if (!P.dynamic && bodies[j].size.w <= 0.0) { return; }\n // Each in a group the other collides with\n let fi = filters[P.index];\n let fj = filters[j];\n if ((fi.x & fj.y) == 0u || (fj.x & fi.y) == 0u) { return; }\n let d = P.pos - bodies[j].pos.xyz;\n let r = P.radius + radius(j);\n if (dot(d, d) > r * r) { return; }\n // Bounding spheres of boxes overlap far more often than the boxes do (neighbouring\n // columns, rows of bricks); world AABBs are a cheap, conservative second test (with a\n // small pad for f32 round-off), and face axes a third: rings of bricks and piles sent\n // 48-72% of their pairs to the narrowphase only to be found apart.\n let B = shapeOf(j);\n if (any(abs(d) > P.aabb + aabbHalf(B) + vec3f(1e-4))) { return; }\n if (faceSeparated(P.shape, B, d)) { return; }\n let a = max(P.index, j);\n let b = min(P.index, j);\n if (ignored(a, b)) { return; }\n let slot = atomicAdd(&counters[C_PAIRS], 1u);\n if (slot >= params.pairCapacity) {\n atomicOr(&counters[C_OVERFLOW], 1u);\n return;\n }\n pairs[slot] = vec2u(a, b);\n}\n\n@compute @workgroup_size(64)\nfn findPairs(@builtin(global_invocation_id) gid: vec3u) {\n let i = gid.x;\n if (i >= params.bodyCount) { return; }\n let small = !isLarge(i);\n let P = probeOf(i);\n if (small) {\n // Every overlapping small pair is in the same or an adjacent cell; emit from the higher index\n let c = cellOf(i);\n for (var oz = -1; oz <= 1; oz++) {\n for (var oy = -1; oy <= 1; oy++) {\n for (var ox = -1; ox <= 1; ox++) {\n let cell = c + vec3i(ox, oy, oz);\n let h = cellHash(cell);\n let end = atomicLoad(&grid[h + 1u]);\n for (var k = atomicLoad(&grid[h]); k < end; k++) {\n let j = atomicLoad(&grid[params.gridSortedOffset + k]);\n if (j >= i) { continue; }\n // Different cells can share a bucket; only accept bodies really in this cell\n let o = params.gridCellOffset + 3u * j;\n let cj = vec3i(bitcast(atomicLoad(&grid[o])), bitcast(atomicLoad(&grid[o + 1u])), bitcast(atomicLoad(&grid[o + 2u])));\n if (any(cj != cell)) { continue; }\n testPair(P, j);\n }\n }\n }\n }\n }\n // Large bodies against everything (large-large pairs once, from the larger index)\n for (var k = 0u; k < params.largeCount; k++) {\n let l = statics[k];\n if (l == i || (!small && l < i)) { continue; }\n testPair(P, l);\n }\n}\n"; /** * The contacts module; with `hulls`, it also binds the hull buffer (binding 9) and collides hull * shapes (./wgsl-hull.ts). Without, hull bodies are written as boxes (GpuSolver3D). */ export declare const makeContactsWGSL: (hulls: boolean) => string; export declare const contactsWGSL: string; export declare const contactsHullWGSL: string; //# sourceMappingURL=wgsl-collision.d.ts.map