Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | /* |
| 2 | * Portions of this file are copyright Rebirth contributors and licensed as |
||
| 3 | * described in COPYING.txt. |
||
| 4 | * Portions of this file are copyright Parallax Software and licensed |
||
| 5 | * according to the Parallax license below. |
||
| 6 | * See COPYING.txt for license details. |
||
| 7 | |||
| 8 | THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX |
||
| 9 | SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO |
||
| 10 | END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A |
||
| 11 | ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS |
||
| 12 | IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS |
||
| 13 | SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE |
||
| 14 | FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE |
||
| 15 | CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS |
||
| 16 | AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. |
||
| 17 | COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. |
||
| 18 | */ |
||
| 19 | |||
| 20 | /* |
||
| 21 | * |
||
| 22 | * Header file for vector/matrix library |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #pragma once |
||
| 27 | |||
| 28 | #ifdef __cplusplus |
||
| 29 | #include <cassert> |
||
| 30 | #include <cstdint> |
||
| 31 | #include <utility> |
||
| 32 | #include "fwd-vecmat.h" |
||
| 33 | |||
| 34 | namespace dcx { |
||
| 35 | |||
| 36 | //The basic fixed-point vector. Access elements by name or position |
||
| 37 | struct vms_vector |
||
| 38 | { |
||
| 39 | fix x, y, z; |
||
| 40 | }; |
||
| 41 | |||
| 42 | class vm_distance |
||
| 43 | { |
||
| 44 | public: |
||
| 45 | fix d = 0; |
||
| 46 | /* Default constructor only required because Fcd_cache,SoundObjects |
||
| 47 | * have global scope instances of vm_distance. They should be |
||
| 48 | * converted to construct as needed, then the default constructor |
||
| 49 | * should be removed. |
||
| 50 | */ |
||
| 51 | constexpr vm_distance() = default; |
||
| 52 | constexpr explicit vm_distance(const fix &f) : |
||
| 53 | d(f) |
||
| 54 | { |
||
| 55 | } |
||
| 56 | template <typename T> |
||
| 57 | vm_distance &operator+=(const T &rhs) |
||
| 58 | { |
||
| 59 | return *this = (*this + rhs); |
||
| 60 | } |
||
| 61 | template <typename T> |
||
| 62 | vm_distance &operator*=(const T &rhs) |
||
| 63 | { |
||
| 64 | return *this = (*this * rhs); |
||
| 65 | } |
||
| 66 | template <typename T> |
||
| 67 | vm_distance &operator/=(const T &rhs) |
||
| 68 | { |
||
| 69 | return *this = (*this / rhs); |
||
| 70 | } |
||
| 71 | constexpr vm_distance operator+(const vm_distance &rhs) const |
||
| 72 | { |
||
| 73 | return vm_distance{d + rhs.d}; |
||
| 74 | } |
||
| 75 | constexpr vm_distance operator*(const int &f) const |
||
| 76 | { |
||
| 77 | return vm_distance{d * f}; |
||
| 78 | } |
||
| 79 | constexpr vm_distance operator/(const int &f) const |
||
| 80 | { |
||
| 81 | return vm_distance{d / f}; |
||
| 82 | } |
||
| 83 | constexpr bool operator<(const fix &f) const |
||
| 84 | { |
||
| 85 | return d < f; |
||
| 86 | } |
||
| 87 | constexpr bool operator<(const vm_distance &rhs) const |
||
| 88 | { |
||
| 89 | return d < rhs.d; |
||
| 90 | } |
||
| 91 | /* Clang chokes using a template operator> to swap the arguments. |
||
| 92 | * Use a non-template operator> for the one needed type. |
||
| 93 | */ |
||
| 94 | constexpr bool operator>(const fix &f) const |
||
| 95 | { |
||
| 96 | return d > f; |
||
| 97 | } |
||
| 98 | template <typename T> |
||
| 99 | bool operator>(const T &t) const = delete; |
||
| 100 | constexpr explicit operator bool() const { return d; } |
||
| 101 | #ifndef __clang__ |
||
| 102 | /* When this catch-all overload is defined, clang becomes confused |
||
| 103 | * and treats all arithmetic operations as ambiguous because it |
||
| 104 | * cannot choose between the deleted template function and the |
||
| 105 | * non-deleted operator fix(). |
||
| 106 | */ |
||
| 107 | template <typename T> |
||
| 108 | operator T() const = delete; |
||
| 109 | #endif |
||
| 110 | constexpr operator fix() const |
||
| 111 | { |
||
| 112 | return d; |
||
| 113 | } |
||
| 114 | constexpr vm_distance_squared operator*(const vm_distance &) const; |
||
| 115 | }; |
||
| 116 | |||
| 117 | class vm_magnitude : public vm_distance |
||
| 118 | { |
||
| 119 | public: |
||
| 120 | constexpr explicit vm_magnitude(const uint32_t &f) : |
||
| 121 | vm_distance(f) |
||
| 122 | { |
||
| 123 | } |
||
| 124 | }; |
||
| 125 | |||
| 126 | class vm_distance_squared |
||
| 127 | { |
||
| 128 | public: |
||
| 129 | fix64 d2; |
||
| 130 | vm_distance_squared(const fix &) = delete; |
||
| 131 | constexpr explicit vm_distance_squared(const fix64 &f2) : |
||
| 132 | d2(f2) |
||
| 133 | { |
||
| 134 | } |
||
| 135 | constexpr bool operator<(const vm_distance_squared &rhs) const |
||
| 136 | { |
||
| 137 | return d2 < rhs.d2; |
||
| 138 | } |
||
| 139 | constexpr bool operator>(const vm_distance_squared &rhs) const |
||
| 140 | { |
||
| 141 | return d2 > rhs.d2; |
||
| 142 | } |
||
| 143 | constexpr bool operator>=(const vm_distance_squared &rhs) const |
||
| 144 | { |
||
| 145 | return !(*this < rhs); |
||
| 146 | } |
||
| 147 | template <typename T> |
||
| 148 | vm_distance_squared &operator-=(const T &rhs) |
||
| 149 | { |
||
| 150 | return *this = (*this - rhs); |
||
| 151 | } |
||
| 152 | constexpr vm_distance_squared operator-(const fix &) const = delete; |
||
| 153 | constexpr vm_distance_squared operator-(const fix64 &f2) const |
||
| 154 | { |
||
| 155 | return vm_distance_squared{d2 - f2}; |
||
| 156 | } |
||
| 157 | explicit operator bool() const { return d2; } |
||
| 158 | template <typename T> |
||
| 159 | constexpr operator T() const = delete; |
||
| 160 | constexpr operator fix64() const |
||
| 161 | { |
||
| 162 | return d2; |
||
| 163 | } |
||
| 164 | static constexpr vm_distance_squared maximum_value() |
||
| 165 | { |
||
| 166 | return vm_distance_squared{INT64_MAX}; |
||
| 167 | } |
||
| 168 | static constexpr vm_distance_squared minimum_value() |
||
| 169 | { |
||
| 170 | return vm_distance_squared{static_cast<fix64>(0)}; |
||
| 171 | } |
||
| 172 | }; |
||
| 173 | |||
| 174 | class vm_magnitude_squared : public vm_distance_squared |
||
| 175 | { |
||
| 176 | public: |
||
| 177 | constexpr explicit vm_magnitude_squared(const uint64_t &f2) : |
||
| 178 | vm_distance_squared(static_cast<fix64>(f2)) |
||
| 179 | { |
||
| 180 | } |
||
| 181 | }; |
||
| 182 | |||
| 183 | constexpr vm_distance_squared vm_distance::operator*(const vm_distance &rhs) const |
||
| 184 | { |
||
| 185 | return vm_distance_squared{static_cast<fix64>(static_cast<fix>(*this)) * static_cast<fix64>(static_cast<fix>(rhs))}; |
||
| 186 | } |
||
| 187 | |||
| 188 | #define DEFINE_SERIAL_VMS_VECTOR_TO_MESSAGE() \ |
||
| 189 | DEFINE_SERIAL_UDT_TO_MESSAGE(vms_vector, v, (v.x, v.y, v.z)); \ |
||
| 190 | ASSERT_SERIAL_UDT_MESSAGE_SIZE(vms_vector, 12) |
||
| 191 | |||
| 192 | //Angle vector. Used to store orientations |
||
| 193 | struct vms_angvec |
||
| 194 | { |
||
| 195 | fixang p, b, h; |
||
| 196 | }; |
||
| 197 | |||
| 198 | |||
| 199 | //A 3x3 rotation matrix. Sorry about the numbering starting with one. |
||
| 200 | //Ordering is across then down, so <m1,m2,m3> is the first row |
||
| 201 | struct vms_matrix |
||
| 202 | { |
||
| 203 | vms_vector rvec, uvec, fvec; |
||
| 204 | }; |
||
| 205 | |||
| 206 | // Quaternion structure |
||
| 207 | struct vms_quaternion |
||
| 208 | { |
||
| 209 | signed short w, x, y, z; |
||
| 210 | }; |
||
| 211 | |||
| 212 | |||
| 213 | //Macros/functions to fill in fields of structures |
||
| 214 | |||
| 215 | //macro to set a vector to zero. we could do this with an in-line assembly |
||
| 216 | //macro, but it's probably better to let the compiler optimize it. |
||
| 217 | //Note: NO RETURN VALUE |
||
| 218 | static inline void vm_vec_zero(vms_vector &v) |
||
| 219 | { |
||
| 220 | v = {}; |
||
| 221 | } |
||
| 222 | |||
| 223 | //macro set set a matrix to the identity. Note: NO RETURN VALUE |
||
| 224 | |||
| 225 | // DPH (18/9/98): Begin mod to fix linefeed problem under linux. Uses an |
||
| 226 | // inline function instead of a multi-line macro to fix CR/LF problems. |
||
| 227 | |||
| 228 | // DPH (19/8/98): End changes. |
||
| 229 | |||
| 230 | //Global constants |
||
| 231 | |||
| 232 | //Here's a handy constant |
||
| 233 | |||
| 234 | //negate a vector |
||
| 235 | static inline void vm_vec_negate(vms_vector &v) |
||
| 236 | { |
||
| 237 | v.x = -v.x; |
||
| 238 | v.y = -v.y; |
||
| 239 | v.z = -v.z; |
||
| 240 | } |
||
| 241 | |||
| 242 | static inline vms_vector vm_vec_negated(vms_vector v) __attribute_warn_unused_result; |
||
| 243 | static inline vms_vector vm_vec_negated(vms_vector v) |
||
| 244 | { |
||
| 245 | return vm_vec_negate(v), v; |
||
| 246 | } |
||
| 247 | |||
| 248 | //Functions in library |
||
| 249 | |||
| 250 | //adds two vectors, fills in dest, returns ptr to dest |
||
| 251 | //ok for dest to equal either source, but should use vm_vec_add2() if so |
||
| 252 | static inline vms_vector vm_vec_add (const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result; |
||
| 253 | static inline vms_vector vm_vec_add (const vms_vector &src0, const vms_vector &src1) |
||
| 254 | { |
||
| 255 | vms_vector dest; |
||
| 256 | return vm_vec_add(dest, src0, src1), dest; |
||
| 257 | } |
||
| 258 | |||
| 259 | |||
| 260 | //subs two vectors, fills in dest, returns ptr to dest |
||
| 261 | //ok for dest to equal either source, but should use vm_vec_sub2() if so |
||
| 262 | static inline vms_vector &vm_vec_sub(vms_vector &dest, const vms_vector &src0, const vms_vector &src1) |
||
| 263 | { |
||
| 264 | #ifdef DXX_CONSTANT_TRUE |
||
| 265 | if (DXX_CONSTANT_TRUE(&src0 == &src1)) |
||
| 266 | DXX_ALWAYS_ERROR_FUNCTION(vm_vec_sub_same_op, "vm_vec_sub with &src0 == &src1"); |
||
| 267 | else if (DXX_CONSTANT_TRUE(src0.x == src1.x && src0.y == src1.y && src0.z == src1.z)) |
||
| 268 | DXX_ALWAYS_ERROR_FUNCTION(vm_vec_sub_same_values, "vm_vec_sub with equal value inputs"); |
||
| 269 | #endif |
||
| 270 | return _vm_vec_sub(dest, src0, src1); |
||
| 271 | } |
||
| 272 | |||
| 273 | __attribute_warn_unused_result |
||
| 274 | static inline vms_vector vm_vec_sub (const vms_vector &src0, const vms_vector &src1) |
||
| 275 | { |
||
| 276 | vms_vector dest; |
||
| 277 | return vm_vec_sub(dest, src0, src1), dest; |
||
| 278 | } |
||
| 279 | |||
| 280 | //averages two vectors. returns ptr to dest |
||
| 281 | //dest can equal either source |
||
| 282 | static inline vms_vector vm_vec_avg (const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result; |
||
| 283 | static inline vms_vector vm_vec_avg (const vms_vector &src0, const vms_vector &src1) |
||
| 284 | { |
||
| 285 | vms_vector dest; |
||
| 286 | return vm_vec_avg(dest, src0, src1), dest; |
||
| 287 | } |
||
| 288 | |||
| 289 | //scales and copies a vector. returns ptr to dest |
||
| 290 | #define vm_vec_copy_scale(A,B,...) vm_vec_copy_scale(A, ## __VA_ARGS__, B) |
||
| 291 | static inline vms_vector vm_vec_copy_scale(vms_vector src, fix s) __attribute_warn_unused_result; |
||
| 292 | static inline vms_vector vm_vec_copy_scale(vms_vector src, fix s) |
||
| 293 | { |
||
| 294 | return vm_vec_scale(src, s), src; |
||
| 295 | } |
||
| 296 | |||
| 297 | //scales a vector, adds it to another, and stores in a 3rd vector |
||
| 298 | //dest = src1 + k * src2 |
||
| 299 | static inline vms_vector vm_vec_scale_add(const vms_vector &src1, const vms_vector &src2, fix k) __attribute_warn_unused_result; |
||
| 300 | static inline vms_vector vm_vec_scale_add(const vms_vector &src1, const vms_vector &src2, fix k) |
||
| 301 | { |
||
| 302 | vms_vector dest; |
||
| 303 | return vm_vec_scale_add(dest, src1, src2, k), dest; |
||
| 304 | } |
||
| 305 | |||
| 306 | static inline vms_vector vm_vec_normalized(vms_vector v) __attribute_warn_unused_result; |
||
| 307 | static inline vms_vector vm_vec_normalized(vms_vector v) |
||
| 308 | { |
||
| 309 | return vm_vec_normalize(v), v; |
||
| 310 | } |
||
| 311 | |||
| 312 | static inline vms_vector vm_vec_normalized_quick(vms_vector v) __attribute_warn_unused_result; |
||
| 313 | static inline vms_vector vm_vec_normalized_quick(vms_vector v) |
||
| 314 | { |
||
| 315 | return vm_vec_normalize_quick(v), v; |
||
| 316 | } |
||
| 317 | |||
| 318 | static inline vms_vector vm_vec_cross(const vms_vector &src0, const vms_vector &src1) __attribute_warn_unused_result; |
||
| 319 | static inline vms_vector vm_vec_cross(const vms_vector &src0, const vms_vector &src1) |
||
| 320 | { |
||
| 321 | vms_vector dest; |
||
| 322 | return vm_vec_cross(dest, src0, src1), dest; |
||
| 323 | } |
||
| 324 | |||
| 325 | static inline vms_vector vm_vec_normal(const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) __attribute_warn_unused_result; |
||
| 326 | static inline vms_vector vm_vec_normal(const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) |
||
| 327 | { |
||
| 328 | vms_vector dest; |
||
| 329 | return vm_vec_normal(dest, p0, p1, p2), dest; |
||
| 330 | } |
||
| 331 | |||
| 332 | static inline vms_vector vm_vec_perp (const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) __attribute_warn_unused_result; |
||
| 333 | static inline vms_vector vm_vec_perp (const vms_vector &p0, const vms_vector &p1, const vms_vector &p2) |
||
| 334 | { |
||
| 335 | vms_vector dest; |
||
| 336 | return vm_vec_perp(dest, p0, p1, p2), dest; |
||
| 337 | } |
||
| 338 | |||
| 339 | static inline vms_matrix vm_angles_2_matrix (const vms_angvec &a) __attribute_warn_unused_result; |
||
| 340 | static inline vms_matrix vm_angles_2_matrix (const vms_angvec &a) |
||
| 341 | { |
||
| 342 | vms_matrix m; |
||
| 343 | return vm_angles_2_matrix(m, a), m; |
||
| 344 | } |
||
| 345 | |||
| 346 | static inline vms_matrix vm_vector_2_matrix (const vms_vector &fvec, const vms_vector *uvec, const vms_vector *rvec) __attribute_warn_unused_result; |
||
| 347 | static inline vms_matrix vm_vector_2_matrix (const vms_vector &fvec, const vms_vector *uvec, const vms_vector *rvec) |
||
| 348 | { |
||
| 349 | vms_matrix m; |
||
| 350 | return vm_vector_2_matrix(m, fvec, uvec, rvec), m; |
||
| 351 | } |
||
| 352 | |||
| 353 | static inline vms_vector vm_vec_rotate (const vms_vector &src, const vms_matrix &m) __attribute_warn_unused_result; |
||
| 354 | static inline vms_vector vm_vec_rotate (const vms_vector &src, const vms_matrix &m) |
||
| 355 | { |
||
| 356 | vms_vector dest; |
||
| 357 | return vm_vec_rotate(dest, src, m), dest; |
||
| 358 | } |
||
| 359 | |||
| 360 | //transpose a matrix in place. returns ptr to matrix |
||
| 361 | static inline void vm_transpose_matrix(vms_matrix &m) |
||
| 362 | { |
||
| 363 | using std::swap; |
||
| 364 | swap(m.uvec.x, m.rvec.y); |
||
| 365 | swap(m.fvec.x, m.rvec.z); |
||
| 366 | swap(m.fvec.y, m.uvec.z); |
||
| 367 | } |
||
| 368 | |||
| 369 | static inline vms_matrix vm_transposed_matrix(vms_matrix m) __attribute_warn_unused_result; |
||
| 370 | static inline vms_matrix vm_transposed_matrix(vms_matrix m) |
||
| 371 | { |
||
| 372 | vm_transpose_matrix(m); |
||
| 373 | return m; |
||
| 374 | } |
||
| 375 | |||
| 376 | //mulitply 2 matrices, fill in dest. returns ptr to dest |
||
| 377 | static inline void vm_matrix_x_matrix(vms_matrix &dest, const vms_matrix &src0, const vms_matrix &src1) |
||
| 378 | { |
||
| 379 | #ifdef DXX_CONSTANT_TRUE |
||
| 380 | if (DXX_CONSTANT_TRUE(&dest == &src0)) |
||
| 381 | DXX_ALWAYS_ERROR_FUNCTION(vm_matrix_x_matrix_dest_src0, "vm_matrix_x_matrix with &dest == &src0"); |
||
| 382 | else if (DXX_CONSTANT_TRUE(&dest == &src1)) |
||
| 383 | DXX_ALWAYS_ERROR_FUNCTION(vm_matrix_x_matrix_dest_src1, "vm_matrix_x_matrix with &dest == &src1"); |
||
| 384 | #endif |
||
| 385 | assert(&dest != &src0); |
||
| 386 | assert(&dest != &src1); |
||
| 387 | return _vm_matrix_x_matrix(dest, src0, src1); |
||
| 388 | } |
||
| 389 | |||
| 390 | static inline vms_matrix vm_matrix_x_matrix(const vms_matrix &src0, const vms_matrix &src1) __attribute_warn_unused_result; |
||
| 391 | static inline vms_matrix vm_matrix_x_matrix(const vms_matrix &src0, const vms_matrix &src1) |
||
| 392 | { |
||
| 393 | vms_matrix dest; |
||
| 394 | vm_matrix_x_matrix(dest, src0, src1); |
||
| 395 | return dest; |
||
| 396 | } |
||
| 397 | |||
| 398 | static inline vms_angvec vm_extract_angles_matrix (const vms_matrix &m) __attribute_warn_unused_result; |
||
| 399 | static inline vms_angvec vm_extract_angles_matrix (const vms_matrix &m) |
||
| 400 | { |
||
| 401 | vms_angvec a; |
||
| 402 | return vm_extract_angles_matrix(a, m), a; |
||
| 403 | } |
||
| 404 | |||
| 405 | //fills in fields of an angle vector |
||
| 406 | static inline void vm_angvec_make(vms_angvec *v, fixang p, fixang b, fixang h) |
||
| 407 | { |
||
| 408 | v->p = p; |
||
| 409 | v->b = b; |
||
| 410 | v->h = h; |
||
| 411 | } |
||
| 412 | |||
| 413 | } |
||
| 414 | |||
| 415 | #endif |