| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include <stdio.h> |
| | 4 | #include <stdlib.h> |
| | 5 | #include <math.h> |
| | 6 | #include <sys/time.h> |
| | 7 | |
| | 8 | #define deg22pt5 256 |
| | 9 | #define deg45 512 |
| | 10 | #define deg90 1024 |
| | 11 | |
| | 12 | #define Cosine45 46341 /* 46340.95001 cosine(45deg)*/ |
| | 13 | |
| | 14 | extern int16_t ArcCosTable[]; |
| | 15 | extern int16_t ArcSineTable[]; |
| | 16 | extern int16_t ArcTanTable[]; |
| | 17 | static int oneoversin[4096]; |
| | 18 | |
| | 19 | int min(int a, int b) { return a < b ? a : b; } |
| | 20 | int max(int a, int b) { return a < b ? b : a; } |
| | 21 | |
| | 22 | /* Fixed Point Divide - returns a / b */ |
| | 23 | |
| | 24 | int DIV_FIXED(const int a, const int b) |
| | 25 | { |
| | 26 | return (((int64_t)a << 16) / b); |
| | 27 | } |
| | 28 | |
| | 29 | /* |
| | 30 | Fixed Point Multiply. |
| | 31 | |
| | 32 | 16.16 * 16.16 -> 16.16 |
| | 33 | or |
| | 34 | 16.16 * 0.32 -> 0.32 |
| | 35 | |
| | 36 | A proper version of this function ought to read |
| | 37 | 16.16 * 16.16 -> 32.16 |
| | 38 | but this would require a long long result |
| | 39 | |
| | 40 | Algorithm: |
| | 41 | |
| | 42 | Take the mid 32 bits of the 64 bit result |
| | 43 | */ |
| | 44 | |
| | 45 | int MUL_FIXED(const int a, const int b) |
| | 46 | { |
| | 47 | return (((int64_t)a * (int64_t)b) >> 16); |
| | 48 | } |
| | 49 | |
| | 50 | void ConstructOneOverSinTable() |
| | 51 | { |
| | 52 | int a = 0; |
| | 53 | |
| | 54 | for (; a < 4096; a++) |
| | 55 | { |
| | 56 | int sin = GetSin(a); |
| | 57 | |
| | 58 | if (sin != 0) |
| | 59 | { |
| | 60 | oneoversin[a] = DIV_FIXED(ONE_FIXED, sin); |
| | 61 | } |
| | 62 | else |
| | 63 | { |
| | 64 | sin = 100; |
| | 65 | oneoversin[a] = DIV_FIXED(ONE_FIXED, sin); |
| | 66 | } |
| | 67 | } |
| | 68 | } |
| | 69 | |
| | 70 | int GetOneOverSin(int a) |
| | 71 | { |
| | 72 | return oneoversin[a & wrap360]; |
| | 73 | } |
| | 74 | |
| | 75 | int DotProduct(const VECTORCH *vptr1, const VECTORCH *vptr2) |
| | 76 | { |
| | 77 | return MUL_FIXED(vptr1->vx, vptr2->vx) + MUL_FIXED(vptr1->vy, vptr2->vy)+ MUL_FIXED(vptr1->vz, vptr2->vz); |
| | 78 | } |
| | 79 | |
| | 80 | int Magnitude(const VECTORCH *v) |
| | 81 | { |
| | 82 | float x = v->vx; |
| | 83 | float y = v->vy; |
| | 84 | float z = v->vz; |
| | 85 | |
| | 86 | return sqrt((x * x) + (y * y) + (z * z)); |
| | 87 | } |
| | 88 | |
| | 89 | int VectorDistance(const VECTORCH *v1, const VECTORCH *v2) |
| | 90 | { |
| | 91 | float x = v1->vx - v2->vx; |
| | 92 | float y = v1->vy - v2->vy; |
| | 93 | float z = v1->vz - v2->vz; |
| | 94 | |
| | 95 | return sqrt((x * x) + (y * y) + (z * z)); |
| | 96 | } |
| | 97 | |
| | 98 | /* |
| | 99 | |
| | 100 | Create Matrix from Euler Angles |
| | 101 | |
| | 102 | It requires a pointer to some euler angles and a pointer to a matrix |
| | 103 | |
| | 104 | Construct the matrix elements using the following formula |
| | 105 | |
| | 106 | Formula for ZXY Matrix |
| | 107 | |
| | 108 | m11 = cy*cz + sx*sy*sz m12 = -cy*sz + sx*sy*cz m13 = cx*sy |
| | 109 | m21 = cx*sz m22 = cx*cz m23 = -sx |
| | 110 | m31 = -sy*cz + sx*cy*sz m32 = sy*sz + sx*cy*cz m33 = cx*cy |
| | 111 | |
| | 112 | */ |
| | 113 | |
| | 114 | void CreateEulerMatrix(EULER *e, MATRIXCH *m1) |
| | 115 | { |
| | 116 | int sx = GetSin(e->EulerX); |
| | 117 | int sy = GetSin(e->EulerY); |
| | 118 | int sz = GetSin(e->EulerZ); |
| | 119 | |
| | 120 | int cx = GetCos(e->EulerX); |
| | 121 | int cy = GetCos(e->EulerY); |
| | 122 | int cz = GetCos(e->EulerZ); |
| | 123 | |
| | 124 | int sx_sy = MUL_FIXED(sx, sy); |
| | 125 | int sx_cy = MUL_FIXED(sx, cy); |
| | 126 | |
| | 127 | /* m11 = cy*cz + sx*sy*sz */ |
| | 128 | |
| | 129 | m1->mat11 = MUL_FIXED(cy, cz) + MUL_FIXED(sx_sy, sz); |
| | 130 | |
| | 131 | /* m12 = -cy*sz + sx*sy*cz */ |
| | 132 | |
| | 133 | m1->mat12 = MUL_FIXED(-cy, sz) + MUL_FIXED(sx_sy, cz); |
| | 134 | |
| | 135 | /* m13 = cx*sy */ |
| | 136 | |
| | 137 | m1->mat13 = MUL_FIXED(cx, sy); |
| | 138 | |
| | 139 | /* m21 = cx*sz */ |
| | 140 | |
| | 141 | m1->mat21 = MUL_FIXED(cx, sz); |
| | 142 | |
| | 143 | /* m22 = cx*cz */ |
| | 144 | |
| | 145 | m1->mat22 = MUL_FIXED(cx, cz); |
| | 146 | |
| | 147 | /* m23 = -sx */ |
| | 148 | |
| | 149 | m1->mat23 = -sx; |
| | 150 | |
| | 151 | /* m31 = -sy*cz + sx*cy*sz */ |
| | 152 | |
| | 153 | m1->mat31 = MUL_FIXED(-sy, cz) + MUL_FIXED(sx_cy, sz); |
| | 154 | |
| | 155 | /* m32 = sy*sz + sx*cy*cz */ |
| | 156 | |
| | 157 | m1->mat32 = MUL_FIXED(sy,sz) + MUL_FIXED(sx_cy, cz); |
| | 158 | |
| | 159 | /* m33 = cx*cy */ |
| | 160 | |
| | 161 | m1->mat33 = MUL_FIXED(cx,cy); |
| | 162 | } |
| | 163 | |
| | 164 | /* |
| | 165 | Matrix Multiply Function |
| | 166 | |
| | 167 | A 3x3 Matrix is represented here as |
| | 168 | |
| | 169 | m11 m12 m13 |
| | 170 | m21 m22 m23 |
| | 171 | m31 m32 m33 |
| | 172 | |
| | 173 | Row #1 (r1) of the matrix is m11 m12 m13 |
| | 174 | Column #1 (c1) of the matrix is m11 m32 m31 |
| | 175 | |
| | 176 | Under multiplication |
| | 177 | |
| | 178 | m'' = m x m' |
| | 179 | |
| | 180 | where |
| | 181 | |
| | 182 | m11'' = c1.r1' |
| | 183 | m12'' = c2.r1' |
| | 184 | m13'' = c3.r1' |
| | 185 | |
| | 186 | m21'' = c1.r2' |
| | 187 | m22'' = c2.r2' |
| | 188 | m23'' = c3.r2' |
| | 189 | |
| | 190 | m31'' = c1.r3' |
| | 191 | m32'' = c2.r3' |
| | 192 | m33'' = c3.r3' |
| | 193 | */ |
| | 194 | |
| | 195 | void MatrixMultiply(const MATRIXCH *m1, const MATRIXCH *m2, MATRIXCH *m3) |
| | 196 | { |
| | 197 | int mat11 = MUL_FIXED(m1->mat11, m2->mat11) + MUL_FIXED(m1->mat21, m2->mat12) + MUL_FIXED(m1->mat31, m2->mat13); |
| | 198 | int mat12 = MUL_FIXED(m1->mat12, m2->mat11) + MUL_FIXED(m1->mat22, m2->mat12) + MUL_FIXED(m1->mat32, m2->mat13); |
| | 199 | int mat13 = MUL_FIXED(m1->mat13, m2->mat11) + MUL_FIXED(m1->mat23, m2->mat12) + MUL_FIXED(m1->mat33, m2->mat13); |
| | 200 | int mat21 = MUL_FIXED(m1->mat11, m2->mat21) + MUL_FIXED(m1->mat21, m2->mat22) + MUL_FIXED(m1->mat31, m2->mat23); |
| | 201 | int mat22 = MUL_FIXED(m1->mat12, m2->mat21) + MUL_FIXED(m1->mat22, m2->mat22) + MUL_FIXED(m1->mat32, m2->mat23); |
| | 202 | int mat23 = MUL_FIXED(m1->mat13, m2->mat21) + MUL_FIXED(m1->mat23, m2->mat22) + MUL_FIXED(m1->mat33, m2->mat23); |
| | 203 | int mat31 = MUL_FIXED(m1->mat11, m2->mat31) + MUL_FIXED(m1->mat21, m2->mat32) + MUL_FIXED(m1->mat31, m2->mat33); |
| | 204 | int mat32 = MUL_FIXED(m1->mat12, m2->mat31) + MUL_FIXED(m1->mat22, m2->mat32) + MUL_FIXED(m1->mat32, m2->mat33); |
| | 205 | int mat33 = MUL_FIXED(m1->mat13, m2->mat31) + MUL_FIXED(m1->mat23, m2->mat32) + MUL_FIXED(m1->mat33, m2->mat33); |
| | 206 | |
| | 207 | m3->mat11 = mat11; |
| | 208 | m3->mat12 = mat12; |
| | 209 | m3->mat13 = mat13; |
| | 210 | m3->mat21 = mat21; |
| | 211 | m3->mat22 = mat22; |
| | 212 | m3->mat23 = mat23; |
| | 213 | m3->mat31 = mat31; |
| | 214 | m3->mat32 = mat32; |
| | 215 | m3->mat33 = mat33; |
| | 216 | } |
| | 217 | |
| | 218 | void TransposeMatrixCH(MATRIXCH *m1) |
| | 219 | { |
| | 220 | int temp = m1->mat12; |
| | 221 | |
| | 222 | m1->mat12 = m1->mat21; |
| | 223 | m1->mat21 = temp; |
| | 224 | |
| | 225 | temp = m1->mat13; |
| | 226 | m1->mat13 = m1->mat31; |
| | 227 | m1->mat31 = temp; |
| | 228 | |
| | 229 | temp = m1->mat23; |
| | 230 | m1->mat23 = m1->mat32; |
| | 231 | m1->mat32 = temp; |
| | 232 | } |
| | 233 | |
| | 234 | /* |
| | 235 | Matrix Rotatation of a Vector |
| | 236 | |
| | 237 | Overwrite the Source Vector with the Rotated Vector |
| | 238 | |
| | 239 | x' = v.c1 |
| | 240 | y' = v.c2 |
| | 241 | z' = v.c3 |
| | 242 | */ |
| | 243 | |
| | 244 | void RotateVector(VECTORCH *v, const MATRIXCH* m) |
| | 245 | { |
| | 246 | int x = MUL_FIXED(m->mat11, v->vx) + MUL_FIXED(m->mat21, v->vy) + MUL_FIXED(m->mat31, v->vz); |
| | 247 | int y = MUL_FIXED(m->mat12, v->vx) + MUL_FIXED(m->mat22, v->vy) + MUL_FIXED(m->mat32, v->vz); |
| | 248 | int z = MUL_FIXED(m->mat13, v->vx) + MUL_FIXED(m->mat23, v->vy) + MUL_FIXED(m->mat33, v->vz); |
| | 249 | |
| | 250 | v->vx = x; |
| | 251 | v->vy = y; |
| | 252 | v->vz = z; |
| | 253 | } |
| | 254 | |
| | 255 | /* |
| | 256 | Matrix Rotation of a Source Vector using a Matrix |
| | 257 | Copying to a Destination Vector |
| | 258 | |
| | 259 | x' = v.c1 |
| | 260 | y' = v.c2 |
| | 261 | z' = v.c3 |
| | 262 | */ |
| | 263 | |
| | 264 | void RotateAndCopyVector(const VECTORCH *v1, VECTORCH *v2, const MATRIXCH *m) |
| | 265 | { |
| | 266 | v2->vx = MUL_FIXED(m->mat11, v1->vx) + MUL_FIXED(m->mat21, v1->vy) + MUL_FIXED(m->mat31, v1->vz); |
| | 267 | v2->vy = MUL_FIXED(m->mat12, v1->vx) + MUL_FIXED(m->mat22, v1->vy) + MUL_FIXED(m->mat32, v1->vz); |
| | 268 | v2->vz = MUL_FIXED(m->mat13, v1->vx) + MUL_FIXED(m->mat23, v1->vy) + MUL_FIXED(m->mat33, v1->vz); |
| | 269 | } |
| | 270 | |
| | 271 | /* |
| | 272 | |
| | 273 | Matrix to Euler Angles |
| | 274 | |
| | 275 | Maths overflow is a real problem for this function. To prevent overflows |
| | 276 | the matrix Sines and Cosines are calculated using values scaled down by 4. |
| | 277 | |
| | 278 | |
| | 279 | sinx = -M23 |
| | 280 | |
| | 281 | cosx = sqr ( 1 - sinx^2 ) |
| | 282 | |
| | 283 | |
| | 284 | siny = M13 / cosx |
| | 285 | |
| | 286 | cosy = M33 / cosx |
| | 287 | |
| | 288 | |
| | 289 | sinz = M21 / cosx |
| | 290 | |
| | 291 | cosz = M22 / cosx |
| | 292 | |
| | 293 | |
| | 294 | */ |
| | 295 | |
| | 296 | int SqRoot32(int A) |
| | 297 | { |
| | 298 | return sqrt( (float)A ); |
| | 299 | } |
| | 300 | |
| | 301 | /* This function performs a Widening Multiply followed by a Narrowing Divide. */ |
| | 302 | |
| | 303 | int WideMulNarrowDiv(const int a, const int b, const int c) |
| | 304 | { |
| | 305 | return (int64_t)a * (int64_t)b /c; |
| | 306 | } |
| | 307 | |
| | 308 | #define m2e_scale 2 |
| | 309 | #define ONE_FIXED_S ((ONE_FIXED >> m2e_scale) - 1) |
| | 310 | #define m2e_shift 14 |
| | 311 | |
| | 312 | #define j_and_r_change 1 |
| | 313 | |
| | 314 | void MatrixToEuler(const MATRIXCH *m, EULER *e) |
| | 315 | { |
| | 316 | int x, siny,cosy, abs_cosy; |
| | 317 | |
| | 318 | if(m->mat32 > -65500 && m->mat32 < 65500) |
| | 319 | { |
| | 320 | int abs_cosx, abs_cosz, sinx, cosx, sinz, cosz; |
| | 321 | int CosMatrixPitch, CosMatrixYaw, CosMatrixRoll; |
| | 322 | int SineMatrixPitch, SineMatrixYaw, SineMatrixRoll; |
| | 323 | /* Yaw */ |
| | 324 | /* Pitch */ |
| | 325 | |
| | 326 | #if j_and_r_change |
| | 327 | SineMatrixPitch = -m->mat32; |
| | 328 | #else |
| | 329 | SineMatrixPitch = -m->mat23; |
| | 330 | #endif |
| | 331 | |
| | 332 | SineMatrixPitch >>= m2e_scale; |
| | 333 | |
| | 334 | CosMatrixPitch = SineMatrixPitch * SineMatrixPitch; |
| | 335 | CosMatrixPitch >>= m2e_shift; |
| | 336 | |
| | 337 | CosMatrixPitch = -CosMatrixPitch; |
| | 338 | CosMatrixPitch += ONE_FIXED_S; |
| | 339 | CosMatrixPitch *= ONE_FIXED_S; |
| | 340 | CosMatrixPitch = SqRoot32(CosMatrixPitch); |
| | 341 | |
| | 342 | if(CosMatrixPitch) |
| | 343 | { |
| | 344 | if(CosMatrixPitch > ONE_FIXED_S) |
| | 345 | CosMatrixPitch = ONE_FIXED_S; |
| | 346 | else if(CosMatrixPitch < -ONE_FIXED_S) |
| | 347 | CosMatrixPitch = -ONE_FIXED_S; |
| | 348 | } |
| | 349 | else |
| | 350 | CosMatrixPitch = 1; |
| | 351 | |
| | 352 | SineMatrixYaw = WideMulNarrowDiv( |
| | 353 | #if j_and_r_change |
| | 354 | m->mat31 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 355 | #else |
| | 356 | m->mat13 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 357 | #endif |
| | 358 | |
| | 359 | CosMatrixYaw = WideMulNarrowDiv( m->mat33 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 360 | |
| | 361 | /* Roll */ |
| | 362 | |
| | 363 | SineMatrixRoll = WideMulNarrowDiv( |
| | 364 | #if j_and_r_change |
| | 365 | m->mat12 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 366 | #else |
| | 367 | m->mat21 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 368 | #endif |
| | 369 | |
| | 370 | CosMatrixRoll = WideMulNarrowDiv( m->mat22 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); |
| | 371 | |
| | 372 | /* Tables are for values +- 2^16 */ |
| | 373 | |
| | 374 | sinx = SineMatrixPitch << m2e_scale; |
| | 375 | siny = SineMatrixYaw << m2e_scale; |
| | 376 | sinz = SineMatrixRoll << m2e_scale; |
| | 377 | |
| | 378 | cosx = CosMatrixPitch << m2e_scale; |
| | 379 | cosy = CosMatrixYaw << m2e_scale; |
| | 380 | cosz = CosMatrixRoll << m2e_scale; |
| | 381 | |
| | 382 | /* Absolute Cosines */ |
| | 383 | |
| | 384 | abs_cosx = abs(cosx); |
| | 385 | abs_cosy = abs(cosy); |
| | 386 | abs_cosz = abs(cosz); |
| | 387 | |
| | 388 | /* Euler X */ |
| | 389 | |
| | 390 | if(abs_cosx > Cosine45) |
| | 391 | { |
| | 392 | x = ArcSin(sinx); |
| | 393 | |
| | 394 | if(cosx < 0) |
| | 395 | { |
| | 396 | x = -x; |
| | 397 | x += deg180; |
| | 398 | x &= wrap360; |
| | 399 | } |
| | 400 | } |
| | 401 | else |
| | 402 | { |
| | 403 | x = ArcCos(cosx); |
| | 404 | |
| | 405 | if(sinx < 0) |
| | 406 | { |
| | 407 | x = -x; |
| | 408 | x &= wrap360; |
| | 409 | } |
| | 410 | } |
| | 411 | |
| | 412 | #if ( 0 == j_and_r_change ) |
| | 413 | x = -x; |
| | 414 | x &= wrap360; |
| | 415 | #endif |
| | 416 | |
| | 417 | e->EulerX = x; |
| | 418 | |
| | 419 | /* Euler Y */ |
| | 420 | |
| | 421 | if(abs_cosy > Cosine45) |
| | 422 | { |
| | 423 | x = ArcSin(siny); |
| | 424 | |
| | 425 | if(cosy < 0) |
| | 426 | { |
| | 427 | x = -x; |
| | 428 | x += deg180; |
| | 429 | x &= wrap360; |
| | 430 | } |
| | 431 | } |
| | 432 | else |
| | 433 | { |
| | 434 | x = ArcCos(cosy); |
| | 435 | |
| | 436 | if(siny < 0) |
| | 437 | { |
| | 438 | x = -x; |
| | 439 | x &= wrap360; |
| | 440 | } |
| | 441 | } |
| | 442 | |
| | 443 | #if ( 0 == j_and_r_change ) |
| | 444 | x = -x; |
| | 445 | x &= wrap360; |
| | 446 | #endif |
| | 447 | |
| | 448 | e->EulerY = x; |
| | 449 | |
| | 450 | /* Euler Z */ |
| | 451 | |
| | 452 | if(abs_cosz > Cosine45) |
| | 453 | { |
| | 454 | x = ArcSin(sinz); |
| | 455 | |
| | 456 | if(cosz < 0) |
| | 457 | { |
| | 458 | x = -x; |
| | 459 | x += deg180; |
| | 460 | x &= wrap360; |
| | 461 | } |
| | 462 | } |
| | 463 | else |
| | 464 | { |
| | 465 | x = ArcCos(cosz); |
| | 466 | |
| | 467 | if(sinz < 0) |
| | 468 | { |
| | 469 | x = -x; |
| | 470 | x &= wrap360; |
| | 471 | } |
| | 472 | } |
| | 473 | |
| | 474 | #if ( 0 == j_and_r_change ) |
| | 475 | x = -x; |
| | 476 | x &= wrap360; |
| | 477 | #endif |
| | 478 | |
| | 479 | e->EulerZ = x; |
| | 480 | } |
| | 481 | else //singularity case |
| | 482 | { |
| | 483 | e->EulerX = (m->mat32 > 0) ? 3072 : 1024; |
| | 484 | e->EulerZ = 0; |
| | 485 | |
| | 486 | /* Yaw */ |
| | 487 | |
| | 488 | siny = -m->mat13 ; |
| | 489 | cosy = m->mat11 ; |
| | 490 | |
| | 491 | abs_cosy = abs(cosy); |
| | 492 | |
| | 493 | if(abs_cosy > Cosine45) |
| | 494 | { |
| | 495 | x = ArcSin(siny); |
| | 496 | |
| | 497 | if(cosy < 0) |
| | 498 | { |
| | 499 | x = -x; |
| | 500 | x += deg180; |
| | 501 | x &= wrap360; |
| | 502 | } |
| | 503 | } |
| | 504 | else |
| | 505 | { |
| | 506 | x = ArcCos(cosy); |
| | 507 | |
| | 508 | if(siny < 0) |
| | 509 | { |
| | 510 | x = -x; |
| | 511 | x &= wrap360; |
| | 512 | } |
| | 513 | } |
| | 514 | |
| | 515 | #if ( 0 == j_and_r_change ) |
| | 516 | x = -x; |
| | 517 | x &= wrap360; |
| | 518 | #endif |
| | 519 | |
| | 520 | e->EulerY = x; |
| | 521 | } |
| | 522 | } |
| | 523 | |
| | 524 | /* |
| | 525 | Normalise a Matrix |
| | 526 | |
| | 527 | Dot the three vectors together (XY, XZ, YZ) and take the two nearest to |
| | 528 | 90Å™ from each other. Cross them to create a new third vector, then cross |
| | 529 | the first and third to create a new second. |
| | 530 | */ |
| | 531 | |
| | 532 | void MNormalise(MATRIXCH *m) |
| | 533 | { |
| | 534 | VECTORCH *x = (VECTORCH *) &m->mat11; |
| | 535 | VECTORCH *y = (VECTORCH *) &m->mat21; |
| | 536 | VECTORCH *z = (VECTORCH *) &m->mat31; |
| | 537 | int dotxy = DotProduct(x, y); |
| | 538 | int dotxz = DotProduct(x, z); |
| | 539 | int dotyz = DotProduct(y, z); |
| | 540 | VECTORCH *s; |
| | 541 | VECTORCH *t; |
| | 542 | VECTORCH u; |
| | 543 | VECTORCH v; |
| | 544 | VECTORCH zero = {0, 0, 0}; |
| | 545 | |
| | 546 | /* Find the two vectors nearest 90Å™ */ |
| | 547 | |
| | 548 | if(dotxy > dotxz && dotxy > dotyz) |
| | 549 | { |
| | 550 | /* xy are the closest to 90Å™ */ |
| | 551 | |
| | 552 | /*printf("xy\n");*/ |
| | 553 | |
| | 554 | s = x; |
| | 555 | t = y; |
| | 556 | |
| | 557 | MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ |
| | 558 | |
| | 559 | MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ |
| | 560 | v.vx = -v.vx; |
| | 561 | v.vy = -v.vy; |
| | 562 | v.vz = -v.vz; |
| | 563 | |
| | 564 | *z = u; |
| | 565 | *y = v; |
| | 566 | } |
| | 567 | else if(dotxz > dotxy && dotxz > dotyz) |
| | 568 | { |
| | 569 | /* xz are the closest to 90Å™ */ |
| | 570 | |
| | 571 | /*printf("xz\n");*/ |
| | 572 | |
| | 573 | s = x; |
| | 574 | t = z; |
| | 575 | |
| | 576 | MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ |
| | 577 | u.vx = -u.vx; |
| | 578 | u.vy = -u.vy; |
| | 579 | u.vz = -u.vz; |
| | 580 | |
| | 581 | MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ |
| | 582 | |
| | 583 | *y = u; |
| | 584 | *z = v; |
| | 585 | } |
| | 586 | else |
| | 587 | { |
| | 588 | /* yz are the closest to 90Å™ */ |
| | 589 | |
| | 590 | /*printf("yz\n");*/ |
| | 591 | |
| | 592 | s = y; |
| | 593 | t = z; |
| | 594 | |
| | 595 | MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ |
| | 596 | |
| | 597 | MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ |
| | 598 | v.vx = -v.vx; |
| | 599 | v.vy = -v.vy; |
| | 600 | v.vz = -v.vz; |
| | 601 | |
| | 602 | *x = u; |
| | 603 | *z = v; |
| | 604 | } |
| | 605 | } |
| | 606 | |
| | 607 | /* |
| | 608 | |
| | 609 | ArcCos |
| | 610 | |
| | 611 | In: COS value as -65,536 -> +65,536. |
| | 612 | Out: Angle in 0 -> 4095 form. |
| | 613 | |
| | 614 | Notes: |
| | 615 | |
| | 616 | The angle returned is in the range 0 -> 2,047 since the sign of SIN |
| | 617 | is not known. |
| | 618 | |
| | 619 | ArcSin(x) = ArcTan ( x, sqr ( 1-x*x ) ) |
| | 620 | ArcCos(x) = ArcTan ( sqr ( 1-x*x ), x) |
| | 621 | |
| | 622 | -65,536 = 180 Degrees |
| | 623 | 0 = 90 Degrees |
| | 624 | +65,536 = 0 Degrees |
| | 625 | |
| | 626 | The table has 4,096 entries. |
| | 627 | |
| | 628 | */ |
| | 629 | |
| | 630 | int ArcCos(int c) |
| | 631 | { |
| | 632 | if(c < (-(ONE_FIXED - 1))) |
| | 633 | c = -(ONE_FIXED - 1); |
| | 634 | else if(c > (ONE_FIXED - 1)) |
| | 635 | c = ONE_FIXED - 1; |
| | 636 | |
| | 637 | int16_t acos = ArcCosTable[(c >> 5) + 2048]; |
| | 638 | |
| | 639 | return (acos & wrap360); |
| | 640 | } |
| | 641 | |
| | 642 | /* |
| | 643 | |
| | 644 | ArcSin |
| | 645 | |
| | 646 | In: SIN value in ax as -65,536 -> +65,536. |
| | 647 | Out: Angle in 0 -> 4095 form in ax. |
| | 648 | |
| | 649 | Notes: |
| | 650 | |
| | 651 | The angle returned is in the range -1,024 -> 1,023 since the sign of COS |
| | 652 | is not known. |
| | 653 | |
| | 654 | ArcSin(x) = ArcTan ( x, sqr ( 1-x*x ) ) |
| | 655 | ArcCos(x) = ArcTan ( sqr ( 1-x*x ), x) |
| | 656 | |
| | 657 | -65,536 = 270 Degrees |
| | 658 | 0 = 0 Degrees |
| | 659 | +65,536 = 90 Degrees |
| | 660 | |
| | 661 | The table has 4,096 entries. |
| | 662 | |
| | 663 | */ |
| | 664 | |
| | 665 | int ArcSin(int s) |
| | 666 | { |
| | 667 | if(s < (-(ONE_FIXED - 1))) |
| | 668 | s = -(ONE_FIXED - 1); |
| | 669 | else if(s > (ONE_FIXED - 1)) |
| | 670 | s = ONE_FIXED - 1; |
| | 671 | |
| | 672 | int16_t asin = ArcSineTable[(s >> 5) + 2048]; |
| | 673 | |
| | 674 | return (asin & wrap360); |
| | 675 | } |
| | 676 | |
| | 677 | |
| | 678 | /* |
| | 679 | |
| | 680 | ArcTan |
| | 681 | |
| | 682 | Pass (x,z) |
| | 683 | |
| | 684 | And ATN(x/z) is returned such that: |
| | 685 | |
| | 686 | 000Å™ is Map North |
| | 687 | 090Å™ is Map East |
| | 688 | 180Å™ is Map South |
| | 689 | 270Å™ is Map West |
| | 690 | |
| | 691 | */ |
| | 692 | |
| | 693 | int ArcTan(int height_x, int width_z) |
| | 694 | { |
| | 695 | int abs_height_x, abs_width_z, angle, signsame = 0; |
| | 696 | |
| | 697 | int sign = 0; |
| | 698 | |
| | 699 | if((height_x < 0 && width_z < 0) || (height_x >=0 && width_z >= 0)) |
| | 700 | signsame = 1; |
| | 701 | |
| | 702 | abs_height_x = abs(height_x); |
| | 703 | abs_width_z = abs(width_z); |
| | 704 | |
| | 705 | if(!width_z) |
| | 706 | angle = -deg90; |
| | 707 | else if(abs_width_z == abs_height_x) |
| | 708 | angle = deg45; |
| | 709 | else |
| | 710 | { |
| | 711 | if(abs_width_z > abs_height_x) |
| | 712 | { |
| | 713 | int temp = abs_width_z; |
| | 714 | abs_width_z = abs_height_x; |
| | 715 | abs_height_x = temp; |
| | 716 | sign = -1; |
| | 717 | } |
| | 718 | |
| | 719 | if(abs_height_x != 0) |
| | 720 | angle = (abs_width_z << 8)/ abs_height_x; |
| | 721 | else |
| | 722 | angle = deg22pt5; |
| | 723 | |
| | 724 | angle = ArcTanTable[angle]; |
| | 725 | |
| | 726 | if(sign >= 0) |
| | 727 | { |
| | 728 | angle = -angle; |
| | 729 | angle += deg90; |
| | 730 | } |
| | 731 | } |
| | 732 | |
| | 733 | if(!signsame) |
| | 734 | angle = -angle; |
| | 735 | |
| | 736 | if(width_z <= 0) |
| | 737 | angle += deg180; |
| | 738 | |
| | 739 | angle &= wrap360; |
| | 740 | |
| | 741 | return angle; |
| | 742 | } |
| | 743 | |
| | 744 | static int CMP_LL(int64_t *a, int64_t *b) |
| | 745 | { |
| | 746 | return (a < b) ? -1 : (a > b); |
| | 747 | } |
| | 748 | |
| | 749 | /* |
| | 750 | |
| | 751 | "Yes" if "point" is inside "polygon" |
| | 752 | |
| | 753 | ************************************************** |
| | 754 | |
| | 755 | WARNING!! Point and Polygon Data are OVERWRITTEN!! |
| | 756 | |
| | 757 | ************************************************** |
| | 758 | |
| | 759 | The function requires point to be an integer array containing a single |
| | 760 | XY pair. The number of points must be passed too. |
| | 761 | |
| | 762 | Pass the size of the polygon point e.g. A Gouraud polygon has points X,Y,I |
| | 763 | so its point size would be 3. |
| | 764 | |
| | 765 | |
| | 766 | Item Polygon Point Size |
| | 767 | ---- ------------------ |
| | 768 | |
| | 769 | I_Polygon 2 |
| | 770 | I_GouraudPolygon 3 |
| | 771 | I_2dTexturedPolygon 4 |
| | 772 | I_3dTexturedPolygon, 5 |
| | 773 | I_Gouraud2dTexturedPolygon 5 |
| | 774 | I_Polygon_ZBuffer 3 |
| | 775 | I_GouraudPolygon_ZBuffer 4 |
| | 776 | |
| | 777 | |
| | 778 | PASS ONLY POSITIVE COORDINATES! |
| | 779 | |
| | 780 | */ |
| | 781 | |
| | 782 | int PointInPolygon(int* point, int* polygon, int c, int ppsize) |
| | 783 | { |
| | 784 | /* Tim's New Point In Polygon test-- hopefully much faster, */ |
| | 785 | /* certainly much smaller. */ |
| | 786 | /* Uses Half-Line test for point-in-2D-polygon test */ |
| | 787 | /* Tests the half-line going from the point in the direction of positive z */ |
| | 788 | |
| | 789 | int x, z; /* point */ |
| | 790 | int sx, sz; /* vertex 1 */ |
| | 791 | int *polyp; /* vertex 2 pointer */ |
| | 792 | int t; |
| | 793 | int dx = 0; /* ABS(vertex 2 - vertex 1) */ |
| | 794 | int sgnx; /* going left or going right */ |
| | 795 | int intersects = 0; /* number of intersections so far discovered */ |
| | 796 | |
| | 797 | /* reject lines and points */ |
| | 798 | if (c < 3) |
| | 799 | return 0; |
| | 800 | |
| | 801 | x = point[ix]; |
| | 802 | z = point[iy]; /* ! */ |
| | 803 | |
| | 804 | /* get last point */ |
| | 805 | polyp = polygon + ((c - 1) * ppsize); |
| | 806 | sx = polyp[0]; |
| | 807 | sz = polyp[1]; |
| | 808 | |
| | 809 | /* go back to first point */ |
| | 810 | polyp = polygon; |
| | 811 | |
| | 812 | /* for each point */ |
| | 813 | while (0 != c) |
| | 814 | { |
| | 815 | |
| | 816 | /* is this line straddling the x co-ordinate of the point? */ |
| | 817 | /* if not it is not worth testing for intersection with the half-line */ |
| | 818 | /* we must be careful to get the strict and non-stict inequalities */ |
| | 819 | /* correct, or we may count intersections with vertices the wrong number */ |
| | 820 | /* of times. */ |
| | 821 | sgnx = 0; |
| | 822 | |
| | 823 | if (sx < x && x <= polyp[0]) |
| | 824 | { |
| | 825 | /* going right */ |
| | 826 | sgnx = 1; |
| | 827 | dx = polyp[0] - sx; |
| | 828 | } |
| | 829 | |
| | 830 | if (polyp[0] < x && x <= sx) |
| | 831 | { |
| | 832 | /* going left */ |
| | 833 | sgnx = -1; |
| | 834 | dx = sx - polyp[0]; |
| | 835 | } |
| | 836 | |
| | 837 | /* if sgnx is zero then neither of the above conditions are true, */ |
| | 838 | /* hence the line does not straddle the point in x */ |
| | 839 | |
| | 840 | if (0 != sgnx) |
| | 841 | { |
| | 842 | /* next do trivial cases of line totally above or below point */ |
| | 843 | if (z < sz && z < polyp[1]) |
| | 844 | { |
| | 845 | /* line totally above point -- intersection */ |
| | 846 | intersects++; |
| | 847 | } |
| | 848 | else if (z <= sz || z <= polyp[1]) |
| | 849 | { |
| | 850 | /* line straddles point in both x and z -- we must do interpolation */ |
| | 851 | |
| | 852 | /* get absolute differences between line end z co-ordinates */ |
| | 853 | int dz = (sz < polyp[1]) ? (polyp[1] - sz) : (sz - polyp[1]); |
| | 854 | |
| | 855 | /* B504 is the square root of 7FFFFFFF */ |
| | 856 | if (0xB504L < dx || 0xB504L < dz) |
| | 857 | { |
| | 858 | /* LARGE line -- use 64-bit values */ |
| | 859 | /* interpolate z */ |
| | 860 | |
| | 861 | int64_t a_ll = (polyp[1] - sz) * (x - sx); |
| | 862 | int64_t b_ll = (polyp[0] - sx) * (z - sz); |
| | 863 | |
| | 864 | if(CMP_LL(&a_ll, &b_ll) == sgnx) |
| | 865 | intersects++; |
| | 866 | } |
| | 867 | else |
| | 868 | { |
| | 869 | /* small line -- use 32-bit values */ |
| | 870 | /* interpolate z */ |
| | 871 | |
| | 872 | t = (polyp[1] - sz) * (x - sx) - (polyp[0] - sx) * (z - sz); |
| | 873 | |
| | 874 | if ((t < 0 && sgnx < 0) || (0 < t && 0 < sgnx)) |
| | 875 | intersects++; |
| | 876 | |
| | 877 | } |
| | 878 | } /* (if line straddles point in z) */ |
| | 879 | } /* (if line straddles point in x) */ |
| | 880 | |
| | 881 | /* get next line : */ |
| | 882 | /* new vertex 1 is old vertex 2 */ |
| | 883 | sx = polyp[0]; |
| | 884 | sz = polyp[1]; |
| | 885 | |
| | 886 | /* new vertex 2 is next point */ |
| | 887 | polyp += ppsize; |
| | 888 | |
| | 889 | /* next vertex */ |
| | 890 | c--; |
| | 891 | } |
| | 892 | |
| | 893 | // return 1, Odd number of intersections -- point is inside polygon |
| | 894 | // return 0, even number of intersections -- point is outside polygon |
| | 895 | return (intersects & 1); |
| | 896 | } |
| | 897 | |
| | 898 | /* |
| | 899 | #defines and statics required for Jamie's Most Excellent |
| | 900 | random number generator |
| | 901 | */ |
| | 902 | |
| | 903 | #define DEG_3 31 |
| | 904 | #define SEP_3 3 |
| | 905 | |
| | 906 | static int32_t table [DEG_3] = |
| | 907 | { |
| | 908 | -851904987, -43806228, -2029755270, 1390239686, -1912102820, |
| | 909 | -485608943, 1969813258, -1590463333, -1944053249, 455935928, |
| | 910 | 508023712, -1714531963, 1800685987, -2015299881, 654595283, |
| | 911 | -1149023258, -1470005550, -1143256056, -1325577603, -1568001885, |
| | 912 | 1275120390, -607508183, -205999574, -1696891592, 1492211999, |
| | 913 | -1528267240, -952028296, -189082757, 362343714, 1424981831, |
| | 914 | 2039449641 |
| | 915 | }; |
| | 916 | |
| | 917 | #define TABLE_END (table + sizeof (table) / sizeof (table [0])) |
| | 918 | |
| | 919 | static int32_t * front_ptr = table + SEP_3; |
| | 920 | static int32_t * rear_ptr = table; |
| | 921 | |
| | 922 | #define SEEDED_DEG_3 13 |
| | 923 | #define SEEDED_SEP_3 3 |
| | 924 | static int32_t seeded_table [SEEDED_DEG_3]; |
| | 925 | static int32_t * seeded_front_ptr = seeded_table + SEEDED_SEP_3; |
| | 926 | static int32_t * seeded_rear_ptr = seeded_table; |
| | 927 | |
| | 928 | /*a second copy of the random number generator for getting random numbers from a single seed*/ |
| | 929 | |
| | 930 | #define SEEDED_TABLE_END (seeded_table + sizeof (seeded_table) / sizeof (seeded_table [0])) |
| | 931 | |
| | 932 | int SeededFastRandom() |
| | 933 | { |
| | 934 | /* |
| | 935 | Discard least random bit. |
| | 936 | Shift as unsigned to avoid replicating sign bit. |
| | 937 | Faster than masking. |
| | 938 | */ |
| | 939 | |
| | 940 | *seeded_front_ptr += *seeded_rear_ptr; |
| | 941 | int32_t i = (int32_t) ((uint32_t) *seeded_front_ptr >> 1); |
| | 942 | |
| | 943 | /* `front_ptr' and `rear_ptr' can't wrap at the same time. */ |
| | 944 | |
| | 945 | ++seeded_front_ptr; |
| | 946 | |
| | 947 | if(seeded_front_ptr < SEEDED_TABLE_END) |
| | 948 | { |
| | 949 | ++seeded_rear_ptr; |
| | 950 | |
| | 951 | if (seeded_rear_ptr < SEEDED_TABLE_END) |
| | 952 | return i; |
| | 953 | |
| | 954 | seeded_rear_ptr = seeded_table; |
| | 955 | } |
| | 956 | else |
| | 957 | { |
| | 958 | /* front_ptr >= TABLE_END */ |
| | 959 | |
| | 960 | seeded_front_ptr = seeded_table; |
| | 961 | ++seeded_rear_ptr; |
| | 962 | } |
| | 963 | |
| | 964 | return i; |
| | 965 | } |
| | 966 | |
| | 967 | void SetSeededFastRandom(int seed) |
| | 968 | { |
| | 969 | int i = 0; |
| | 970 | int32_t number = seed; |
| | 971 | |
| | 972 | for(; i < SEEDED_DEG_3; ++i) |
| | 973 | { |
| | 974 | number = 1103515145 * number + 12345; |
| | 975 | seeded_table[i] = number; |
| | 976 | } |
| | 977 | |
| | 978 | seeded_front_ptr = seeded_table + SEEDED_SEP_3; |
| | 979 | seeded_rear_ptr = seeded_table; |
| | 980 | |
| | 981 | for(i = 0; i < 2 * SEEDED_DEG_3; ++i) |
| | 982 | SeededFastRandom (); |
| | 983 | } |
| | 984 | |
| | 985 | static struct timeval starttime; |
| | 986 | |
| | 987 | void InitTimer() |
| | 988 | { |
| | 989 | gettimeofday(&starttime, NULL); |
| | 990 | } |
| | 991 | |
| | 992 | /* time in miliseconds */ |
| | 993 | unsigned int timeGetTime() |
| | 994 | { |
| | 995 | static struct timeval tv1; |
| | 996 | |
| | 997 | gettimeofday(&tv1, NULL); |
| | 998 | |
| | 999 | int secs = tv1.tv_sec - starttime.tv_sec; |
| | 1000 | int usecs = tv1.tv_usec - starttime.tv_usec; |
| | 1001 | |
| | 1002 | if (usecs < 0) |
| | 1003 | { |
| | 1004 | usecs += 1000000; |
| | 1005 | secs--; |
| | 1006 | } |
| | 1007 | |
| | 1008 | return secs * 1000 + (usecs / 1000); |
| | 1009 | } |
| | 1010 | |
| | 1011 | void SetFastRandom() |
| | 1012 | { |
| | 1013 | int i = 0; |
| | 1014 | unsigned int number = timeGetTime(); |
| | 1015 | |
| | 1016 | for(; i < DEG_3; ++i) |
| | 1017 | { |
| | 1018 | number = 1103515145 * number + 12345; |
| | 1019 | table[i] = number; |
| | 1020 | } |
| | 1021 | |
| | 1022 | front_ptr = table + SEP_3; |
| | 1023 | rear_ptr = table; |
| | 1024 | |
| | 1025 | for(i = 0; i < 10 * DEG_3; ++i) |
| | 1026 | FastRandom(); |
| | 1027 | |
| | 1028 | SetSeededFastRandom(FastRandom()); |
| | 1029 | } |
| | 1030 | |
| | 1031 | int FastRandom() |
| | 1032 | { |
| | 1033 | /* |
| | 1034 | Discard least random bit. |
| | 1035 | Shift as unsigned to avoid replicating sign bit. |
| | 1036 | Faster than masking. |
| | 1037 | */ |
| | 1038 | |
| | 1039 | *front_ptr += *rear_ptr; |
| | 1040 | int32_t i = (int32_t) ((uint32_t) *front_ptr >> 1); |
| | 1041 | |
| | 1042 | /* `front_ptr' and `rear_ptr' can't wrap at the same time. */ |
| | 1043 | |
| | 1044 | ++front_ptr; |
| | 1045 | |
| | 1046 | if(front_ptr < TABLE_END) |
| | 1047 | { |
| | 1048 | ++rear_ptr; |
| | 1049 | |
| | 1050 | if (rear_ptr < TABLE_END) |
| | 1051 | return i; |
| | 1052 | |
| | 1053 | rear_ptr = table; |
| | 1054 | } |
| | 1055 | else |
| | 1056 | { |
| | 1057 | /* front_ptr >= TABLE_END */ |
| | 1058 | front_ptr = table; |
| | 1059 | ++rear_ptr; |
| | 1060 | } |
| | 1061 | |
| | 1062 | return i; |
| | 1063 | } |
| | 1064 | |
| | 1065 | int MagnitudeOfCrossProduct(const VECTORCH *a, const VECTORCH *b) |
| | 1066 | { |
| | 1067 | float x = MUL_FIXED(a->vy, b->vz) - MUL_FIXED(a->vz, b->vy); |
| | 1068 | float y = MUL_FIXED(a->vz, b->vx) - MUL_FIXED(a->vx, b->vz); |
| | 1069 | float z = MUL_FIXED(a->vx, b->vy) - MUL_FIXED(a->vy, b->vx); |
| | 1070 | |
| | 1071 | return sqrt((x * x) + (y * y) + (z * z)); |
| | 1072 | } |
| | 1073 | |
| | 1074 | void CrossProduct(const VECTORCH *a, const VECTORCH *b, VECTORCH *c) |
| | 1075 | { |
| | 1076 | c->vx = MUL_FIXED(a->vy, b->vz) - MUL_FIXED(a->vz, b->vy); |
| | 1077 | c->vy = MUL_FIXED(a->vz, b->vx) - MUL_FIXED(a->vx, b->vz); |
| | 1078 | c->vz = MUL_FIXED(a->vx, b->vy) - MUL_FIXED(a->vy, b->vx); |
| | 1079 | } |
| | 1080 | |
| | 1081 | /* |
| | 1082 | KJL 12:01:08 7/16/97 - returns the magnitude of a vector - max error about 13%, though average error |
| | 1083 | less than half this. Very fast compared to other approaches. |
| | 1084 | */ |
| | 1085 | |
| | 1086 | int Approximate3dMagnitude(const VECTORCH *v) |
| | 1087 | { |
| | 1088 | int dx = abs(v->vx); |
| | 1089 | int dy = abs(v->vy); |
| | 1090 | int dz = abs(v->vz); |
| | 1091 | |
| | 1092 | if (dx > dy) |
| | 1093 | { |
| | 1094 | if (dx > dz) |
| | 1095 | return dx + ((dy + dz) >> 2); |
| | 1096 | else |
| | 1097 | return dz + ((dy + dx) >> 2); |
| | 1098 | } |
| | 1099 | else |
| | 1100 | { |
| | 1101 | if (dy > dz) |
| | 1102 | return dy + ((dx + dz) >> 2); |
| | 1103 | else |
| | 1104 | return dz + ((dx + dy) >> 2); |
| | 1105 | } |
| | 1106 | } |
| | 1107 | |
| | 1108 | /* |
| | 1109 | |
| | 1110 | Quaternion to Matrix |
| | 1111 | |
| | 1112 | This is the column(row) matrix that is produced. Our matrices are |
| | 1113 | row(column) and so are a transpose of this. |
| | 1114 | |
| | 1115 | 1 - 2yy - 2zz 2xy + 2wz 2xz - 2wy |
| | 1116 | |
| | 1117 | 2xy - 2wz 1 - 2xx - 2zz 2yz + 2wx |
| | 1118 | |
| | 1119 | 2xz + 2wy 2yz - 2wx 1 - 2xx - 2yy |
| | 1120 | |
| | 1121 | */ |
| | 1122 | |
| | 1123 | void QuatToMat(QUAT *q,MATRIXCH *m) |
| | 1124 | { |
| | 1125 | /* |
| | 1126 | The most efficient way to create the matrix is as follows 1 / Double x, y & z |
| | 1127 | */ |
| | 1128 | int q_w = q->quatw; |
| | 1129 | int q_x = q->quatx; |
| | 1130 | int q_y = q->quaty; |
| | 1131 | int q_z = q->quatz; |
| | 1132 | |
| | 1133 | int q_2x = q_x * 2; |
| | 1134 | int q_2y = q_y * 2; |
| | 1135 | int q_2z = q_z * 2; |
| | 1136 | |
| | 1137 | /* |
| | 1138 | 2/ Form their products with w, x, y & z |
| | 1139 | These are |
| | 1140 | |
| | 1141 | (2x)w (2y)w (2z)w |
| | 1142 | (2x)x |
| | 1143 | (2x)y (2y)y |
| | 1144 | (2x)z (2y)z (2z)z |
| | 1145 | */ |
| | 1146 | int q_2xw = MUL_FIXED(q_2x, q_w); |
| | 1147 | int q_2yw = MUL_FIXED(q_2y, q_w); |
| | 1148 | int q_2zw = MUL_FIXED(q_2z, q_w); |
| | 1149 | |
| | 1150 | int q_2xx = MUL_FIXED(q_2x, q_x); |
| | 1151 | |
| | 1152 | int q_2xy = MUL_FIXED(q_2x, q_y); |
| | 1153 | int q_2yy = MUL_FIXED(q_2y, q_y); |
| | 1154 | |
| | 1155 | int q_2xz = MUL_FIXED(q_2x, q_z); |
| | 1156 | int q_2yz = MUL_FIXED(q_2y, q_z); |
| | 1157 | int q_2zz = MUL_FIXED(q_2z, q_z); |
| | 1158 | |
| | 1159 | /* mat11 = 1 - 2y^2 - 2z^2 */ |
| | 1160 | |
| | 1161 | m->mat11 = ONE_FIXED - q_2yy - q_2zz; |
| | 1162 | |
| | 1163 | /* mat12 = 2xy - 2wz */ |
| | 1164 | |
| | 1165 | m->mat12 = q_2xy - q_2zw; |
| | 1166 | |
| | 1167 | /* mat13 = 2xz + 2wy */ |
| | 1168 | |
| | 1169 | m->mat13 = q_2xz + q_2yw; |
| | 1170 | |
| | 1171 | /* mat21 = 2xy + 2wz */ |
| | 1172 | |
| | 1173 | m->mat21 = q_2xy + q_2zw; |
| | 1174 | |
| | 1175 | /* mat22 = 1 - 2x^2 - 2z^2 */ |
| | 1176 | |
| | 1177 | m->mat22 = ONE_FIXED - q_2xx - q_2zz; |
| | 1178 | |
| | 1179 | /* mat23 = 2yz - 2wx */ |
| | 1180 | |
| | 1181 | m->mat23 = q_2yz - q_2xw; |
| | 1182 | |
| | 1183 | /* mat31 = 2xz - 2wy */ |
| | 1184 | |
| | 1185 | m->mat31 = q_2xz - q_2yw; |
| | 1186 | |
| | 1187 | /* mat32 = 2yz + 2wx */ |
| | 1188 | |
| | 1189 | m->mat32 = q_2yz + q_2xw; |
| | 1190 | |
| | 1191 | /* mat33 = 1 - 2x^2 - 2y^2 */ |
| | 1192 | |
| | 1193 | m->mat33 = ONE_FIXED - q_2xx - q_2yy; |
| | 1194 | } |
| | 1195 | |
| | 1196 | /* |
| | 1197 | Calculate Plane Normal from three POP's |
| | 1198 | |
| | 1199 | The three input vectors are treated as POP's and used to make two vectors. |
| | 1200 | These are then crossed to create the normal. |
| | 1201 | |
| | 1202 | Make two vectors; (2-1) & (3-1) |
| | 1203 | Cross them |
| | 1204 | Normalise the vector |
| | 1205 | Find the magnitude of the vector |
| | 1206 | Divide each component by the magnitude |
| | 1207 | */ |
| | 1208 | |
| | 1209 | void MakeNormal(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3, VECTORCH *v4) |
| | 1210 | { |
| | 1211 | float vect0_x = v2->vx - v1->vx; |
| | 1212 | float vect0_y = v2->vy - v1->vy; |
| | 1213 | float vect0_z = v2->vz - v1->vz; |
| | 1214 | |
| | 1215 | float vect1_x = v3->vx - v1->vx; |
| | 1216 | float vect1_y = v3->vy - v1->vy; |
| | 1217 | float vect1_z = v3->vz - v1->vz; |
| | 1218 | |
| | 1219 | /* x = v0y.v1z - v0z.v1y */ |
| | 1220 | |
| | 1221 | float x = (vect0_y * vect1_z) - (vect0_z * vect1_y); |
| | 1222 | |
| | 1223 | /* y = v0z.v1x - v0x.v1z */ |
| | 1224 | |
| | 1225 | float y = (vect0_z * vect1_x) - (vect0_x * vect1_z); |
| | 1226 | |
| | 1227 | /* z = v0x.v1y - v0y.v1x */ |
| | 1228 | |
| | 1229 | float z = (vect0_x * vect1_y) - (vect0_y * vect1_x); |
| | 1230 | |
| | 1231 | { |
| | 1232 | float m = sqrt((x * x) + (y * y) + (z * z)); |
| | 1233 | |
| | 1234 | x /= m; |
| | 1235 | y /= m; |
| | 1236 | z /= m; |
| | 1237 | } |
| | 1238 | |
| | 1239 | v4->vx = (int)(x * ONE_FIXED); |
| | 1240 | v4->vy = (int)(y * ONE_FIXED); |
| | 1241 | v4->vz = (int)(z * ONE_FIXED); |
| | 1242 | } |
| | 1243 | |
| | 1244 | /* |
| | 1245 | |
| | 1246 | Normalise a vector. |
| | 1247 | |
| | 1248 | The returned vector is a fixed point unit vector. |
| | 1249 | |
| | 1250 | WARNING! |
| | 1251 | |
| | 1252 | The vector must be no larger than 2<<14 because of the square root. |
| | 1253 | Because this is an integer function, small components produce errors. |
| | 1254 | |
| | 1255 | e.g. |
| | 1256 | |
| | 1257 | (100,100,0) |
| | 1258 | |
| | 1259 | m=141 (141.42) |
| | 1260 | |
| | 1261 | nx = 100 * ONE_FIXED / m = 46,479 |
| | 1262 | ny = 100 * ONE_FIXED / m = 46,479 |
| | 1263 | nz = 0 |
| | 1264 | |
| | 1265 | New m ought to be 65,536 but in fact is 65,731 i.e. 0.29% too large. |
| | 1266 | |
| | 1267 | */ |
| | 1268 | |
| | 1269 | void Normalise(VECTORCH *nvector) |
| | 1270 | { |
| | 1271 | float x = nvector->vx; |
| | 1272 | float y = nvector->vy; |
| | 1273 | float z = nvector->vz; |
| | 1274 | |
| | 1275 | float m = 65536.0/sqrt((x * x) + (y * y) + (z * z)); |
| | 1276 | |
| | 1277 | nvector->vx = (int)(x * m); |
| | 1278 | nvector->vy = (int)(y * m); |
| | 1279 | nvector->vz = (int)(z * m); |
| | 1280 | } |