Imported from d1x
[btb/d2x.git] / include / vecmat.h
1
2 /*
3    THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4    SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5    END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6    ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7    IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8    SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9    FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10    CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11    AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
12    COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13  */  
14 /*
15  * $Source: /cvs/cvsroot/d2x/include/vecmat.h,v $
16  * $Revision: 1.3 $
17  * $Author: bradleyb $
18  * $Date: 2001-10-18 23:59:22 $
19  *
20  * Header file for vector/matrix library
21  *
22  * $Log: not supported by cvs2svn $
23  * Revision 1.2  2001/10/12 06:40:49  bradleyb
24  * fix some gcc 3.0 warnings, courtesy of paoloulivi@tin.it
25  *
26  * Revision 1.1.1.1  2001/01/19 03:30:16  bradleyb
27  * Import of d2x-0.0.8
28  *
29  * Revision 1.1.1.1  1999/06/14 22:02:28  donut
30  * Import of d1x 1.37 source.
31  *
32  * Revision 1.1  1995/04/17  16:18:05  allender
33  * Initial revision
34  *
35  *
36  * --- PC RCS Information ---
37  * Revision 1.37  1995/02/22  13:23:22  john
38  * Added the vms_vector_array structure, to access a vms_vector
39  * with an array.
40  * 
41  * Revision 1.36  1995/02/22  12:34:33  john
42  * Took out anonymous unions.
43  * 
44  * Revision 1.35  1994/12/13  14:44:20  matt
45  * Added vm_vector_2_matrix_norm()
46  * 
47  * Revision 1.34  1994/09/11  19:22:55  matt
48  * Added vm_vec_normalized_dir_quick()
49  * 
50  * Revision 1.33  1994/08/04  19:45:38  matt
51  * Added option to make a bunch of functions (add, sub, dotprod) inline
52  * 
53  * Revision 1.32  1994/07/19  18:52:36  matt
54  * Added vm_vec_normalize_quick() and vm_vec_copy_normalize_quick()
55  * 
56  * Revision 1.31  1994/06/16  18:24:30  matt
57  * Added vm_vec_mag_quick()
58  * 
59  * Revision 1.30  1994/06/10  23:19:00  matt
60  * New register usage for vm_vec_ang_2_matrix()
61  * 
62  * Revision 1.29  1994/06/01  17:32:06  matt
63  * Fixed modify list for vm_vec_normalized_dir()
64  * 
65  * Revision 1.28  1994/05/19  12:07:20  matt
66  * Fixed globals and macros and added a constant
67  * 
68  * Revision 1.27  1994/05/19  09:19:15  matt
69  * Made vm_vec_normalized_dir() return mag of vector
70  * 
71  * Revision 1.26  1994/05/18  22:28:57  matt
72  * Added function vm_vec_normalized_dir()
73  * Added C macros IS_ZERO_VEC(), vm_vec_zero(), and vm_set_identity()
74  * Added C global static vars vmd_zero_vector & vmd_identity_matrix
75  * 
76  * Revision 1.25  1994/05/18  21:45:06  matt
77  * Added functions:
78  *   vm_extract_angles_vector()
79  *   vm_extract_angles_vector_normalized()
80  *   vm_vec_copy_normalize()
81  * 
82  * Revision 1.24  1994/05/13  12:42:16  matt
83  * Added new function, vm_vec_dist_quick(), which does an approximation.
84  * 
85  * Revision 1.23  1994/03/30  13:37:34  matt
86  * Added prototype for vm_vec_scale_add(), and fixed typos
87  * 
88  * Revision 1.22  1994/03/30  13:29:42  matt
89  * Header for vm_vec_scale_add2()
90  * 
91  * Revision 1.21  1994/01/31  19:45:13  matt
92  * Added function vm_extract_angles_matrix()
93  * 
94  * Revision 1.20  1993/12/21  19:46:14  matt
95  * Added function vm_dist_to_plane()
96  * 
97  * Revision 1.19  1993/12/13  17:26:41  matt
98  * Added vm_vec_dist()
99  * 
100  * Revision 1.18  1993/12/02  12:45:11  matt
101  * New functions: vm_vec_copy_scale(), vm_vec_scale2()
102  * Aliases: vm_transpose(), vm_vec_dot(), vm_vec_cross(), vm_copy_transpose()
103  * 
104  * Revision 1.17  1993/10/29  22:38:36  matt
105  * Changed matrix order, making direction vectors the rows
106  * 
107  * Revision 1.16  1993/10/25  11:49:57  matt
108  * Made vm_vec_delta_ang() take optional forward vector to return signed delta
109  * 
110  * Revision 1.15  1993/10/20  01:10:05  matt
111  * Added vm_vec_delta_ang(), vm_vec_delta_ang_norm(), and vm_vec_ang_2_matrix()
112  * 
113  * Revision 1.14  1993/10/17  17:02:52  matt
114  * vm_vector_2_matrix() now takes optional right vector
115  * 
116  * Revision 1.13  1993/10/12  19:31:39  matt
117  * Added IDENTITY_MATRIX constant
118  * 
119  * Revision 1.12  1993/10/08  18:10:16  matt
120  * Changed vm_vec_make() and vm_angvec_make() to be inline assembly 
121  * functions, to get rid of compiler warnings.  Did not change vm_mat_make(),
122  * which could still get warnings if the return value is unused.
123  * 
124  * Revision 1.11  1993/09/29  12:10:07  matt
125  * Changed modified regs in pragmas to include return register
126  * 
127  * Revision 1.10  1993/09/28  12:15:41  matt
128  * Added func vm_vector_2_matrix()
129  * 
130  * Revision 1.9  1993/09/24  21:18:38  matt
131  * Added vm_vec_avg(), vm_vec_avg4(), and vm_angvec_make().
132  * Documented which functions could have dest==source
133  * 
134  * Revision 1.8  1993/09/20  14:56:11  matt
135  * Added new function, vm_vec_perp()
136  * 
137  * Revision 1.7  1993/09/20  14:27:42  mike
138  * unfix last fix which introduced a bug
139  * 
140  * Revision 1.6  1993/09/20  10:11:53  mike
141  * no changes
142  * 
143  * Revision 1.5  1993/09/20  09:58:58  mike
144  * Re-fix vm_vec_make
145  * 
146  * Revision 1.4  1993/09/20  09:41:21  mike
147  * Correct vm_vec_make and vm_mat_make macros to return the destination
148  * as the value of the macro.
149  * 
150  * Revision 1.3  1993/09/17  11:23:47  matt
151  * Added row access (via xrow,yrow,zrow) to vms_matrix
152  * Added macro vm_mat_make(), like vm_vec_make()
153  * 
154  * Revision 1.2  1993/09/17  11:10:32  matt
155  * Added vm_vec_add2() and vm_vec_sub2(), which take 2 args (dest==src0)
156  * 
157  * Revision 1.1  1993/09/16  20:10:01  matt
158  * Initial revision
159  * 
160  *
161  */ 
162
163 #ifndef _VECMAT_H
164 #define _VECMAT_H
165
166 #include "maths.h"
167
168 //#define INLINE 1              //are some of these functions inline?
169
170 //The basic fixed-point vector.  Access elements by name or position
171 typedef struct vms_vector
172   {
173     
174     fix x, y, z;
175     
176   }
177 __pack__ vms_vector;
178
179
180 typedef struct vms_vector_array
181   {
182     
183     fix xyz[3];
184     
185   }
186 __pack__ vms_vector_array;
187
188
189 //Short vector, used for pre-rotation points. 
190 //Access elements by name or position
191 typedef struct vms_svec
192   {
193     
194     short sv_x, sv_y, sv_z;
195      
196   }
197 __pack__ vms_svec;
198
199
200 //Angle vector.  Used to store orientations
201 typedef struct vms_angvec
202   {
203     
204     fixang p, b, h;
205     
206   }
207 __pack__ vms_angvec;
208
209
210 //A 3x3 rotation matrix.  Sorry about the numbering starting with one.
211 //Ordering is across then down, so <m1,m2,m3> is the first row
212 typedef struct vms_matrix
213   {
214     
215     vms_vector rvec, uvec, fvec;
216     
217   }
218 __pack__ vms_matrix;
219
220
221 //Macros/functions to fill in fields of structures
222
223 //macro to check if vector is zero
224 #define IS_VEC_NULL(v) (v->x == 0 && v->y == 0 && v->z == 0)
225
226 //macro to set a vector to zero.  we could do this with an in-line assembly 
227 //macro, but it's probably better to let the compiler optimize it.
228 //Note: NO RETURN VALUE
229 #define vm_vec_zero(v) (v)->x=(v)->y=(v)->z=0
230
231 //macro set set a matrix to the identity. Note: NO RETURN VALUE
232
233 // DPH (18/9/98): Begin mod to fix linefeed problem under linux. Uses an
234 // inline function instead of a multi-line macro to fix CR/LF problems.
235
236 #ifdef __linux__
237 static inline void vm_set_identity(vms_matrix *m)
238 {
239   m->rvec.x = m->uvec.y = m->fvec.z = f1_0;
240   m->rvec.y = m->rvec.z = m->uvec.x = m->uvec.z = m->fvec.x = m->fvec.y = 0;
241 }
242 #else
243 #define vm_set_identity(m) do {m->rvec.x = m->uvec.y = m->fvec.z = f1_0; \
244         m->rvec.y = m->rvec.z = \
245         m->uvec.x = m->uvec.z = \
246         m->fvec.x = m->fvec.y = 0;} while (0)
247 #endif
248
249 // DPH (19/8/98): End changes.
250
251 vms_vector * vm_vec_make (vms_vector * v, fix x, fix y, fix z);
252
253
254 #ifdef __WATCOMC__
255 #pragma aux vm_vec_make "*_" parm [eax] [edx] [ebx] [ecx] value [eax] modify exact [] = \
256 "mov 0[eax],edx" \
257 "mov 4[eax],ebx" \
258 "mov 8[eax],ecx";
259
260 #endif
261
262 vms_angvec * vm_angvec_make (vms_angvec * v, fixang p, fixang b, fixang h);
263
264
265 #ifdef __WATCOMC__
266 #pragma aux vm_angvec_make "*_" parm [eax] [dx] [bx] [cx] value [eax] modify exact [] = \
267 "mov 0[eax],dx" \
268 "mov 2[eax],bx" \
269 "mov 4[eax],cx";
270
271 #endif
272
273 //Global constants
274
275 extern vms_vector vmd_zero_vector;
276
277 extern vms_matrix vmd_identity_matrix;
278
279
280 //Here's a handy constant
281
282 #define ZERO_VECTOR {0,0,0}
283 #define IDENTITY_MATRIX { {f1_0,0,0}, {0,f1_0,0}, {0,0,f1_0} }
284
285 //#define vm_vec_make(v,_x,_y,_z) (((v)->x=(_x), (v)->y=(_y), (v)->z=(_z)), (v))
286
287 //#pragma off (unreferenced)
288 ////make this local, so compiler can in-line it
289 //static vms_vector *vm_vec_make(vms_vector *v,fix x,fix y,fix z)
290 //{
291 //      v->x = x;
292 //      v->y = y;
293 //      v->z = z;
294 //
295 //      return v;
296 //}
297 //#pragma on (unreferenced)
298
299
300 ////macro to fill in elements of a matrix, also for Mike
301 /*
302    #define vm_mat_make(m,_m1,_m2,_m3,_m4,_m5,_m6,_m7,_m8,_m9) \
303    do { (m)->m1=(_m1); (m)->m2=(_m2); (m)->m3=(_m3); \
304    (m)->m4=(_m4); (m)->m5=(_m5); (m)->m6=(_m6); \
305    (m)->m7=(_m7); (m)->m8=(_m8); (m)->m9=(_m9);} while (0)
306  */ 
307
308 #if 0                           //kill this, since bogus with new matrix ordering
309
310 //macro to fill in elements of a matrix, also for Mike
311 #define vm_mat_make(m,_m1,_m2,_m3,_m4,_m5,_m6,_m7,_m8,_m9) \
312 (((m)->m1 = (_m1), (m)->m2 = (_m2), (m)->m3 = (_m3), \
313   (m)->m4 = (_m4), (m)->m5 = (_m5), (m)->m6 = (_m6), \
314   (m)->m7 = (_m7), (m)->m8 = (_m8), (m)->m9 = (_m9)), (m)) 
315
316 #endif  /* 
317  */
318
319 ////fills in fields of an angle vector
320 //#define vm_angvec_make(v,_p,_b,_h) (((v)->p=(_p), (v)->b=(_b), (v)->h=(_h)), (v))
321
322 //negate a vector
323 #define vm_vec_negate(v) do {(v)->x = - (v)->x; (v)->y = - (v)->y; (v)->z = - (v)->z;} while (0);
324
325 //Functions in library
326
327 #ifndef INLINE
328
329 //adds two vectors, fills in dest, returns ptr to dest
330 //ok for dest to equal either source, but should use vm_vec_add2() if so
331 vms_vector * vm_vec_add (vms_vector * dest, vms_vector * src0, vms_vector * src1);
332
333
334 //subs two vectors, fills in dest, returns ptr to dest
335 //ok for dest to equal either source, but should use vm_vec_sub2() if so
336 vms_vector * vm_vec_sub (vms_vector * dest, vms_vector * src0, vms_vector * src1);
337
338
339 //adds one vector to another. returns ptr to dest
340 //dest can equal source
341 vms_vector * vm_vec_add2 (vms_vector * dest, vms_vector * src);
342
343
344 //subs one vector from another, returns ptr to dest
345 //dest can equal source
346 vms_vector * vm_vec_sub2 (vms_vector * dest, vms_vector * src);
347
348
349 #else   /* 
350  */
351
352 #define vm_vec_add(dest,src0,src1) do { \
353 (dest)->x = (src0)->x + (src1)->x;
354 \
355 (dest)->y = (src0)->y + (src1)->y;
356 \
357 (dest)->z = (src0)->z + (src1)->z;
358 \
359 }
360 while (0);
361
362
363 #define vm_vec_sub(dest,src0,src1) do { \
364 (dest)->x = (src0)->x - (src1)->x;
365 \
366 (dest)->y = (src0)->y - (src1)->y;
367 \
368 (dest)->z = (src0)->z - (src1)->z;
369 \
370 }
371 while (0);
372
373
374 #define vm_vec_add2(dest,src) do {              \
375 (dest)->x += (src)->x;
376 \
377 (dest)->y += (src)->y;
378 \
379 (dest)->z += (src)->z;
380 \
381 }
382 while (0);
383
384
385 #define vm_vec_sub2(dest,src) do {              \
386 (dest)->x -= (src)->x;
387 \
388 (dest)->y -= (src)->y;
389 \
390 (dest)->z -= (src)->z;
391 \
392 }
393 while (0);
394
395
396 #endif  /* 
397  */
398
399 //averages two vectors. returns ptr to dest
400 //dest can equal either source
401 vms_vector * vm_vec_avg (vms_vector * dest, vms_vector * src0, vms_vector * src1);
402
403
404 //averages four vectors. returns ptr to dest
405 //dest can equal any source
406 vms_vector * vm_vec_avg4 (vms_vector * dest, vms_vector * src0, vms_vector * src1, vms_vector * src2, vms_vector * src3);
407
408
409 //scales a vector in place.  returns ptr to vector
410 vms_vector * vm_vec_scale (vms_vector * dest, fix s);
411
412
413 //scales and copies a vector.  returns ptr to dest
414 vms_vector * vm_vec_copy_scale (vms_vector * dest, vms_vector * src, fix s);
415
416
417 //scales a vector, adds it to another, and stores in a 3rd vector
418 //dest = src1 + k * src2
419 vms_vector * vm_vec_scale_add (vms_vector * dest, vms_vector * src1, vms_vector * src2, fix k);
420
421
422 //scales a vector and adds it to another
423 //dest += k * src
424 vms_vector * vm_vec_scale_add2 (vms_vector * dest, vms_vector * src, fix k);
425
426
427 //scales a vector in place, taking n/d for scale.  returns ptr to vector
428 //dest *= n/d
429 vms_vector * vm_vec_scale2 (vms_vector * dest, fix n, fix d);
430
431
432 //returns magnitude of a vector
433 fix vm_vec_mag (vms_vector * v);
434
435
436 //computes the distance between two points. (does sub and mag)
437 fix vm_vec_dist (vms_vector * v0, vms_vector * v1);
438
439
440 //computes an approximation of the magnitude of the vector
441 //uses dist = largest + next_largest*3/8 + smallest*3/16
442 fix vm_vec_mag_quick (vms_vector * v);
443
444
445 //computes an approximation of the distance between two points.
446 //uses dist = largest + next_largest*3/8 + smallest*3/16
447 fix vm_vec_dist_quick (vms_vector * v0, vms_vector * v1);
448
449
450
451 //normalize a vector. returns mag of source vec
452 fix vm_vec_copy_normalize (vms_vector * dest, vms_vector * src);
453
454 fix vm_vec_normalize (vms_vector * v);
455
456
457 //normalize a vector. returns mag of source vec. uses approx mag
458 fix vm_vec_copy_normalize_quick (vms_vector * dest, vms_vector * src);
459
460 fix vm_vec_normalize_quick (vms_vector * v);
461
462
463 //return the normalized direction vector between two points
464 //dest = normalized(end - start).  Returns mag of direction vector
465 //NOTE: the order of the parameters matches the vector subtraction
466 fix vm_vec_normalized_dir (vms_vector * dest, vms_vector * end, vms_vector * start);
467
468 fix vm_vec_normalized_dir_quick (vms_vector * dest, vms_vector * end, vms_vector * start);
469
470
471 ////returns dot product of two vectors
472 fix vm_vec_dotprod (vms_vector * v0, vms_vector * v1);
473
474 #define vm_vec_dot(v0,v1) vm_vec_dotprod((v0),(v1))
475
476 #ifdef INLINE
477 #ifdef __WATCOMC__
478 #pragma aux vm_vec_dotprod parm [esi] [edi] value [eax] modify exact [eax ebx ecx edx] = \
479 "mov    eax,[esi]" \
480 "imul   dword ptr [edi]" \
481 "mov    ebx,eax" \
482 "mov    ecx,edx" \
483 \
484 "mov    eax,4[esi]" \
485 "imul   dword ptr 4[edi]" \
486 "add    ebx,eax" \
487 "adc    ecx,edx" \
488 \
489 "mov    eax,8[esi]" \
490 "imul   dword ptr 8[edi]" \
491 "add    eax,ebx" \
492 "adc    edx,ecx" \
493 \
494 "shrd   eax,edx,16";
495
496 #endif
497 #endif  /* 
498  */
499
500 //computes cross product of two vectors. returns ptr to dest
501 //dest CANNOT equal either source
502 vms_vector * vm_vec_crossprod (vms_vector * dest, vms_vector * src0, vms_vector * src1);
503
504 #define vm_vec_cross(dest,src0,src1) vm_vec_crossprod((dest),(src0),(src1))
505
506 //computes surface normal from three points. result is normalized
507 //returns ptr to dest
508 //dest CANNOT equal either source
509 vms_vector * vm_vec_normal (vms_vector * dest, vms_vector * p0, vms_vector * p1, vms_vector * p2);
510
511
512 //computes non-normalized surface normal from three points. 
513 //returns ptr to dest
514 //dest CANNOT equal either source
515 vms_vector * vm_vec_perp (vms_vector * dest, vms_vector * p0, vms_vector * p1, vms_vector * p2);
516
517
518 //computes the delta angle between two vectors. 
519 //vectors need not be normalized. if they are, call vm_vec_delta_ang_norm()
520 //the forward vector (third parameter) can be NULL, in which case the absolute
521 //value of the angle in returned.  Otherwise the angle around that vector is
522 //returned.
523 fixang vm_vec_delta_ang (vms_vector * v0, vms_vector * v1, vms_vector * fvec);
524
525
526 //computes the delta angle between two normalized vectors. 
527 fixang vm_vec_delta_ang_norm (vms_vector * v0, vms_vector * v1, vms_vector * fvec);
528
529
530 //computes a matrix from a set of three angles.  returns ptr to matrix
531 vms_matrix * vm_angles_2_matrix (vms_matrix * m, vms_angvec * a);
532
533
534 //computes a matrix from a forward vector and an angle
535 vms_matrix * vm_vec_ang_2_matrix (vms_matrix * m, vms_vector * v, fixang a);
536
537
538 //computes a matrix from one or more vectors. The forward vector is required,
539 //with the other two being optional.  If both up & right vectors are passed,
540 //the up vector is used.  If only the forward vector is passed, a bank of
541 //zero is assumed
542 //returns ptr to matrix
543 vms_matrix * vm_vector_2_matrix (vms_matrix * m, vms_vector * fvec, vms_vector * uvec, vms_vector * rvec);
544
545
546 //this version of vector_2_matrix requires that the vectors be more-or-less
547 //normalized and close to perpendicular
548 vms_matrix * vm_vector_2_matrix_norm (vms_matrix * m, vms_vector * fvec, vms_vector * uvec, vms_vector * rvec);
549
550
551 //rotates a vector through a matrix. returns ptr to dest vector
552 //dest CANNOT equal either source
553 vms_vector * vm_vec_rotate (vms_vector * dest, vms_vector * src, vms_matrix * m);
554
555
556 //transpose a matrix in place. returns ptr to matrix
557 vms_matrix * vm_transpose_matrix (vms_matrix * m);
558
559 #define vm_transpose(m) vm_transpose_matrix(m)
560
561 //copy and transpose a matrix. returns ptr to matrix
562 //dest CANNOT equal source. use vm_transpose_matrix() if this is the case
563 vms_matrix * vm_copy_transpose_matrix (vms_matrix * dest, vms_matrix * src);
564
565 #define vm_copy_transpose(dest,src) vm_copy_transpose_matrix((dest),(src))
566
567 //mulitply 2 matrices, fill in dest.  returns ptr to dest
568 //dest CANNOT equal either source
569 vms_matrix * vm_matrix_x_matrix (vms_matrix * dest, vms_matrix * src0, vms_matrix * src1);
570
571
572 //extract angles from a matrix 
573 vms_angvec * vm_extract_angles_matrix (vms_angvec * a, vms_matrix * m);
574
575
576 //extract heading and pitch from a vector, assuming bank==0
577 vms_angvec * vm_extract_angles_vector (vms_angvec * a, vms_vector * v);
578
579
580 //compute the distance from a point to a plane.  takes the normalized normal
581 //of the plane (ebx), a point on the plane (edi), and the point to check (esi).
582 //returns distance in eax
583 //distance is signed, so negative dist is on the back of the plane
584 fix vm_dist_to_plane (vms_vector * checkp, vms_vector * norm, vms_vector * planep);
585
586
587 //fills in fields of an angle vector
588 #define vm_angvec_make(v,_p,_b,_h) (((v)->p=(_p), (v)->b=(_b), (v)->h=(_h)), (v))
589 #endif  /* 
590  */
591