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;
vm_distance(const fix & f)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
fix()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:
vm_magnitude(const uint32_t & f)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;
vm_distance_squared(const fix64 & f2)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;
fix64()160 constexpr operator fix64() const
161 {
162 return d2;
163 }
maximum_value()164 static constexpr vm_distance_squared maximum_value()
165 {
166 return vm_distance_squared{INT64_MAX};
167 }
minimum_value()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:
vm_magnitude_squared(const uint64_t & f2)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
vm_vec_zero(vms_vector & v)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
vm_vec_negate(vms_vector & v)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 [[nodiscard]]
vm_vec_negated(vms_vector v)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 [[nodiscard]]
vm_vec_add(const vms_vector & src0,const vms_vector & src1)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
vm_vec_sub(vms_vector & dest,const vms_vector & src0,const vms_vector & src1)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 [[nodiscard]]
vm_vec_sub(const vms_vector & src0,const vms_vector & src1)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 [[nodiscard]]
vm_vec_avg(const vms_vector & src0,const vms_vector & src1)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 [[nodiscard]]
vm_vec_copy_scale(vms_vector src,fix s)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 [[nodiscard]]
vm_vec_scale_add(const vms_vector & src1,const vms_vector & src2,fix k)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 [[nodiscard]]
vm_vec_normalized(vms_vector v)307 static inline vms_vector vm_vec_normalized(vms_vector v)
308 {
309 return vm_vec_normalize(v), v;
310 }
311
312 [[nodiscard]]
vm_vec_normalized_quick(vms_vector v)313 static inline vms_vector vm_vec_normalized_quick(vms_vector v)
314 {
315 return vm_vec_normalize_quick(v), v;
316 }
317
318 [[nodiscard]]
vm_vec_cross(const vms_vector & src0,const vms_vector & src1)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 [[nodiscard]]
vm_vec_normal(const vms_vector & p0,const vms_vector & p1,const vms_vector & p2)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 [[nodiscard]]
vm_vec_perp(const vms_vector & p0,const vms_vector & p1,const vms_vector & p2)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 [[nodiscard]]
vm_angles_2_matrix(const vms_angvec & a)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 [[nodiscard]]
vm_vector_2_matrix(const vms_vector & fvec,const vms_vector * uvec,const vms_vector * rvec)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 [[nodiscard]]
vm_vec_rotate(const vms_vector & src,const vms_matrix & m)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
vm_transpose_matrix(vms_matrix & m)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 [[nodiscard]]
vm_transposed_matrix(vms_matrix m)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
vm_matrix_x_matrix(vms_matrix & dest,const vms_matrix & src0,const vms_matrix & src1)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 [[nodiscard]]
vm_matrix_x_matrix(const vms_matrix & src0,const vms_matrix & src1)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 [[nodiscard]]
vm_extract_angles_matrix(const vms_matrix & m)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
vm_angvec_make(vms_angvec * v,fixang p,fixang b,fixang h)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
416