chipmunk 4.1.0-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ // Collides two cpShape structures. (this function is lonely :( )
23
+ int cpCollideShapes(cpShape *a, cpShape *b, cpContact **arr);
@@ -0,0 +1,219 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ #include <stdlib.h>
23
+ #include <assert.h>
24
+
25
+ #include "chipmunk.h"
26
+ #include "prime.h"
27
+
28
+ void
29
+ cpHashSetDestroy(cpHashSet *set)
30
+ {
31
+ // Free the chains.
32
+ for(int i=0; i<set->size; i++){
33
+ // Free the bins in the chain.
34
+ cpHashSetBin *bin = set->table[i];
35
+ while(bin){
36
+ cpHashSetBin *next = bin->next;
37
+ free(bin);
38
+ bin = next;
39
+ }
40
+ }
41
+
42
+ // Free the table.
43
+ free(set->table);
44
+ }
45
+
46
+ void
47
+ cpHashSetFree(cpHashSet *set)
48
+ {
49
+ if(set) cpHashSetDestroy(set);
50
+ free(set);
51
+ }
52
+
53
+ cpHashSet *
54
+ cpHashSetAlloc(void)
55
+ {
56
+ return (cpHashSet *)calloc(1, sizeof(cpHashSet));
57
+ }
58
+
59
+ cpHashSet *
60
+ cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
61
+ {
62
+ set->size = next_prime(size);
63
+ set->entries = 0;
64
+
65
+ set->eql = eqlFunc;
66
+ set->trans = trans;
67
+
68
+ set->default_value = NULL;
69
+
70
+ set->table = (cpHashSetBin **)calloc(set->size, sizeof(cpHashSetBin *));
71
+
72
+ return set;
73
+ }
74
+
75
+ cpHashSet *
76
+ cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
77
+ {
78
+ return cpHashSetInit(cpHashSetAlloc(), size, eqlFunc, trans);
79
+ }
80
+
81
+ static int
82
+ setIsFull(cpHashSet *set)
83
+ {
84
+ return (set->entries >= set->size);
85
+ }
86
+
87
+ static void
88
+ cpHashSetResize(cpHashSet *set)
89
+ {
90
+ // Get the next approximate doubled prime.
91
+ int newSize = next_prime(set->size + 1);
92
+ // Allocate a new table.
93
+ cpHashSetBin **newTable = (cpHashSetBin **)calloc(newSize, sizeof(cpHashSetBin *));
94
+
95
+ // Iterate over the chains.
96
+ for(int i=0; i<set->size; i++){
97
+ // Rehash the bins into the new table.
98
+ cpHashSetBin *bin = set->table[i];
99
+ while(bin){
100
+ cpHashSetBin *next = bin->next;
101
+
102
+ int index = bin->hash%newSize;
103
+ bin->next = newTable[index];
104
+ newTable[index] = bin;
105
+
106
+ bin = next;
107
+ }
108
+ }
109
+
110
+ free(set->table);
111
+
112
+ set->table = newTable;
113
+ set->size = newSize;
114
+ }
115
+
116
+ void *
117
+ cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data)
118
+ {
119
+ int index = hash%set->size;
120
+
121
+ // Find the bin with the matching element.
122
+ cpHashSetBin *bin = set->table[index];
123
+ while(bin && !set->eql(ptr, bin->elt))
124
+ bin = bin->next;
125
+
126
+ // Create it necessary.
127
+ if(!bin){
128
+ bin = (cpHashSetBin *)malloc(sizeof(cpHashSetBin));
129
+ bin->hash = hash;
130
+ bin->elt = set->trans(ptr, data); // Transform the pointer.
131
+
132
+ bin->next = set->table[index];
133
+ set->table[index] = bin;
134
+
135
+ set->entries++;
136
+
137
+ // Resize the set if it's full.
138
+ if(setIsFull(set))
139
+ cpHashSetResize(set);
140
+ }
141
+
142
+ return bin->elt;
143
+ }
144
+
145
+ void *
146
+ cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr)
147
+ {
148
+ int index = hash%set->size;
149
+
150
+ // Pointer to the previous bin pointer.
151
+ cpHashSetBin **prev_ptr = &set->table[index];
152
+ // Pointer the the current bin.
153
+ cpHashSetBin *bin = set->table[index];
154
+
155
+ // Find the bin
156
+ while(bin && !set->eql(ptr, bin->elt)){
157
+ prev_ptr = &bin->next;
158
+ bin = bin->next;
159
+ }
160
+
161
+ // Remove it if it exists.
162
+ if(bin){
163
+ // Update the previos bin pointer to point to the next bin.
164
+ (*prev_ptr) = bin->next;
165
+ set->entries--;
166
+
167
+ void *return_value = bin->elt;
168
+ free(bin);
169
+ return return_value;
170
+ }
171
+
172
+ return NULL;
173
+ }
174
+
175
+ void *
176
+ cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr)
177
+ {
178
+ int index = hash%set->size;
179
+ cpHashSetBin *bin = set->table[index];
180
+ while(bin && !set->eql(ptr, bin->elt))
181
+ bin = bin->next;
182
+
183
+ return (bin ? bin->elt : set->default_value);
184
+ }
185
+
186
+ void
187
+ cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)
188
+ {
189
+ for(int i=0; i<set->size; i++){
190
+ cpHashSetBin *bin;
191
+ for(bin = set->table[i]; bin; bin = bin->next)
192
+ func(bin->elt, data);
193
+ }
194
+ }
195
+
196
+ void
197
+ cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data)
198
+ {
199
+ // Iterate over all the chains.
200
+ for(int i=0; i<set->size; i++){
201
+ // The rest works similarly to cpHashSetRemove() above.
202
+ cpHashSetBin **prev_ptr = &set->table[i];
203
+ cpHashSetBin *bin = set->table[i];
204
+ while(bin){
205
+ cpHashSetBin *next = bin->next;
206
+
207
+ if(func(bin->elt, data)){
208
+ prev_ptr = &bin->next;
209
+ } else {
210
+ (*prev_ptr) = next;
211
+
212
+ set->entries--;
213
+ free(bin);
214
+ }
215
+
216
+ bin = next;
217
+ }
218
+ }
219
+ }
@@ -0,0 +1,79 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ // cpHashSet uses a chained hashtable implementation.
23
+ // Other than the transformation functions, there is nothing fancy going on.
24
+
25
+ // cpHashSetBin's form the linked lists in the chained hash table.
26
+ typedef struct cpHashSetBin {
27
+ // Pointer to the element.
28
+ void *elt;
29
+ // Hash value of the element.
30
+ unsigned int hash;
31
+ // Next element in the chain.
32
+ struct cpHashSetBin *next;
33
+ } cpHashSetBin;
34
+
35
+ // Equality function. Returns true if ptr is equal to elt.
36
+ typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);
37
+ // Used by cpHashSetInsert(). Called to transform the ptr into an element.
38
+ typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
39
+ // Iterator function for a hashset.
40
+ typedef void (*cpHashSetIterFunc)(void *elt, void *data);
41
+ // Reject function. Returns true if elt should be dropped.
42
+ typedef int (*cpHashSetRejectFunc)(void *elt, void *data);
43
+
44
+ typedef struct cpHashSet {
45
+ // Number of elements stored in the table.
46
+ int entries;
47
+ // Number of cells in the table.
48
+ int size;
49
+
50
+ cpHashSetEqlFunc eql;
51
+ cpHashSetTransFunc trans;
52
+
53
+ // Default value returned by cpHashSetFind() when no element is found.
54
+ // Defaults to NULL.
55
+ void *default_value;
56
+
57
+ cpHashSetBin **table;
58
+ } cpHashSet;
59
+
60
+ // Basic allocation/destruction functions.
61
+ void cpHashSetDestroy(cpHashSet *set);
62
+ void cpHashSetFree(cpHashSet *set);
63
+
64
+ cpHashSet *cpHashSetAlloc(void);
65
+ cpHashSet *cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
66
+ cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
67
+
68
+ // Insert an element into the set, returns the element.
69
+ // If it doesn't already exist, the transformation function is applied.
70
+ void *cpHashSetInsert(cpHashSet *set, unsigned int hash, void *ptr, void *data);
71
+ // Remove and return an element from the set.
72
+ void *cpHashSetRemove(cpHashSet *set, unsigned int hash, void *ptr);
73
+ // Find an element in the set. Returns the default value if the element isn't found.
74
+ void *cpHashSetFind(cpHashSet *set, unsigned int hash, void *ptr);
75
+
76
+ // Iterate over a hashset.
77
+ void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);
78
+ // Iterate over a hashset while rejecting certain elements.
79
+ void cpHashSetReject(cpHashSet *set, cpHashSetRejectFunc func, void *data);
@@ -0,0 +1,553 @@
1
+ /* Copyright (c) 2007 Scott Lembcke
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ * of this software and associated documentation files (the "Software"), to deal
5
+ * in the Software without restriction, including without limitation the rights
6
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ * copies of the Software, and to permit persons to whom the Software is
8
+ * furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in
11
+ * all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ * SOFTWARE.
20
+ */
21
+
22
+ #include <stdlib.h>
23
+ #include <math.h>
24
+
25
+ #include "chipmunk.h"
26
+
27
+ // TODO: Comment me!
28
+
29
+ cpFloat cp_joint_bias_coef = 0.1f;
30
+
31
+ void cpJointDestroy(cpJoint *joint){}
32
+
33
+ void
34
+ cpJointFree(cpJoint *joint)
35
+ {
36
+ if(joint) cpJointDestroy(joint);
37
+ free(joint);
38
+ }
39
+
40
+ static void
41
+ cpJointInit(cpJoint *joint, const cpJointClass *klass, cpBody *a, cpBody *b)
42
+ {
43
+ joint->klass = klass;
44
+ joint->a = a;
45
+ joint->b = b;
46
+ }
47
+
48
+
49
+ static inline cpVect
50
+ relative_velocity(cpVect r1, cpVect v1, cpFloat w1, cpVect r2, cpVect v2, cpFloat w2){
51
+ cpVect v1_sum = cpvadd(v1, cpvmult(cpvperp(r1), w1));
52
+ cpVect v2_sum = cpvadd(v2, cpvmult(cpvperp(r2), w2));
53
+
54
+ return cpvsub(v2_sum, v1_sum);
55
+ }
56
+
57
+ static inline cpFloat
58
+ scalar_k(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)
59
+ {
60
+ cpFloat mass_sum = a->m_inv + b->m_inv;
61
+ cpFloat r1cn = cpvcross(r1, n);
62
+ cpFloat r2cn = cpvcross(r2, n);
63
+
64
+ return mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;
65
+ }
66
+
67
+ static inline void
68
+ apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
69
+ {
70
+ cpBodyApplyImpulse(a, cpvneg(j), r1);
71
+ cpBodyApplyImpulse(b, j, r2);
72
+ }
73
+
74
+ static inline void
75
+ apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
76
+ {
77
+ cpBodyApplyBiasImpulse(a, cpvneg(j), r1);
78
+ cpBodyApplyBiasImpulse(b, j, r2);
79
+ }
80
+
81
+
82
+ static void
83
+ pinJointPreStep(cpJoint *joint, cpFloat dt_inv)
84
+ {
85
+ cpBody *a = joint->a;
86
+ cpBody *b = joint->b;
87
+ cpPinJoint *jnt = (cpPinJoint *)joint;
88
+
89
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
90
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
91
+
92
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
93
+ cpFloat dist = cpvlength(delta);
94
+ jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
95
+
96
+ // calculate mass normal
97
+ jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);
98
+
99
+ // calculate bias velocity
100
+ jnt->bias = -cp_joint_bias_coef*dt_inv*(dist - jnt->dist);
101
+ jnt->jBias = 0.0f;
102
+
103
+ // apply accumulated impulse
104
+ cpVect j = cpvmult(jnt->n, jnt->jnAcc);
105
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
106
+ }
107
+
108
+ static void
109
+ pinJointApplyImpulse(cpJoint *joint)
110
+ {
111
+ cpBody *a = joint->a;
112
+ cpBody *b = joint->b;
113
+
114
+ cpPinJoint *jnt = (cpPinJoint *)joint;
115
+ cpVect n = jnt->n;
116
+ cpVect r1 = jnt->r1;
117
+ cpVect r2 = jnt->r2;
118
+
119
+ //calculate bias impulse
120
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
121
+ cpFloat vbn = cpvdot(vbr, n);
122
+
123
+ cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;
124
+ jnt->jBias += jbn;
125
+
126
+ cpVect jb = cpvmult(n, jbn);
127
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
128
+
129
+ // compute relative velocity
130
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
131
+ cpFloat vrn = cpvdot(vr, n);
132
+
133
+ // compute normal impulse
134
+ cpFloat jn = -vrn*jnt->nMass;
135
+ jnt->jnAcc =+ jn;
136
+
137
+ // apply impulse
138
+ cpVect j = cpvmult(n, jn);
139
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
140
+ }
141
+
142
+ static const cpJointClass pinJointClass = {
143
+ CP_PIN_JOINT,
144
+ pinJointPreStep,
145
+ pinJointApplyImpulse,
146
+ };
147
+
148
+ cpPinJoint *
149
+ cpPinJointAlloc(void)
150
+ {
151
+ return (cpPinJoint *)malloc(sizeof(cpPinJoint));
152
+ }
153
+
154
+ cpPinJoint *
155
+ cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
156
+ {
157
+ cpJointInit((cpJoint *)joint, &pinJointClass, a, b);
158
+
159
+ joint->anchr1 = anchr1;
160
+ joint->anchr2 = anchr2;
161
+
162
+ cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));
163
+ cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));
164
+ joint->dist = cpvlength(cpvsub(p2, p1));
165
+
166
+ joint->jnAcc = 0.0;
167
+
168
+ return joint;
169
+ }
170
+
171
+ cpJoint *
172
+ cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
173
+ {
174
+ return (cpJoint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);
175
+ }
176
+
177
+
178
+
179
+
180
+ static void
181
+ slideJointPreStep(cpJoint *joint, cpFloat dt_inv)
182
+ {
183
+ cpBody *a = joint->a;
184
+ cpBody *b = joint->b;
185
+ cpSlideJoint *jnt = (cpSlideJoint *)joint;
186
+
187
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
188
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
189
+
190
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
191
+ cpFloat dist = cpvlength(delta);
192
+ cpFloat pdist = 0.0;
193
+ if(dist > jnt->max) {
194
+ pdist = dist - jnt->max;
195
+ } else if(dist < jnt->min) {
196
+ pdist = jnt->min - dist;
197
+ dist = -dist;
198
+ }
199
+ jnt->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
200
+
201
+ // calculate mass normal
202
+ jnt->nMass = 1.0f/scalar_k(a, b, jnt->r1, jnt->r2, jnt->n);
203
+
204
+ // calculate bias velocity
205
+ jnt->bias = -cp_joint_bias_coef*dt_inv*(pdist);
206
+ jnt->jBias = 0.0f;
207
+
208
+ // apply accumulated impulse
209
+ if(!jnt->bias) //{
210
+ // if bias is 0, then the joint is not at a limit.
211
+ jnt->jnAcc = 0.0f;
212
+ // } else {
213
+ cpVect j = cpvmult(jnt->n, jnt->jnAcc);
214
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
215
+ // }
216
+ }
217
+
218
+ static void
219
+ slideJointApplyImpulse(cpJoint *joint)
220
+ {
221
+ cpSlideJoint *jnt = (cpSlideJoint *)joint;
222
+ if(!jnt->bias) return; // early exit
223
+
224
+ cpBody *a = joint->a;
225
+ cpBody *b = joint->b;
226
+
227
+ cpVect n = jnt->n;
228
+ cpVect r1 = jnt->r1;
229
+ cpVect r2 = jnt->r2;
230
+
231
+ //calculate bias impulse
232
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
233
+ cpFloat vbn = cpvdot(vbr, n);
234
+
235
+ cpFloat jbn = (jnt->bias - vbn)*jnt->nMass;
236
+ cpFloat jbnOld = jnt->jBias;
237
+ jnt->jBias = cpfmin(jbnOld + jbn, 0.0f);
238
+ jbn = jnt->jBias - jbnOld;
239
+
240
+ cpVect jb = cpvmult(n, jbn);
241
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
242
+
243
+ // compute relative velocity
244
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
245
+ cpFloat vrn = cpvdot(vr, n);
246
+
247
+ // compute normal impulse
248
+ cpFloat jn = -vrn*jnt->nMass;
249
+ cpFloat jnOld = jnt->jnAcc;
250
+ jnt->jnAcc = cpfmin(jnOld + jn, 0.0f);
251
+ jn = jnt->jnAcc - jnOld;
252
+
253
+ // apply impulse
254
+ cpVect j = cpvmult(n, jn);
255
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
256
+ }
257
+
258
+ static const cpJointClass slideJointClass = {
259
+ CP_SLIDE_JOINT,
260
+ slideJointPreStep,
261
+ slideJointApplyImpulse,
262
+ };
263
+
264
+ cpSlideJoint *
265
+ cpSlideJointAlloc(void)
266
+ {
267
+ return (cpSlideJoint *)malloc(sizeof(cpSlideJoint));
268
+ }
269
+
270
+ cpSlideJoint *
271
+ cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
272
+ {
273
+ cpJointInit((cpJoint *)joint, &slideJointClass, a, b);
274
+
275
+ joint->anchr1 = anchr1;
276
+ joint->anchr2 = anchr2;
277
+ joint->min = min;
278
+ joint->max = max;
279
+
280
+ joint->jnAcc = 0.0;
281
+
282
+ return joint;
283
+ }
284
+
285
+ cpJoint *
286
+ cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
287
+ {
288
+ return (cpJoint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);
289
+ }
290
+
291
+
292
+
293
+
294
+ static void
295
+ pivotJointPreStep(cpJoint *joint, cpFloat dt_inv)
296
+ {
297
+ cpBody *a = joint->a;
298
+ cpBody *b = joint->b;
299
+ cpPivotJoint *jnt = (cpPivotJoint *)joint;
300
+
301
+ jnt->r1 = cpvrotate(jnt->anchr1, a->rot);
302
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
303
+
304
+ // calculate mass matrix
305
+ // If I wasn't lazy, this wouldn't be so gross...
306
+ cpFloat k11, k12, k21, k22;
307
+
308
+ cpFloat m_sum = a->m_inv + b->m_inv;
309
+ k11 = m_sum; k12 = 0.0f;
310
+ k21 = 0.0f; k22 = m_sum;
311
+
312
+ cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;
313
+ cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;
314
+ cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;
315
+ k11 += r1ysq; k12 += r1nxy;
316
+ k21 += r1nxy; k22 += r1xsq;
317
+
318
+ cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;
319
+ cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;
320
+ cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;
321
+ k11 += r2ysq; k12 += r2nxy;
322
+ k21 += r2nxy; k22 += r2xsq;
323
+
324
+ cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);
325
+ jnt->k1 = cpv( k22*det_inv, -k12*det_inv);
326
+ jnt->k2 = cpv(-k21*det_inv, k11*det_inv);
327
+
328
+
329
+ // calculate bias velocity
330
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
331
+ jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);
332
+ jnt->jBias = cpvzero;
333
+
334
+ // apply accumulated impulse
335
+ apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);
336
+ }
337
+
338
+ static void
339
+ pivotJointApplyImpulse(cpJoint *joint)
340
+ {
341
+ cpBody *a = joint->a;
342
+ cpBody *b = joint->b;
343
+
344
+ cpPivotJoint *jnt = (cpPivotJoint *)joint;
345
+ cpVect r1 = jnt->r1;
346
+ cpVect r2 = jnt->r2;
347
+ cpVect k1 = jnt->k1;
348
+ cpVect k2 = jnt->k2;
349
+
350
+ //calculate bias impulse
351
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
352
+ vbr = cpvsub(jnt->bias, vbr);
353
+
354
+ cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));
355
+ jnt->jBias = cpvadd(jnt->jBias, jb);
356
+
357
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
358
+
359
+ // compute relative velocity
360
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
361
+
362
+ // compute normal impulse
363
+ cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));
364
+ jnt->jAcc = cpvadd(jnt->jAcc, j);
365
+
366
+ // apply impulse
367
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
368
+ }
369
+
370
+ static const cpJointClass pivotJointClass = {
371
+ CP_PIVOT_JOINT,
372
+ pivotJointPreStep,
373
+ pivotJointApplyImpulse,
374
+ };
375
+
376
+ cpPivotJoint *
377
+ cpPivotJointAlloc(void)
378
+ {
379
+ return (cpPivotJoint *)malloc(sizeof(cpPivotJoint));
380
+ }
381
+
382
+ cpPivotJoint *
383
+ cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot)
384
+ {
385
+ cpJointInit((cpJoint *)joint, &pivotJointClass, a, b);
386
+
387
+ joint->anchr1 = cpvunrotate(cpvsub(pivot, a->p), a->rot);
388
+ joint->anchr2 = cpvunrotate(cpvsub(pivot, b->p), b->rot);
389
+
390
+ joint->jAcc = cpvzero;
391
+
392
+ return joint;
393
+ }
394
+
395
+ cpJoint *
396
+ cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
397
+ {
398
+ return (cpJoint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, pivot);
399
+ }
400
+
401
+
402
+
403
+
404
+ static void
405
+ grooveJointPreStep(cpJoint *joint, cpFloat dt_inv)
406
+ {
407
+ cpBody *a = joint->a;
408
+ cpBody *b = joint->b;
409
+ cpGrooveJoint *jnt = (cpGrooveJoint *)joint;
410
+
411
+ // calculate endpoints in worldspace
412
+ cpVect ta = cpBodyLocal2World(a, jnt->grv_a);
413
+ cpVect tb = cpBodyLocal2World(a, jnt->grv_b);
414
+
415
+ // calculate axis
416
+ cpVect n = cpvrotate(jnt->grv_n, a->rot);
417
+ cpFloat d = cpvdot(ta, n);
418
+
419
+ jnt->grv_tn = n;
420
+ jnt->r2 = cpvrotate(jnt->anchr2, b->rot);
421
+
422
+ // calculate tangential distance along the axis of r2
423
+ cpFloat td = cpvcross(cpvadd(b->p, jnt->r2), n);
424
+ // calculate clamping factor and r2
425
+ if(td <= cpvcross(ta, n)){
426
+ jnt->clamp = 1.0f;
427
+ jnt->r1 = cpvsub(ta, a->p);
428
+ } else if(td >= cpvcross(tb, n)){
429
+ jnt->clamp = -1.0f;
430
+ jnt->r1 = cpvsub(tb, a->p);
431
+ } else {
432
+ jnt->clamp = 0.0f;
433
+ jnt->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);
434
+ }
435
+
436
+ // calculate mass matrix
437
+ // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...
438
+ cpFloat k11, k12, k21, k22;
439
+ cpFloat m_sum = a->m_inv + b->m_inv;
440
+
441
+ // start with I*m_sum
442
+ k11 = m_sum; k12 = 0.0f;
443
+ k21 = 0.0f; k22 = m_sum;
444
+
445
+ // add the influence from r1
446
+ cpFloat r1xsq = jnt->r1.x * jnt->r1.x * a->i_inv;
447
+ cpFloat r1ysq = jnt->r1.y * jnt->r1.y * a->i_inv;
448
+ cpFloat r1nxy = -jnt->r1.x * jnt->r1.y * a->i_inv;
449
+ k11 += r1ysq; k12 += r1nxy;
450
+ k21 += r1nxy; k22 += r1xsq;
451
+
452
+ // add the influnce from r2
453
+ cpFloat r2xsq = jnt->r2.x * jnt->r2.x * b->i_inv;
454
+ cpFloat r2ysq = jnt->r2.y * jnt->r2.y * b->i_inv;
455
+ cpFloat r2nxy = -jnt->r2.x * jnt->r2.y * b->i_inv;
456
+ k11 += r2ysq; k12 += r2nxy;
457
+ k21 += r2nxy; k22 += r2xsq;
458
+
459
+ // invert
460
+ cpFloat det_inv = 1.0f/(k11*k22 - k12*k21);
461
+ jnt->k1 = cpv( k22*det_inv, -k12*det_inv);
462
+ jnt->k2 = cpv(-k21*det_inv, k11*det_inv);
463
+
464
+
465
+ // calculate bias velocity
466
+ cpVect delta = cpvsub(cpvadd(b->p, jnt->r2), cpvadd(a->p, jnt->r1));
467
+ jnt->bias = cpvmult(delta, -cp_joint_bias_coef*dt_inv);
468
+ jnt->jBias = cpvzero;
469
+
470
+ // apply accumulated impulse
471
+ apply_impulses(a, b, jnt->r1, jnt->r2, jnt->jAcc);
472
+ }
473
+
474
+ static inline cpVect
475
+ grooveConstrain(cpGrooveJoint *jnt, cpVect j){
476
+ cpVect n = jnt->grv_tn;
477
+ cpVect jn = cpvmult(n, cpvdot(j, n));
478
+
479
+ cpVect t = cpvperp(n);
480
+ cpFloat coef = (jnt->clamp*cpvcross(j, n) > 0.0f) ? 1.0f : 0.0f;
481
+ cpVect jt = cpvmult(t, cpvdot(j, t)*coef);
482
+
483
+ return cpvadd(jn, jt);
484
+ }
485
+
486
+ static void
487
+ grooveJointApplyImpulse(cpJoint *joint)
488
+ {
489
+ cpBody *a = joint->a;
490
+ cpBody *b = joint->b;
491
+
492
+ cpGrooveJoint *jnt = (cpGrooveJoint *)joint;
493
+ cpVect r1 = jnt->r1;
494
+ cpVect r2 = jnt->r2;
495
+ cpVect k1 = jnt->k1;
496
+ cpVect k2 = jnt->k2;
497
+
498
+ //calculate bias impulse
499
+ cpVect vbr = relative_velocity(r1, a->v_bias, a->w_bias, r2, b->v_bias, b->w_bias);
500
+ vbr = cpvsub(jnt->bias, vbr);
501
+
502
+ cpVect jb = cpv(cpvdot(vbr, k1), cpvdot(vbr, k2));
503
+ cpVect jbOld = jnt->jBias;
504
+ jnt->jBias = grooveConstrain(jnt, cpvadd(jbOld, jb));
505
+ jb = cpvsub(jnt->jBias, jbOld);
506
+
507
+ apply_bias_impulses(a, b, jnt->r1, jnt->r2, jb);
508
+
509
+ // compute impulse
510
+ cpVect vr = relative_velocity(r1, a->v, a->w, r2, b->v, b->w);
511
+
512
+ cpVect j = cpv(-cpvdot(vr, k1), -cpvdot(vr, k2));
513
+ cpVect jOld = jnt->jAcc;
514
+ jnt->jAcc = grooveConstrain(jnt, cpvadd(jOld, j));
515
+ j = cpvsub(jnt->jAcc, jOld);
516
+
517
+ // apply impulse
518
+ apply_impulses(a, b, jnt->r1, jnt->r2, j);
519
+ }
520
+
521
+ static const cpJointClass grooveJointClass = {
522
+ CP_GROOVE_JOINT,
523
+ grooveJointPreStep,
524
+ grooveJointApplyImpulse,
525
+ };
526
+
527
+ cpGrooveJoint *
528
+ cpGrooveJointAlloc(void)
529
+ {
530
+ return (cpGrooveJoint *)malloc(sizeof(cpGrooveJoint));
531
+ }
532
+
533
+ cpGrooveJoint *
534
+ cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
535
+ {
536
+ cpJointInit((cpJoint *)joint, &grooveJointClass, a, b);
537
+
538
+ joint->grv_a = groove_a;
539
+ joint->grv_b = groove_b;
540
+ joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));
541
+ joint->anchr2 = anchr2;
542
+
543
+ joint->jAcc = cpvzero;
544
+
545
+ return joint;
546
+ }
547
+
548
+ cpJoint *
549
+ cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
550
+ {
551
+ return (cpJoint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
552
+ }
553
+