Fx2D
A C++20 2D rigid-body physics engine
Loading...
Searching...
No Matches
Solver.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cstdint>
5#include <memory>
6#include <vector>
7
8#include "Fx2D/Math.h"
9
10// Forward declaration
11class FxEntity;
12
13// Result of a single-sided SAT overlap query (A's edges tested against B).
14// gap < 0: bodies overlapping, |gap| = penetration depth on that axis.
15// has_sep: true if a separating axis was found (no overlap from A's side).
17 FxVec2f normal = {1.0f, 0.0f}; // edge normal of the min-penetration axis
18 float gap = -FxInfinityf; // maximum B_min_val seen (signed separation)
19 bool has_sep = false; // true if any edge gave gap > 0
20 size_t ref_edge_index = 0; // index of that edge in A's vertex list
21 FxVec2f ref_edge_dir = {0.0f, 0.0f}; // normalized direction along that edge
22 size_t pen_vertex_index = 0; // index of B's deepest vertex on that edge
23};
24
25// Solver-local body state, structure of arrays, one entry per registry packed index. Gathered
26// once per substep so the sweeps address bodies by index rather than chasing shared_ptrs, and
27// the layout the batched solve reads. See docs/roadmap/simd.md.
29 std::vector<float> vx, vy, w; // linear and angular velocity
30 std::vector<float> inv_m, inv_i; // effective inverse mass and inertia (0 when immovable)
31
32 void resize(std::size_t n) {
33 vx.resize(n);
34 vy.resize(n);
35 w.resize(n);
36 inv_m.resize(n);
37 inv_i.resize(n);
38 }
39
40 std::size_t size() const { return vx.size(); }
41
42 // Velocity of the material point at body-relative offset r. Same expression as
43 // FxEntity::velocity_at_local_point, kept identical so the two cannot drift apart.
44 FxVec2f velocity_at(int32_t body, const FxVec2f& r) const {
45 const std::size_t i = static_cast<std::size_t>(body);
46 return FxVec2f(vx[i] - w[i] * r.y(), vy[i] + w[i] * r.x());
47 }
48};
49
50// Per-substep sweep scratch for one contact: lever arms, their cross products with the contact
51// basis, the effective masses, the restitution target and the mixed material constants. Kept
52// beside the contact, not inside it, so copying a contact does not carry it.
54 FxVec2f rA[2]{{0.0f, 0.0f}, {0.0f, 0.0f}};
55 FxVec2f rB[2]{{0.0f, 0.0f}, {0.0f, 0.0f}};
56 float ra_n[2] = {0.0f, 0.0f}, rb_n[2] = {0.0f, 0.0f};
57 float ra_t[2] = {0.0f, 0.0f}, rb_t[2] = {0.0f, 0.0f};
58 float K_n[2] = {0.0f, 0.0f}, K_t[2] = {0.0f, 0.0f};
59 float wA = 0.0f, wB = 0.0f, IA = 0.0f, IB = 0.0f;
60
61 // Closing speed at substep start — fixes the restitution target for every sweep.
62 float vn_pre[2] = {0.0f, 0.0f};
63
64 // Pair material constants, mixed once per substep so the sweeps never touch an entity to
65 // find out how bouncy or how rough the pair is.
66 float restitution = 0.0f;
67 float mu_static = 0.0f;
68 float mu_kinetic = 0.0f;
69};
70
71struct FxContact {
72 // Sentinel for cache_slot below: this contact has not been registered with a scene.
73 static constexpr uint32_t kNoCacheSlot = 0xffffffffu;
74
75 private:
76 bool m_is_valid = false;
77
78 public:
79 size_t count = 0; // True if contact is valid
80 FxVec2f position[2] = {{0.0f, 0.0f}, {0.0f, 0.0f}}; // up to 2 contact points in world
81 // coordinates
82 FxVec2f normal{0.0f, 0.0f}; // Contact normal (unit vector)
83 float penetration_depth = FxInfinityf; // Penetration depth (positive if overlapping)
84
85 // The two colliding bodies, borrowed not owned: FxScene pins a shared_ptr to every entity
86 // its contact buffers name, so one deleted between steps still survives to be reported.
87 // Valid until the next step(); do not keep a contact past the frame that produced it.
88 FxEntity* entity1 = nullptr; // First entity in collision
89 FxEntity* entity2 = nullptr; // Second entity in collision
90
91 // Impulse applied this substep (may be released; never exceeds what was applied).
92 float jn_accumulated[2] = {0.0f, 0.0f};
93 float jt_accumulated[2] = {0.0f, 0.0f};
94
95 // Previous substep impulse used as the warm-start guess.
96 float jn_warm[2] = {0.0f, 0.0f};
97 float jt_warm[2] = {0.0f, 0.0f};
98
99 // Packed indices of the two bodies into FxSolverBodies, filled when the contact is detected.
100 // The shared_ptrs above stay for the public contact buffer; the solver uses these.
101 int32_t body1 = -1;
102 int32_t body2 = -1;
103
104 // Solver-internal pair bookkeeping: the key identifies the entity pair, the slot is where
105 // its warm-start impulses and step-buffer position live. Exposed through contacts() only
106 // because the whole struct is; nothing outside the solver should read them.
107 uint64_t pair_key = 0;
109
110 // Constructor overloads
111 FxContact() = default;
112 FxContact(bool valid) : m_is_valid(valid) {}
113
114 // method to check validity
115 bool is_valid(bool full_check = true) const {
116 return m_is_valid &&
117 (!full_check || (entity1 != nullptr && entity2 != nullptr && count != 0 &&
118 std::isfinite(penetration_depth) && normal.norm() > 1e-3f));
119 }
120 void set_valid(bool valid) { m_is_valid = valid; }
121};
122
123// Position-based constraint base class for XPBD solver
125 // Joints rename the constraints they own; see FxJoint::namespace_constraints.
126 friend class FxJoint;
127
128 protected:
129 std::string m_name; // "id1_id2_constraint-name"
130 double compliance = 1e-7; // XPBD alpha = compliance / dt^2
131 // When set, prev_pose moves with pose so the correction registers no velocity. Velocity is
132 // derived as (pose - prev_pose)/h, so a constraint that only moves pose is a spring that
133 // converts every pull into momentum -- right for a joint, wrong for dragging a body.
134 bool carries_velocity = true;
135 std::shared_ptr<FxEntity> entity1;
136 std::shared_ptr<FxEntity> entity2;
137
138 public:
139 // bool entities_collide = false; // Whether connected entities should collide
140 // Set stiffness (converts to compliance internally)
141 void set_stiffness(double k) {
142 if (k <= 0.0) return;
143 compliance = 1.0 / k;
144 }
145 void setCompliance(double c) { compliance = std::max(0.0, c); }
146 // Evaluate C and gradients; set active=false to skip
147 virtual void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
148 bool& active) const = 0;
149 // One-iteration XPBD/PBD correction (no lambda term in numerator)
150 void resolve(double dt);
151 // Accessor method for name (required by FxNamedRegistry)
152 const std::string& get_name() const { return m_name; }
153
154 // Entity accessor methods (read-only)
155 const std::shared_ptr<FxEntity>& get_entity1() const { return entity1; }
156 const std::shared_ptr<FxEntity>& get_entity2() const { return entity2; }
157
158 // Entity name accessor methods
159 std::string get_entity1_name() const;
160 std::string get_entity2_name() const;
161
162 virtual ~FxConstraint() = default;
163};
164
165// Angular limit constraint that restricts the relative angle between two entities
166// to be within a specified range [lower, upper]. The constraint is only active when violated
168 public:
169 float lower_limit = 0.0f; // Lower angle limit (degrees)
170 float upper_limit = FxPif; // Upper angle limit (degrees)
171 float slop = 0.01f; // Tolerance zone around limits
172 bool enabled = true; // Whether this constraint is active
173 FxAngularLimitConstraint(const std::shared_ptr<FxEntity>& e1,
174 const std::shared_ptr<FxEntity>& e2);
175 void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
176 bool& active) const override;
177};
178
179// Constraint that locks relative angle between two entities to a target value
181 public:
182 float target = 0.0f; // Target relative angle
183 bool enabled = true; // Whether this constraint is active
184 FxAngleLockConstraint(const std::shared_ptr<FxEntity>& e1, const std::shared_ptr<FxEntity>& e2,
185 float tgt = 0.0f);
186 void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
187 bool& active) const override;
188};
189
190// Constraint that projects the separation between two anchor points onto a specified world axis
192 private:
193 FxVec2f m_anchor1; // Local anchor point on entity1
194 FxVec2f m_anchor2; // Local anchor point on entity2
195 public:
196 bool enabled = true; // Whether this constraint is active
197 FxAnchorConstraint(const std::shared_ptr<FxEntity>& e1, const std::shared_ptr<FxEntity>& e2,
198 const FxVec2f& anchor, bool anchor_is_local = true);
199 void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
200 bool& active) const override;
201};
202
203// Linear limit constraint that restricts the projection of separation between two entities onto a
204// specified axis
206 private:
207 FxVec2f m_axis; // Axis direction (normalized)
208 bool m_axis_is_local; // Whether axis is local to entity1 or in world coordinates
209 float m_initial_projection;
210
211 public:
212 float lower_limit = 0; // Lower limit for projection
213 float upper_limit = 10; // Upper limit for projection
214 float slop = 0.0001f; // Tolerance zone around limits
215 bool enabled = true; // Whether this constraint is active
216 FxSeparationConstraint(const std::shared_ptr<FxEntity>& e1, const std::shared_ptr<FxEntity>& e2,
217 const FxVec2f& axis, bool axis_is_local = true);
218 void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
219 bool& active) const override;
220};
221
222// Constraint that forces motion along a specified axis
224 private:
225 FxVec2f m_axis; // Axis direction (normalized)
226 bool m_axis_is_local; // Whether axis is local to entity1 or in world coordinates
227 float m_initial_projection; // Initial perpendicular distance projection
228 public:
229 bool enabled = true; // Whether this constraint is active
230 FxMotionAlongAxisConstraint(const std::shared_ptr<FxEntity>& e1,
231 const std::shared_ptr<FxEntity>& e2, const FxVec2f& axis,
232 bool axis_is_local = true);
233 void evaluate(float& C, FxVec2f& g1, FxVec2f& g2, float& gth1, float& gth2,
234 bool& active) const override;
235};
236
237// Partitions the broad-phase pair list into colors, where no two pairs in a color touch the
238// same movable body -- so a color's contacts write to disjoint bodies and can be solved
239// together. Greedy in pair order, so deterministic. See docs/concepts/collisions.md.
241 public:
242 // Colors are capped so the per-color bookkeeping stays a fixed, small cost. Contacts that
243 // find no free color land in an overflow group, which is solved one contact at a time.
244 static constexpr uint32_t kMaxColors = 12;
245
246 // Color `pairs`, leaving the list itself alone -- reordering it costs the narrow phase its
247 // locality. `entities` is the registry packed storage, indexed by the pair entries.
248 // Buffers are reused, so this allocates nothing after the first call.
249 void color_pairs(const std::vector<std::pair<size_t, size_t>>& pairs,
250 const std::vector<std::shared_ptr<FxEntity>>& entities);
251
252 // The color assigned to pair i, as an index the contact carries forward. kMaxColors means
253 // the pair overflowed and must be solved on its own.
254 uint32_t color_of_pair(size_t i) const { return m_color_of[i]; }
255
256 // Turn per-contact colors into a sweep order: `order` comes back holding contact indices
257 // grouped by color. Cheap -- it sorts four-byte indices, not contacts.
258 void group_contacts(const std::vector<uint32_t>& contact_colors, std::vector<uint32_t>& order);
259
260 // Group g spans [group_start(g), group_start(g + 1)) in that order.
261 size_t group_count() const { return m_group_starts.empty() ? 0 : m_group_starts.size() - 1; }
262 uint32_t group_start(size_t g) const { return m_group_starts[g]; }
263
264 // True when group g holds the contacts whose pairs did not fit a color. They may share
265 // bodies with each other and must be solved sequentially, never batched.
266 bool is_overflow_group(size_t g) const { return g == m_overflow_group; }
267
268 // Pairs placed into a color, and those that overflowed. Diagnostics only.
269 size_t colored_count() const { return m_colored_count; }
270 size_t overflow_count() const { return m_overflow_count; }
271
272 private:
273 std::vector<uint32_t> m_group_starts; // group_count() + 1 entries
274 std::vector<uint32_t> m_color_of; // per pair: color index, or kMaxColors for overflow
275 std::vector<uint64_t> m_used; // kMaxColors bitsets, one bit per body
276 std::vector<uint32_t> m_counts; // pairs per group, then reused as write cursors
277 std::vector<uint8_t> m_movable; // per body: can an impulse move it at all
278 std::vector<uint32_t> m_group_of_color; // color -> sweep group, or kUncolored if unused
279 std::vector<uint32_t> m_group_counts; // counting-sort cursors for group_contacts
280 size_t m_overflow_group = static_cast<size_t>(-1); // sweep group holding overflow, if any
281 size_t m_colored_count = 0;
282 size_t m_overflow_count = 0;
283 bool m_has_overflow = false;
284};
285
286// One color's contacts transposed into columns, built once per substep and swept
287// velocity_passes times. Always two slots per contact: a one-point manifold leaves slot 1 with
288// zero effective mass, read as inactive, so no lane has to branch on manifold size.
290 // Per contact.
291 std::vector<int32_t> ia, ib;
292 std::vector<float> nx, ny, tx, ty;
293 std::vector<float> wA, wB, IA, IB;
294 std::vector<float> restitution, mu_s, mu_k;
295 std::vector<uint32_t> contact_index; // where to write the impulses back
296 std::vector<float> jn_sum;
297
298 // The two bodies' velocities, gathered in and scattered out once per colour per pass. Held
299 // in columns so everything between the gather and the scatter is contiguous.
300 std::vector<float> vax, vay, wav, vbx, vby, wbv;
301
302 // Per contact, per slot.
303 std::vector<float> rAx[2], rAy[2], rBx[2], rBy[2];
304 std::vector<float> ra_n[2], rb_n[2], ra_t[2], rb_t[2];
305 std::vector<float> K_n[2], K_t[2], vn_pre[2];
306 std::vector<float> jn[2], jt[2];
307
308 std::size_t size() const { return ia.size(); }
309
310 // Every column, visited once. The single place that knows the full list, so adding a column
311 // cannot leave one uncleared and carrying last substep's data.
312 template<typename Fn>
313 void for_each_column(Fn fn) {
314 fn(ia);
315 fn(ib);
316 fn(nx);
317 fn(ny);
318 fn(tx);
319 fn(ty);
320 fn(wA);
321 fn(wB);
322 fn(IA);
323 fn(IB);
324 fn(restitution);
325 fn(mu_s);
326 fn(mu_k);
327 fn(contact_index);
328 fn(jn_sum);
329 fn(vax);
330 fn(vay);
331 fn(wav);
332 fn(vbx);
333 fn(vby);
334 fn(wbv);
335 for (int s = 0; s < 2; ++s) {
336 fn(rAx[s]);
337 fn(rAy[s]);
338 fn(rBx[s]);
339 fn(rBy[s]);
340 fn(ra_n[s]);
341 fn(rb_n[s]);
342 fn(ra_t[s]);
343 fn(rb_t[s]);
344 fn(K_n[s]);
345 fn(K_t[s]);
346 fn(vn_pre[s]);
347 fn(jn[s]);
348 fn(jt[s]);
349 }
350 }
351
352 void clear() {
353 for_each_column([](auto& column) { column.clear(); });
354 }
355
356 // Grow the velocity columns to match the contact columns after a build.
358 vax.resize(ia.size());
359 vay.resize(ia.size());
360 wav.resize(ia.size());
361 vbx.resize(ia.size());
362 vby.resize(ia.size());
363 wbv.resize(ia.size());
364 jn_sum.resize(ia.size());
365 }
366};
367
368namespace FxSolver {
369// True when a contact is one the velocity solver will actually act on. Shared so the contact
370// graph colors exactly the set the sweeps visit -- coloring a contact the solver then skips
371// would waste a color slot and could push a real contact into the overflow group.
372inline bool contact_is_solvable(const FxContact& contact) {
373 if (!contact.is_valid() || contact.penetration_depth <= 0.0f) return false;
374 if (!contact.entity1 || !contact.entity2) return false;
375 return contact.body1 >= 0 && contact.body2 >= 0;
376}
377
378// AABB overlap check methods
379bool aabb_overlap_check(const FxEntity& entity1, const FxEntity& entity2);
380bool aabb_overlap_check(const std::shared_ptr<FxEntity>& entity1,
381 const std::shared_ptr<FxEntity>& entity2);
382
383// Main collision detection method using SAT
384const FxContact collision_check(const FxEntity& entity1, const FxEntity& entity2);
385const FxContact collision_check(const std::shared_ptr<FxEntity>& entity1,
386 const std::shared_ptr<FxEntity>& entity2);
387
388// Speculative contact for CCD bodies: generates a pre-contact when bodies are separated but
389// approaching fast enough to close the gap within this substep.
390FxContact speculative_contact_check(const std::shared_ptr<FxEntity>& entity1,
391 const std::shared_ptr<FxEntity>& entity2, float substep_dt);
392
393// Main collision resolution method
394void resolve_penetration(const FxContact& contact, double dt = 0.016f);
395// Capture closing speeds once per substep before impulses (shared restitution target), and
396// resolve the per-substep constants the sweeps need. Reads pose and material properties from the
397// entities, velocity from the columns.
399 const FxSolverBodies& bodies);
400// Velocity-level solver: restitution and dynamic friction impulses. Columns only.
401// Append one contact to the batch. Caller guarantees contact_is_solvable(contact).
402void batch_append(FxContactBatch& batch, const FxContact& contact, const FxContactSolverData& data,
403 uint32_t contact_index);
404// Solve batch entries [begin, end) -- one colour and one manifold size, so no two entries
405// share a movable body and every lane runs the same number of contact points.
406void resolve_velocities_batched(FxContactBatch& batch, std::size_t begin, std::size_t end,
407 FxSolverBodies& bodies, int slots);
408// Copy the accumulated impulses back onto the contacts, for the warm-start cache.
409void batch_write_back(const FxContactBatch& batch, std::vector<FxContact>& contacts);
410// Re-apply cached impulses from the previous solve before computing new ones. Columns only.
411void warm_start(FxContact& contact, const FxContactSolverData& data, FxSolverBodies& bodies);
412
413} // namespace FxSolver
void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const override
FxAnchorConstraint(const std::shared_ptr< FxEntity > &e1, const std::shared_ptr< FxEntity > &e2, const FxVec2f &anchor, bool anchor_is_local=true)
FxAngleLockConstraint(const std::shared_ptr< FxEntity > &e1, const std::shared_ptr< FxEntity > &e2, float tgt=0.0f)
void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const override
void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const override
FxAngularLimitConstraint(const std::shared_ptr< FxEntity > &e1, const std::shared_ptr< FxEntity > &e2)
Base type for solver constraints.
Definition Solver.h:124
void resolve(double dt)
const std::shared_ptr< FxEntity > & get_entity2() const
Definition Solver.h:156
void set_stiffness(double k)
Definition Solver.h:141
const std::shared_ptr< FxEntity > & get_entity1() const
Definition Solver.h:155
bool carries_velocity
Definition Solver.h:134
std::shared_ptr< FxEntity > entity1
Definition Solver.h:135
std::string get_entity2_name() const
const std::string & get_name() const
Definition Solver.h:152
double compliance
Definition Solver.h:130
void setCompliance(double c)
Definition Solver.h:145
virtual void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const =0
std::shared_ptr< FxEntity > entity2
Definition Solver.h:136
virtual ~FxConstraint()=default
std::string get_entity1_name() const
std::string m_name
Definition Solver.h:129
bool is_overflow_group(size_t g) const
Definition Solver.h:266
void group_contacts(const std::vector< uint32_t > &contact_colors, std::vector< uint32_t > &order)
size_t group_count() const
Definition Solver.h:261
size_t colored_count() const
Definition Solver.h:269
uint32_t group_start(size_t g) const
Definition Solver.h:262
static constexpr uint32_t kMaxColors
Definition Solver.h:244
void color_pairs(const std::vector< std::pair< size_t, size_t > > &pairs, const std::vector< std::shared_ptr< FxEntity > > &entities)
size_t overflow_count() const
Definition Solver.h:270
uint32_t color_of_pair(size_t i) const
Definition Solver.h:254
A named rigid body with state, material properties, geometry, and forces.
Definition Entity.h:49
Base type shared by engine joints.
Definition Joints.h:13
FxMotionAlongAxisConstraint(const std::shared_ptr< FxEntity > &e1, const std::shared_ptr< FxEntity > &e2, const FxVec2f &axis, bool axis_is_local=true)
void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const override
FxSeparationConstraint(const std::shared_ptr< FxEntity > &e1, const std::shared_ptr< FxEntity > &e2, const FxVec2f &axis, bool axis_is_local=true)
void evaluate(float &C, FxVec2f &g1, FxVec2f &g2, float &gth1, float &gth2, bool &active) const override
Single-precision 2D vector.
Definition Math.h:47
float & y()
Definition Math.h:57
float & x()
Definition Math.h:56
const FxContact collision_check(const FxEntity &entity1, const FxEntity &entity2)
void warm_start(FxContact &contact, const FxContactSolverData &data, FxSolverBodies &bodies)
void resolve_penetration(const FxContact &contact, double dt=0.016f)
void batch_append(FxContactBatch &batch, const FxContact &contact, const FxContactSolverData &data, uint32_t contact_index)
bool aabb_overlap_check(const FxEntity &entity1, const FxEntity &entity2)
void resolve_velocities_batched(FxContactBatch &batch, std::size_t begin, std::size_t end, FxSolverBodies &bodies, int slots)
FxContact speculative_contact_check(const std::shared_ptr< FxEntity > &entity1, const std::shared_ptr< FxEntity > &entity2, float substep_dt)
bool contact_is_solvable(const FxContact &contact)
Definition Solver.h:372
void batch_write_back(const FxContactBatch &batch, std::vector< FxContact > &contacts)
void init_velocity_pass(FxContact &contact, FxContactSolverData &data, const FxSolverBodies &bodies)
std::vector< float > ty
Definition Solver.h:292
void clear()
Definition Solver.h:352
std::vector< float > jn_sum
Definition Solver.h:296
std::vector< float > vax
Definition Solver.h:300
std::vector< float > vbx
Definition Solver.h:300
std::vector< float > IA
Definition Solver.h:293
std::vector< float > wA
Definition Solver.h:293
std::vector< float > rAy[2]
Definition Solver.h:303
std::vector< float > rb_n[2]
Definition Solver.h:304
std::vector< float > wbv
Definition Solver.h:300
std::vector< float > rb_t[2]
Definition Solver.h:304
std::vector< float > vby
Definition Solver.h:300
std::vector< float > K_t[2]
Definition Solver.h:305
std::vector< int32_t > ia
Definition Solver.h:291
std::vector< float > mu_k
Definition Solver.h:294
std::vector< float > wB
Definition Solver.h:293
std::vector< float > nx
Definition Solver.h:292
std::vector< float > K_n[2]
Definition Solver.h:305
std::vector< float > vay
Definition Solver.h:300
std::vector< float > jn[2]
Definition Solver.h:306
std::vector< int32_t > ib
Definition Solver.h:291
std::vector< float > ra_n[2]
Definition Solver.h:304
std::vector< float > ra_t[2]
Definition Solver.h:304
std::vector< float > mu_s
Definition Solver.h:294
std::vector< float > wav
Definition Solver.h:300
std::size_t size() const
Definition Solver.h:308
std::vector< float > rBx[2]
Definition Solver.h:303
std::vector< uint32_t > contact_index
Definition Solver.h:295
std::vector< float > rAx[2]
Definition Solver.h:303
void for_each_column(Fn fn)
Definition Solver.h:313
std::vector< float > IB
Definition Solver.h:293
void size_velocity_columns()
Definition Solver.h:357
std::vector< float > rBy[2]
Definition Solver.h:303
std::vector< float > ny
Definition Solver.h:292
std::vector< float > tx
Definition Solver.h:292
std::vector< float > jt[2]
Definition Solver.h:306
std::vector< float > restitution
Definition Solver.h:294
std::vector< float > vn_pre[2]
Definition Solver.h:305
FxVec2f rB[2]
Definition Solver.h:55
FxVec2f rA[2]
Definition Solver.h:54
float rb_n[2]
Definition Solver.h:56
float ra_n[2]
Definition Solver.h:56
float vn_pre[2]
Definition Solver.h:62
float ra_t[2]
Definition Solver.h:57
float rb_t[2]
Definition Solver.h:57
Contact data produced by the narrow phase and solver.
Definition Solver.h:71
bool is_valid(bool full_check=true) const
Definition Solver.h:115
int32_t body1
Definition Solver.h:101
FxEntity * entity1
Definition Solver.h:88
FxVec2f normal
Definition Solver.h:82
FxEntity * entity2
Definition Solver.h:89
float jn_accumulated[2]
Definition Solver.h:92
float jn_warm[2]
Definition Solver.h:96
FxVec2f position[2]
Definition Solver.h:80
FxContact(bool valid)
Definition Solver.h:112
uint32_t cache_slot
Definition Solver.h:108
FxContact()=default
float jt_accumulated[2]
Definition Solver.h:93
float penetration_depth
Definition Solver.h:83
void set_valid(bool valid)
Definition Solver.h:120
int32_t body2
Definition Solver.h:102
static constexpr uint32_t kNoCacheSlot
Definition Solver.h:73
uint64_t pair_key
Definition Solver.h:107
size_t count
Definition Solver.h:79
float jt_warm[2]
Definition Solver.h:97
size_t ref_edge_index
Definition Solver.h:20
FxVec2f ref_edge_dir
Definition Solver.h:21
bool has_sep
Definition Solver.h:19
size_t pen_vertex_index
Definition Solver.h:22
FxVec2f normal
Definition Solver.h:17
float gap
Definition Solver.h:18
std::vector< float > inv_i
Definition Solver.h:30
std::vector< float > vx
Definition Solver.h:29
std::vector< float > vy
Definition Solver.h:29
std::size_t size() const
Definition Solver.h:40
std::vector< float > w
Definition Solver.h:29
std::vector< float > inv_m
Definition Solver.h:30
FxVec2f velocity_at(int32_t body, const FxVec2f &r) const
Definition Solver.h:44
void resize(std::size_t n)
Definition Solver.h:32