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);