1 /*************************************************************************
2  *                          D bindings for ODE                           *
3  *                                                                       *
4  *       C header port by Daniel "q66" Kolesa <quaker66@gmail.com>       *
5  *                                                                       *
6  * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith.       *
7  * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
8  *                                                                       *
9  * This library is free software; you can redistribute it and/or         *
10  * modify it under the terms of EITHER:                                  *
11  *   (1) The GNU Lesser General Public License as published by the Free  *
12  *       Software Foundation; either version 2.1 of the License, or (at  *
13  *       your option) any later version. The text of the GNU Lesser      *
14  *       General Public License is included with this library in the     *
15  *       file LICENSE.TXT.                                               *
16  *   (2) The BSD-style license that is included with this library in     *
17  *       the file LICENSE-BSD.TXT.                                       *
18  *                                                                       *
19  * This library is distributed in the hope that it will be useful,       *
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
22  * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
23  *                                                                       *
24  *************************************************************************/
25 
26 module deimos.ode.odemath;
27 
28 private import deimos.ode.common;
29 
30 /*
31  * macro to access elements i,j in an NxM matrix A, independent of the
32  * matrix storage convention.
33  */
34 auto dACCESS33(T)(T a, size_t i, size_t j)
35 {
36     return a[i * 4 + j];
37 }
38 
39 /*
40  * Macro to test for valid floating point values
41  */
42 bool dVALIDVEC3(T)(T v)
43 {
44     return !(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2]));
45 }
46 
47 bool dVALIDVEC4(T)(T v)
48 {
49     return !(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2]) || dIsNan(v[3]));
50 }
51 
52 bool dVALIDMAT3(T)(T m)
53 {
54     return !(
55         dIsNan(m[0]) || dIsNan(m[1]) || dIsNan(m[2])  || dIsNan(m[3]) ||
56         dIsNan(m[4]) || dIsNan(m[5]) || dIsNan(m[6])  || dIsNan(m[7]) ||
57         dIsNan(m[8]) || dIsNan(m[9]) || dIsNan(m[10]) || dIsNan(m[11])
58     );
59 }
60 
61 bool dVALIDMAT4(T)(T m)
62 {
63     return !(
64         dIsNan(m[0])  || dIsNan(m[1])  || dIsNan(m[2])  || dIsNan(m[3])  ||
65         dIsNan(m[4])  || dIsNan(m[5])  || dIsNan(m[6])  || dIsNan(m[7])  ||
66         dIsNan(m[8])  || dIsNan(m[9])  || dIsNan(m[10]) || dIsNan(m[11]) ||
67         dIsNan(m[12]) || dIsNan(m[13]) || dIsNan(m[14]) || dIsNan(m[15])
68     );
69 }
70 
71 // Some vector math
72 void dAddVectors3(dReal* res, in dReal* a, in dReal* b)
73 {
74     dReal res_0, res_1, res_2;
75     res_0 = a[0] + b[0];
76     res_1 = a[1] + b[1];
77     res_2 = a[2] + b[2];
78 
79     // Only assign after all the calculations are over to avoid incurring memory aliasing
80     res[0] = res_0; res[1] = res_1; res[2] = res_2;
81 }
82 
83 
84 void dSubtractVectors3(dReal* res, in dReal* a, in dReal* b)
85 {
86     dReal res_0, res_1, res_2;
87     res_0 = a[0] - b[0];
88     res_1 = a[1] - b[1];
89     res_2 = a[2] - b[2];
90 
91     // Only assign after all the calculations are over to avoid incurring memory aliasing
92     res[0] = res_0; res[1] = res_1; res[2] = res_2;
93 }
94 
95 void dAddScaledVectors3(dReal* res, in dReal* a, in dReal* b, dReal a_scale, dReal b_scale)
96 {
97     dReal res_0, res_1, res_2;
98     res_0 = a_scale * a[0] + b_scale * b[0];
99     res_1 = a_scale * a[1] + b_scale * b[1];
100     res_2 = a_scale * a[2] + b_scale * b[2];
101 
102     // Only assign after all the calculations are over to avoid incurring memory aliasing
103     res[0] = res_0; res[1] = res_1; res[2] = res_2;
104 }
105 
106 void dScaleVector3(dReal* res, dReal nScale)
107 {
108     res[0] *= nScale;
109     res[1] *= nScale;
110     res[2] *= nScale;
111 }
112 
113 void dNegateVector3(dReal* res)
114 {
115     res[0] = -res[0];
116     res[1] = -res[1];
117     res[2] = -res[2];
118 }
119 
120 void dCopyVector3(dReal* res, in dReal* a)
121 {
122     dReal res_0, res_1, res_2;
123     res_0 = a[0];
124     res_1 = a[1];
125     res_2 = a[2];
126 
127     // Only assign after all the calculations are over to avoid incurring memory aliasing
128     res[0] = res_0; res[1] = res_1; res[2] = res_2;
129 }
130 
131 void dCopyScaledVector3(dReal* res, in dReal* a, dReal nScale)
132 {
133     dReal res_0, res_1, res_2;
134     res_0 = a[0] * nScale;
135     res_1 = a[1] * nScale;
136     res_2 = a[2] * nScale;
137 
138     // Only assign after all the calculations are over to avoid incurring memory aliasing
139     res[0] = res_0; res[1] = res_1; res[2] = res_2;
140 }
141 
142 void dCopyNegatedVector3(dReal* res, in dReal* a)
143 {
144     dReal res_0, res_1, res_2;
145     res_0 = -a[0];
146     res_1 = -a[1];
147     res_2 = -a[2];
148 
149     // Only assign after all the calculations are over to avoid incurring memory aliasing
150     res[0] = res_0; res[1] = res_1; res[2] = res_2;
151 }
152 
153 void dCopyVector4(dReal* res, in dReal* a)
154 {
155     dReal res_0, res_1, res_2, res_3;
156     res_0 = a[0];
157     res_1 = a[1];
158     res_2 = a[2];
159     res_3 = a[3];
160 
161     // Only assign after all the calculations are over to avoid incurring memory aliasing
162     res[0] = res_0; res[1] = res_1; res[2] = res_2; res[3] = res_3;
163 }
164 
165 void dCopyMatrix4x4(dReal* res, in dReal* a)
166 {
167     dCopyVector4(res + 0, a + 0);
168     dCopyVector4(res + 4, a + 4);
169     dCopyVector4(res + 8, a + 8);
170 }
171 
172 void dCopyMatrix4x3(dReal* res, in dReal* a)
173 {
174     dCopyVector3(res + 0, a + 0);
175     dCopyVector3(res + 4, a + 4);
176     dCopyVector3(res + 8, a + 8);
177 }
178 
179 void dGetMatrixColumn3(dReal* res, in dReal* a, uint n)
180 {
181     dReal res_0, res_1, res_2;
182     res_0 = a[n + 0];
183     res_1 = a[n + 4];
184     res_2 = a[n + 8];
185 
186     // Only assign after all the calculations are over to avoid incurring memory aliasing
187     res[0] = res_0; res[1] = res_1; res[2] = res_2;
188 }
189 
190 dReal dCalcVectorLength3(in dReal* a)
191 {
192     return dSqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
193 }
194 
195 dReal dCalcVectorLengthSquare3(in dReal* a)
196 {
197     return (a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
198 }
199 
200 dReal dCalcPointDepth3(in dReal* test_p, in dReal* plane_p, in dReal* plane_n)
201 {
202     return (plane_p[0] - test_p[0]) * plane_n[0] + (plane_p[1] - test_p[1]) * plane_n[1] + (plane_p[2] - test_p[2]) * plane_n[2];
203 }
204 
205 /*
206 * 3-way dot product. _dCalcVectorDot3 means that elements of `a' and `b' are spaced
207 * step_a and step_b indexes apart respectively. dCalcVectorDot3() means dDot311.
208 */
209 dReal _dCalcVectorDot3(in dReal* a, in dReal* b, uint step_a, uint step_b)
210 {
211     return a[0] * b[0] + a[step_a] * b[step_b] + a[2 * step_a] * b[2 * step_b];
212 }
213 
214 dReal dCalcVectorDot3    (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,1,1); }
215 dReal dCalcVectorDot3_13 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,1,3); }
216 dReal dCalcVectorDot3_31 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,3,1); }
217 dReal dCalcVectorDot3_33 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,3,3); }
218 dReal dCalcVectorDot3_14 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,1,4); }
219 dReal dCalcVectorDot3_41 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,4,1); }
220 dReal dCalcVectorDot3_44 (in dReal* a, in dReal* b) { return _dCalcVectorDot3(a,b,4,4); }
221 
222 /*
223  * cross product, set res = a x b. _dCalcVectorCross3 means that elements of `res', `a'
224  * and `b' are spaced step_res, step_a and step_b indexes apart respectively.
225  * dCalcVectorCross3() means dCross3111. 
226  */
227 void _dCalcVectorCross3(dReal* res, in dReal* a, in dReal* b, uint step_res, uint step_a, uint step_b)
228 {
229     dReal res_0, res_1, res_2;
230     res_0 = a[  step_a]*b[2*step_b] - a[2*step_a]*b[  step_b];
231     res_1 = a[2*step_a]*b[       0] - a[       0]*b[2*step_b];
232     res_2 = a[       0]*b[  step_b] - a[  step_a]*b[       0];
233 
234     res[         0] = res_0;
235     res[  step_res] = res_1;
236     res[2*step_res] = res_2;
237 }
238 
239 void dCalcVectorCross3    (dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 1, 1, 1); }
240 void dCalcVectorCross3_114(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 1, 1, 4); }
241 void dCalcVectorCross3_141(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 1, 4, 1); }
242 void dCalcVectorCross3_144(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 1, 4, 4); }
243 void dCalcVectorCross3_411(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 4, 1, 1); }
244 void dCalcVectorCross3_414(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 4, 1, 4); }
245 void dCalcVectorCross3_441(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 4, 4, 1); }
246 void dCalcVectorCross3_444(dReal* res, in dReal* a, in dReal* b) { _dCalcVectorCross3(res, a, b, 4, 4, 4); }
247 
248 void dAddVectorCross3(dReal* res, in dReal* a, in dReal* b)
249 {
250     dReal[3] tmp;
251     dCalcVectorCross3(tmp.ptr, a, b);
252     dAddVectors3(res, res, tmp.ptr);
253 }
254 
255 void dSubtractVectorCross3(dReal* res, in dReal* a, in dReal* b)
256 {
257     dReal[3] tmp;
258     dCalcVectorCross3(tmp.ptr, a, b);
259     dSubtractVectors3(res, res, tmp.ptr);
260 }
261 
262 /*
263  * set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b.
264  * A is stored by rows, and has `skip' elements per row. the matrix is
265  * assumed to be already zero, so this does not write zero elements!
266  * if (plus,minus) is (+,-) then a positive version will be written.
267  * if (plus,minus) is (-,+) then a negative version will be written.
268  */
269 void dSetCrossMatrixPlus(dReal* res, in dReal* a, uint skip)
270 {
271     const dReal a_0 = a[0], a_1 = a[1], a_2 = a[2];
272     res[1] = -a_2;
273     res[2] = +a_1;
274     res[skip+0] = +a_2;
275     res[skip+2] = -a_0;
276     res[2*skip+0] = -a_1;
277     res[2*skip+1] = +a_0;
278 }
279 
280 void dSetCrossMatrixMinus(dReal* res, in dReal* a, uint skip)
281 {
282     const dReal a_0 = a[0], a_1 = a[1], a_2 = a[2];
283     res[1] = +a_2;
284     res[2] = -a_1;
285     res[skip+0] = -a_2;
286     res[skip+2] = +a_0;
287     res[2*skip+0] = +a_1;
288     res[2*skip+1] = -a_0;
289 }
290 
291 /*
292  * compute the distance between two 3D-vectors
293  */
294 dReal dCalcPointsDistance3(in dReal* a, in dReal* b)
295 {
296     dReal res;
297     dReal[3] tmp;
298     dSubtractVectors3(tmp.ptr, a, b);
299     res = dCalcVectorLength3(tmp.ptr);
300     return res;
301 }
302 
303 /*
304  * special case matrix multiplication, with operator selection
305  */
306 void dMultiplyHelper0_331(dReal* res, in dReal* a, in dReal* b)
307 {
308     dReal res_0, res_1, res_2;
309     res_0 = dCalcVectorDot3(a, b);
310     res_1 = dCalcVectorDot3(a + 4, b);
311     res_2 = dCalcVectorDot3(a + 8, b);
312 
313     // Only assign after all the calculations are over to avoid incurring memory aliasing
314     res[0] = res_0; res[1] = res_1; res[2] = res_2;
315 }
316 
317 void dMultiplyHelper1_331(dReal* res, in dReal* a, in dReal* b)
318 {
319     dReal res_0, res_1, res_2;
320     res_0 = dCalcVectorDot3_41(a, b);
321     res_1 = dCalcVectorDot3_41(a + 1, b);
322     res_2 = dCalcVectorDot3_41(a + 2, b);
323 
324     // Only assign after all the calculations are over to avoid incurring memory aliasing
325     res[0] = res_0; res[1] = res_1; res[2] = res_2;
326 }
327 
328 void dMultiplyHelper0_133(dReal* res, in dReal* a, in dReal* b)
329 {
330     dMultiplyHelper1_331(res, b, a);
331 }
332 
333 void dMultiplyHelper1_133(dReal* res, in dReal* a, in dReal* b)
334 {
335     dReal res_0, res_1, res_2;
336     res_0 = dCalcVectorDot3_44(a, b);
337     res_1 = dCalcVectorDot3_44(a + 1, b);
338     res_2 = dCalcVectorDot3_44(a + 2, b);
339 
340     // Only assign after all the calculations are over to avoid incurring memory aliasing
341     res[0] = res_0; res[1] = res_1; res[2] = res_2;
342 }
343 
344 /* 
345 Note: NEVER call any of these functions/macros with the same variable for A and C, 
346 it is not equivalent to A*=B.
347 */
348 void dMultiply0_331(dReal* res, in dReal* a, in dReal* b)
349 {
350     dMultiplyHelper0_331(res, a, b);
351 }
352 
353 void dMultiply1_331(dReal* res, in dReal* a, in dReal* b)
354 {
355     dMultiplyHelper1_331(res, a, b);
356 }
357 
358 void dMultiply0_133(dReal* res, in dReal* a, in dReal* b)
359 {
360     dMultiplyHelper0_133(res, a, b);
361 }
362 
363 void dMultiply0_333(dReal* res, in dReal* a, in dReal* b)
364 {
365     dMultiplyHelper0_133(res + 0, a + 0, b);
366     dMultiplyHelper0_133(res + 4, a + 4, b);
367     dMultiplyHelper0_133(res + 8, a + 8, b);
368 }
369 
370 void dMultiply1_333(dReal* res, in dReal* a, in dReal* b)
371 {
372     dMultiplyHelper1_133(res + 0, b, a + 0);
373     dMultiplyHelper1_133(res + 4, b, a + 1);
374     dMultiplyHelper1_133(res + 8, b, a + 2);
375 }
376 
377 void dMultiply2_333(dReal* res, in dReal* a, in dReal* b)
378 {
379     dMultiplyHelper0_331(res + 0, b, a + 0);
380     dMultiplyHelper0_331(res + 4, b, a + 4);
381     dMultiplyHelper0_331(res + 8, b, a + 8);
382 }
383 
384 void dMultiplyAdd0_331(dReal* res, in dReal* a, in dReal* b)
385 {
386     dReal[3] tmp;
387     dMultiplyHelper0_331(tmp.ptr, a, b);
388     dAddVectors3(res, res, tmp.ptr);
389 }
390 
391 void dMultiplyAdd1_331(dReal* res, in dReal* a, in dReal* b)
392 {
393     dReal[3] tmp;
394     dMultiplyHelper1_331(tmp.ptr, a, b);
395     dAddVectors3(res, res, tmp.ptr);
396 }
397 
398 void dMultiplyAdd0_133(dReal* res, in dReal* a, in dReal* b)
399 {
400     dReal[3] tmp;
401     dMultiplyHelper0_133(tmp.ptr, a, b);
402     dAddVectors3(res, res, tmp.ptr);
403 }
404 
405 void dMultiplyAdd0_333(dReal* res, in dReal* a, in dReal* b)
406 {
407     dReal[3] tmp;
408     dMultiplyHelper0_133(tmp.ptr, a + 0, b);
409     dAddVectors3(res+ 0, res + 0, tmp.ptr);
410     dMultiplyHelper0_133(tmp.ptr, a + 4, b);
411     dAddVectors3(res + 4, res + 4, tmp.ptr);
412     dMultiplyHelper0_133(tmp.ptr, a + 8, b);
413     dAddVectors3(res + 8, res + 8, tmp.ptr);
414 }
415 
416 void dMultiplyAdd1_333(dReal* res, in dReal* a, in dReal* b)
417 {
418     dReal[3] tmp;
419     dMultiplyHelper1_133(tmp.ptr, b, a + 0);
420     dAddVectors3(res + 0, res + 0, tmp.ptr);
421     dMultiplyHelper1_133(tmp.ptr, b, a + 1);
422     dAddVectors3(res + 4, res + 4, tmp.ptr);
423     dMultiplyHelper1_133(tmp.ptr, b, a + 2);
424     dAddVectors3(res + 8, res + 8, tmp.ptr);
425 }
426 
427 void dMultiplyAdd2_333(dReal* res, in dReal* a, in dReal* b)
428 {
429     dReal[3] tmp;
430     dMultiplyHelper0_331(tmp.ptr, b, a + 0);
431     dAddVectors3(res + 0, res + 0, tmp.ptr);
432     dMultiplyHelper0_331(tmp.ptr, b, a + 4);
433     dAddVectors3(res + 4, res + 4, tmp.ptr);
434     dMultiplyHelper0_331(tmp.ptr, b, a + 8);
435     dAddVectors3(res + 8, res + 8, tmp.ptr);
436 }
437 
438 extern (C):
439 nothrow:
440 
441 /*
442  * normalize 3x1 and 4x1 vectors (i.e. scale them to unit length)
443  */
444 
445 // For DLL export
446 int  dSafeNormalize3(dVector3 a);
447 int  dSafeNormalize4(dVector4 a);
448 void dNormalize3(dVector3 a); // Potentially asserts on zero vec
449 void dNormalize4(dVector4 a); // Potentially asserts on zero vec
450 
451 /*
452  * given a unit length "normal" vector n, generate vectors p and q vectors
453  * that are an orthonormal basis for the plane space perpendicular to n.
454  * i.e. this makes p,q such that n,p,q are all perpendicular to each other.
455  * q will equal n x p. if n is not unit length then p will be unit length but
456  * q wont be.
457  */
458 
459 void dPlaneSpace(in dVector3 n, dVector3 p, dVector3 q);
460 /* Makes sure the matrix is a proper rotation */
461 void dOrthogonalizeR(dMatrix3 m);