+VG_STATIC void rb_correct_swingtwist_constraints( rb_constr_swingtwist *buf,
+ int len, float amt ){
+ for( int i=0; i<len; i++ ){
+ rb_constr_swingtwist *st = &buf[i];
+
+ if( !st->tangent_violation )
+ continue;
+
+ v3f va;
+ m3x3_mulv( st->rbb->to_world, st->coneva, va );
+
+ float angle = v3_dot( va, st->tangent_target );
+
+ if( fabsf(angle) < 0.9999f ){
+ v3f axis;
+ v3_cross( va, st->tangent_target, axis );
+
+ v4f correction;
+ q_axis_angle( correction, axis, acosf(angle) * amt );
+ q_mul( correction, st->rbb->q, st->rbb->q );
+ rb_update_transform( st->rbb );
+ }
+ }
+
+ for( int i=0; i<len; i++ ){
+ rb_constr_swingtwist *st = &buf[i];
+
+ if( !st->axis_violation )
+ continue;
+
+ v3f vxb;
+ m3x3_mulv( st->rbb->to_world, st->conevxb, vxb );
+
+ float angle = v3_dot( vxb, st->axis_target );
+
+ if( fabsf(angle) < 0.9999f ){
+ v3f axis;
+ v3_cross( vxb, st->axis_target, axis );
+
+ v4f correction;
+ q_axis_angle( correction, axis, acosf(angle) * amt );
+ q_mul( correction, st->rbb->q, st->rbb->q );
+ rb_update_transform( st->rbb );
+ }
+ }
+}
+
+VG_STATIC void rb_correct_contact_constraints( rb_ct *buf, int len, float amt ){
+ for( int i=0; i<len; i++ ){
+ rb_ct *ct = &buf[i];
+ rigidbody *rba = ct->rba,
+ *rbb = ct->rbb;
+
+ float mass_total = 1.0f / (rba->inv_mass + rbb->inv_mass);
+
+ v3_muladds( rba->co, ct->n, -mass_total * rba->inv_mass, rba->co );
+ v3_muladds( rbb->co, ct->n, mass_total * rbb->inv_mass, rbb->co );
+ }
+}
+
+
+/*
+ * Effectors
+ */
+
+VG_STATIC void rb_effect_simple_bouyency( rigidbody *ra, v4f plane,
+ float amt, float drag ){
+ /* float */
+ float depth = v3_dot( plane, ra->co ) - plane[3],
+ lambda = vg_clampf( -depth, 0.0f, 1.0f ) * amt;
+
+ v3_muladds( ra->v, plane, lambda * k_rb_delta, ra->v );
+
+ if( depth < 0.0f )
+ v3_muls( ra->v, 1.0f-(drag*k_rb_delta), ra->v );
+}
+
+/* apply a spring&dampener force to match ra(worldspace) on rigidbody, to
+ * rt(worldspace)
+ */
+VG_STATIC void rb_effect_spring_target_vector( rigidbody *rba, v3f ra, v3f rt,
+ float spring, float dampening,
+ float timestep ){
+ float d = v3_dot( rt, ra );
+ float a = acosf( vg_clampf( d, -1.0f, 1.0f ) );
+
+ v3f axis;
+ v3_cross( rt, ra, axis );
+
+ float Fs = -a * spring,
+ Fd = -v3_dot( rba->w, axis ) * dampening;
+
+ v3_muladds( rba->w, axis, (Fs+Fd) * timestep, rba->w );
+}