]> icculus.org git repositories - btb/d2x.git/blob - maths/vecmata.asm
add --enable-xploader, support arch/linux subdir, fix NASMFLAGS.
[btb/d2x.git] / maths / vecmata.asm
1 ;THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
2 ;SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
3 ;END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
4 ;ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
5 ;IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
6 ;SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
7 ;FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
8 ;CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
9 ;AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
10 ;COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
11 ;
12 ; $Source: /cvs/cvsroot/d2x/maths/vecmata.asm,v $
13 ; $Revision: 1.1.1.1 $
14 ; $Author: bradleyb $
15 ; $Date: 2001-01-19 03:29:58 $
16 ;
17 ; Source for vector/matrix library
18 ;
19 ; $Log: not supported by cvs2svn $
20 ; Revision 1.1.1.1  1999/06/14 22:13:33  donut
21 ; Import of d1x 1.37 source.
22 ;
23 ; Revision 1.54  1995/01/31  00:14:50  matt
24 ; Took out int3 from dotprod overflow, since it saturates now
25
26 ; Revision 1.53  1994/12/14  18:29:33  matt
27 ; Made dotprod overflow check stay in, and return saturated value
28
29 ; Revision 1.52  1994/12/14  12:34:13  matt
30 ; Disabled now-unused vector_2_matrix_norm()
31
32 ; Revision 1.51  1994/12/13  16:55:13  matt
33 ; Ripped out optimization from last version, which was bogus
34
35 ; Revision 1.50  1994/12/13  14:55:18  matt
36 ; Use quick normalize in a couple of places where it was safe to do so
37
38 ; Revision 1.49  1994/12/13  14:44:12  matt
39 ; Added vm_vector_2_matrix_norm()
40
41 ; Revision 1.48  1994/12/13  13:26:49  matt
42 ; Fixed overflow check
43
44 ; Revision 1.47  1994/12/03  15:39:54  matt
45 ; Gracefully handle some vector_2_matrix problems
46
47 ; Revision 1.46  1994/11/19  17:15:05  matt
48 ; Assemble out some code not used in DESCENT
49
50 ; Revision 1.45  1994/11/17  11:41:05  matt
51 ; Put handling in extract_angles_from_matrix to deal with bad matrices
52
53 ; Revision 1.44  1994/11/16  11:48:10  matt
54 ; Added error checking to vm_extract_angles_matrix()
55
56 ; Revision 1.43  1994/09/19  22:00:10  matt
57 ; Fixed register trash
58
59 ; Revision 1.42  1994/09/11  19:23:05  matt
60 ; Added vm_vec_normalized_dir_quick()
61
62 ; Revision 1.41  1994/08/14  13:28:38  matt
63 ; Put in check for zero-length vector in extract angles
64
65 ; Revision 1.40  1994/07/19  18:52:53  matt
66 ; Added vm_vec_normalize_quick() and vm_vec_copy_normalize_quick()
67
68 ; Revision 1.39  1994/06/16  18:24:22  matt
69 ; Added vm_vec_mag_quick()
70
71 ; Revision 1.38  1994/06/10  23:18:38  matt
72 ; Added new code for vm_vec_ang_2_matrix() which may be better, but may
73 ; not be.
74
75 ; Revision 1.37  1994/05/22  18:17:29  mike
76 ; Optimize vm_vec_dist_quick, using jns in place of abs_eax.
77
78 ; Revision 1.36  1994/05/19  12:07:04  matt
79 ; Fixed globals and macros and added a constant
80
81 ; Revision 1.35  1994/05/19  09:19:00  matt
82 ; Made vm_vec_normalized_dir() return mag of vector
83
84 ; Revision 1.34  1994/05/18  22:28:01  matt
85 ; Added function vm_vec_normalized_dir()
86 ; Added C macros IS_ZERO_VEC(), vm_vec_zero(), and vm_set_identity()
87 ; Added C global static vars vmd_zero_vector & vmd_identity_matrix
88
89 ; Revision 1.33  1994/05/18  21:44:16  matt
90 ; Added functions:
91 ;   vm_extract_angles_vector()
92 ;   vm_extract_angles_vector_normalized()
93 ;   vm_vec_copy_normalize()
94
95 ; Revision 1.32  1994/05/13  12:41:51  matt
96 ; Added new function, vm_vec_dist_quick(), which does an approximation.
97
98 ; Revision 1.31  1994/05/04  17:41:31  mike
99 ; Comment out debug_brk on null vector.
100
101 ; Revision 1.30  1994/04/15  21:41:31  matt
102 ; Check for foward vector straigt up in extract angles routine
103
104 ; Revision 1.29  1994/03/30  15:45:05  matt
105 ; Added two functions, vm_vec_scale_add() & vm_vec_scale_add2()
106
107 ; Revision 1.28  1994/02/26  19:23:35  matt
108 ; Do an int3 when we get a null vector when computing surface normal
109
110 ; Revision 1.27  1994/02/10  18:29:45  matt
111 ; Changed 'if DEBUG_ON' to 'ifndef NDEBUG'
112
113 ; Revision 1.26  1994/02/10  18:28:55  matt
114 ; Fixed bugs in extract angles function
115
116 ; Revision 1.25  1994/01/31  22:46:07  matt
117 ; Added vm_extract_angles_matrix() function
118
119 ; Revision 1.24  1994/01/30  19:29:55  matt
120 ; Put in debug_brk when vm_vec_2_matrix got zero-length vector
121
122 ; Revision 1.23  1994/01/25  15:27:59  matt
123 ; Added debugging check for dotprod overflow
124
125 ; Revision 1.22  1994/01/24  11:52:59  matt
126 ; Added checking for dest==src for several functions where this is not allowed
127
128 ; Revision 1.21  1994/01/19  23:13:02  matt
129 ; Fixed bug in vm_vec_ang_2_matrix()
130
131 ; Revision 1.20  1994/01/04  12:33:43  mike
132 ; Prevent divide overflow in vm_vec_scale2
133
134 ; Revision 1.19  1993/12/21  19:46:26  matt
135 ; Added function vm_dist_to_plane()
136
137 ; Revision 1.18  1993/12/13  17:26:23  matt
138 ; Added vm_vec_dist()
139
140 ; Revision 1.17  1993/12/02  12:43:39  matt
141 ; New functions: vm_vec_copy_scale(), vm_vec_scale2()
142
143 ; Revision 1.16  1993/10/29  22:39:29  matt
144 ; Changed matrix order, making direction vectors the rows
145
146 ; Revision 1.15  1993/10/29  18:06:01  matt
147 ; Fixed vm_vector_2_matrix() bug when forward vector was straight down
148
149 ; Revision 1.14  1993/10/26  18:51:26  matt
150 ; Fixed some register trashes in vm_vec_ang_2_matrix()
151
152 ; Revision 1.13  1993/10/25  11:49:37  matt
153 ; Made vm_vec_delta_ang() take optional forward vector to return signed delta
154
155 ; Revision 1.12  1993/10/20  01:09:42  matt
156 ; Added vm_vec_delta_ang(), vm_vec_delta_ang_norm(), and vm_vec_ang_2_matrix()
157
158 ; Revision 1.11  1993/10/17  17:03:08  matt
159 ; vm_vector_2_matrix() now takes optional right vector
160
161 ; Revision 1.10  1993/10/10  18:11:42  matt
162 ; Changed angles_2_matrix so that heading & bank rotate in the 
163 ; correct directions.
164
165 ; Revision 1.9  1993/09/30  16:17:59  matt
166 ; Fixed bug in vector_2_matrix() by adding another normalize
167
168 ; Revision 1.8  1993/09/29  10:51:58  matt
169 ; Fixed bad register trashes in crossprod, perp, & normal
170
171 ; Revision 1.7  1993/09/28  12:16:46  matt
172 ; Fixed bugs in cross product
173 ; Added func vm_vector_2_matrix()
174
175 ; Revision 1.6  1993/09/24  21:19:37  matt
176 ; Added vm_vec_avg() and vm_vec_avg4()
177
178 ; Revision 1.5  1993/09/20  18:15:07  matt
179 ; Trap zero-length vectors in vm_vec_normalize(), vm_vec_perp(), and vm_vec_normal()
180
181 ; Revision 1.4  1993/09/20  14:56:43  matt
182 ; Fixed bug in vm_vec_normal(), made that routine normalize the results,
183 ; and added new function vm_vec_perp().
184
185 ; Revision 1.3  1993/09/20  10:12:06  mike
186 ; no changes
187
188 ; Revision 1.2  1993/09/17  11:10:33  matt
189 ; Added vm_vec_add2() and vm_vec_sub2(), which take 2 args (dest==src0)
190
191 ; Revision 1.1  1993/09/16  20:10:24  matt
192 ; Initial revision
193
194 ;
195 ;
196
197 %define NDEBUG
198
199 [BITS 32]
200
201 %ifdef __ENV_LINUX__
202 ; Cater for linux ELF compilers which don't prefix underscores...
203 ; Variables:
204 %define _vmd_zero_vector              vmd_zero_vector
205 %define _vmd_identity_matrix          vmd_identity_matrix
206 ; Functions:
207 %define _vm_vec_add     vm_vec_add
208 %define _vm_vec_sub     vm_vec_sub
209 %define _vm_vec_add2    vm_vec_add2
210 %define _vm_vec_sub2    vm_vec_sub2
211 %define _vm_vec_avg     vm_vec_avg
212 %define _vm_vec_scale   vm_vec_scale
213 %define _vm_vec_copy_scale      vm_vec_copy_scale
214 %define _vm_vec_scale2  vm_vec_scale2
215 %define _vm_vec_scale_add       vm_vec_scale_add
216 %define _vm_vec_scale_add2      vm_vec_scale_add2
217 %define _vm_vec_mag     vm_vec_mag
218 %define _vm_vec_dist    vm_vec_dist
219 %define _vm_vec_mag_quick       vm_vec_mag_quick
220 %define _vm_vec_dist_quick      vm_vec_dist_quick
221 %define _vm_vec_normalize       vm_vec_normalize
222 %define _vm_vec_normalize_quick vm_vec_normalize_quick
223 %define _vm_vec_normalized_dir  vm_vec_normalized_dir
224 %define _vm_vec_normalized_dir_quick    vm_vec_normalized_dir_quick
225 %define _vm_vec_copy_normalize  vm_vec_copy_normalize
226 %define _vm_vec_copy_normalize_quick    vm_vec_copy_normalize_quick
227 %define _vm_vec_dotprod         vm_vec_dotprod
228 %define _vm_vec_crossprod       vm_vec_crossprod
229 %define _vm_vec_perp            vm_vec_perp
230 %define _vm_vec_normal          vm_vec_normal
231 %define _vm_vec_rotate          vm_vec_rotate
232 %define _vm_vec_delta_ang       vm_vec_delta_ang
233 %define _vm_vec_delta_ang_norm  vm_vec_delta_ang_norm
234 %define _vm_vector_2_matrix     vm_vector_2_matrix
235 %define _vm_vec_ang_2_matrix    vm_vec_ang_2_matrix
236 %define _vm_angles_2_matrix             vm_angles_2_matrix
237 %define _vm_transpose_matrix            vm_transpose_matrix
238 %define _vm_copy_transpose_matrix       vm_copy_transpose_matrix
239 %define _vm_matrix_x_matrix             vm_matrix_x_matrix
240 %endif
241
242 [SECTION .data]
243
244 ;temporary vectors for surface normal calculation
245 tempv0  dd 0,0,0
246 tempv1  dd 0,0,0
247
248 xvec    dd 0,0,0
249 yvec    dd 0,0,0
250 zvec    dd 0,0,0
251
252 tempav  dw 0,0,0
253
254 ;sine & cosine values for angles_2_matrix
255 sinp    dd      0
256 cosp    dd      0
257 sinb    dd      0
258 cosb    dd      0
259 sinh    dd      0
260 cosh    dd      0
261
262         global _vmd_zero_vector,_vmd_identity_matrix
263 %define f1_0 10000h
264 ;These should never be changed!
265 _vmd_zero_vector:
266         dd      0,0,0
267
268 _vmd_identity_matrix:
269         dd      f1_0,0,0
270         dd      0,f1_0,0
271         dd      0,0,f1_0
272
273 [SECTION .text]
274         extern quad_sqrt_asm
275         extern fix_sincos_asm
276         extern fix_acos_asm
277         extern long_sqrt_asm
278 ; calling convention is arguments on stack from right to left,
279 ; eax,ecx,edx possibly destroyed, ebx,esi,edi,ebp preserved,
280 ; caller removes arguments.
281         global _vm_vec_add
282         global _vm_vec_sub
283         global _vm_vec_add2
284         global _vm_vec_sub2
285         global _vm_vec_avg
286         global _vm_vec_scale
287         global _vm_vec_copy_scale
288         global _vm_vec_scale2
289         global _vm_vec_scale_add
290         global _vm_vec_scale_add2
291         global _vm_vec_mag
292         global _vm_vec_dist
293         global _vm_vec_mag_quick
294         global _vm_vec_dist_quick
295         global _vm_vec_normalize
296         global _vm_vec_normalize_quick
297         global _vm_vec_normalized_dir
298         global _vm_vec_normalized_dir_quick
299         global _vm_vec_copy_normalize
300         global _vm_vec_copy_normalize_quick
301         global _vm_vec_dotprod
302         global _vm_vec_crossprod
303         global _vm_vec_perp
304         global _vm_vec_normal
305         global _vm_angles_2_matrix
306         global _vm_vec_rotate
307         global _vm_vec_delta_ang
308         global _vm_vec_delta_ang_norm
309         global _vm_transpose_matrix
310         global _vm_copy_transpose_matrix
311         global _vm_matrix_x_matrix
312         global _vm_vector_2_matrix
313         global _vm_vec_ang_2_matrix
314
315 %macro debug_brk 1-*
316 ;int 3
317 %endmacro
318
319 %macro abs_eax 0
320         cdq
321         xor     eax,edx
322         sub     eax,edx
323 %endmacro
324
325 %macro fixmul 1
326         imul %1
327         shrd eax,edx,16
328 %endmacro
329
330 %macro fixdiv 1
331         mov     edx,eax
332         sar     edx,16
333         shl     eax,16
334         idiv    %1
335 %endmacro
336
337 %macro vm_copy 2
338 %assign i 0
339 %rep 3
340         mov     eax,[%2+i]
341         mov     [%1+i],eax
342 %assign i i+4
343 %endrep
344 %endmacro
345
346 ; offsets in fixang struct (packed)
347 %define pitch 0
348 %define bank 2
349 %define head 4
350 ; offsets in matrix
351 %define m1 0*4
352 %define m4 1*4
353 %define m7 2*4
354 %define m2 3*4
355 %define m5 4*4
356 %define m8 5*4
357 %define m3 6*4
358 %define m6 7*4
359 %define m9 8*4
360 ;vector offsets in matrix
361 %define rvec 0*12
362 %define uvec 1*12
363 %define fvec 2*12
364
365 ; vec *vm_vec_add(vec *dest, vec *src1, vec *src2);
366 ; returns dest
367 ; dest=src1+src2
368 _vm_vec_add:
369         push ebx
370         mov eax,[esp+8]
371         mov ecx,[esp+12]
372         mov edx,[esp+16]
373 %assign i 0
374 %rep 3
375         mov ebx,[ecx+i]
376         add ebx,[edx+i]
377         mov [eax+i],ebx
378 %assign i i+4
379 %endrep
380         pop ebx
381         ret
382
383 ; vec *vm_vec_sub(vec *dest, vec *src1, vec *src2);
384 ; returns dest
385 ; dest=src1-src2
386 _vm_vec_sub:
387         push ebx
388         mov eax,[esp+8]
389         mov ecx,[esp+12]
390         mov edx,[esp+16]
391 %assign i 0
392 %rep 3
393         mov ebx,[ecx+i]
394         sub ebx,[edx+i]
395         mov [eax+i],ebx
396 %assign i i+4
397 %endrep
398         pop ebx
399         ret
400
401 ; vec *vm_vec_add2(vec *dest, vec *src);
402 ; returns dest
403 ; dest+=src
404 _vm_vec_add2:
405         mov eax,[esp+4]
406         mov ecx,[esp+8]
407 %assign i 0
408 %rep 3
409         mov edx,[ecx+i]
410         add [eax+i],edx
411 %assign i i+4
412 %endrep
413         ret
414
415 ; vec *vm_vec_sub2(vec *dest, vec *src);
416 ; returns dest
417 ; dest-=src
418 _vm_vec_sub2:
419         mov eax,[esp+4]
420         mov ecx,[esp+8]
421 %assign i 0
422 %rep 3
423         mov edx,[ecx+i]
424         sub [eax+i],edx
425 %assign i i+4
426 %endrep
427         ret
428
429 ; vec *vm_vec_avg(vec *dest, vec *src1, vec *src2);
430 ; returns dest
431 ; dest=(src1+src2)/2
432 _vm_vec_avg:
433         push ebx
434         mov eax,[esp+8]
435         mov ecx,[esp+12]
436         mov edx,[esp+16]
437 %assign i 0
438 %rep 3
439         mov ebx,[ecx+i]
440         add ebx,[edx+i]
441         sar ebx,1
442         mov [eax+i],ebx
443 %assign i i+4
444 %endrep
445         pop ebx
446         ret
447
448 ; vec *vm_vec_scale(vec *dest, fix scale);
449 ; returns dest
450 ; dest*=scale
451 _vm_vec_scale:
452         push ebx
453         mov ebx,[esp+8]
454         mov ecx,[esp+12]
455 %assign i 0
456 %rep 3
457         mov eax,[ebx+i]
458         fixmul ecx
459         mov [ebx+i],eax
460 %assign i i+4
461 %endrep
462         mov eax,ebx
463         pop ebx
464         ret
465
466 ; vec *vm_vec_copy_scale(vec *dest, vec *src, fix scale);
467 ; returns dest
468 ; dest=src*scale
469 _vm_vec_copy_scale:
470         push ebx
471         push edi
472         mov edi,[esp+12]
473         mov ebx,[esp+16]
474         mov ecx,[esp+20]
475 %assign i 0
476 %rep 3
477         mov eax,[ebx+i]
478         fixmul ecx
479         mov [edi+i],eax
480 %assign i i+4
481 %endrep
482         mov eax,edi
483         pop edi
484         pop ebx
485         ret
486
487 ; vec *vm_vec_scale_add(vec *dest, vec *src1, vec *src2, fix scale);
488 ; returns dest
489 ; dest=src1+src2*scale
490 _vm_vec_scale_add:
491         push ebx
492         push esi
493         push edi
494         mov edi,[esp+16]
495         mov ebx,[esp+20]
496         mov esi,[esp+24]
497         mov ecx,[esp+28]
498 %assign i 0
499 %rep 3
500         mov eax,[esi+i]
501         fixmul ecx
502         add eax,[ebx+i]
503         mov [edi+i],eax
504 %assign i i+4
505 %endrep
506         mov eax,edi
507         pop edi
508         pop esi
509         pop ebx
510         ret
511
512 ; vec *vm_vec_scale_add2(vec *dest, vec *src, fix scale);
513 ; returns dest
514 ; dest+=src*scale
515 _vm_vec_scale_add2:
516         push ebx
517         push edi
518         mov edi,[esp+12]
519         mov ebx,[esp+16]
520         mov ecx,[esp+20]
521 %assign i 0
522 %rep 3
523         mov eax,[ebx+i]
524         fixmul ecx
525         add [edi+i],eax
526 %assign i i+4
527 %endrep
528         mov eax,edi
529         pop edi
530         pop ebx
531         ret
532
533 ; vec *vm_vec_scale2(vec *dest, fix n, fix d);
534 ; returns dest
535 ; dest*=n/d
536 ;_vm_vec_scale2:
537 ;       push ebx
538 ;       push edi
539 ;       mov edi,[esp+12]
540 ;       mov ebx,[esp+16]
541 ;       mov ecx,[esp+20]
542 ;       or ecx,ecx
543 ;       je no_scale2
544 ;%assign i 0
545 ;%rep 3
546 ;       mov eax,[edi+i]
547 ;       imul ebx
548 ;       idiv ecx
549 ;       mov [edi+i],eax
550 ;%assign i i+4
551 ;%endrep
552 ;no_scale2:
553 ;       mov eax,edi
554 ;       pop edi
555 ;       pop ebx
556 ;        ret
557
558 ;compute magnitude of vector. takes esi=vector, returns eax=mag
559 _vm_vec_mag:
560         push    ebx
561         push    esi
562         mov     esi,[esp+12]
563
564         mov     eax,[esi]
565         imul    eax
566         mov     ebx,eax
567         mov     ecx,edx
568
569         mov     eax,[esi+4]
570         imul    eax
571         add     ebx,eax
572         adc     ecx,edx
573
574         mov     eax,[esi+8]
575         imul    eax
576         add     eax,ebx
577         adc     edx,ecx
578
579         call    quad_sqrt_asm
580
581         pop     esi
582         pop     ebx
583         ret
584
585 ;compute the distance between two points. (does sub and mag)
586 _vm_vec_dist:
587         push ebx
588         push esi
589         push edi
590         mov esi,[esp+16]
591         mov edi,[esp+20]
592         mov eax,[esi]
593         sub eax,[edi]
594         imul eax
595         mov ebx,eax
596         mov ecx,edx
597         mov eax,[esi+4]
598         sub eax,[edi+4]
599         imul eax
600         add ebx,eax
601         adc ecx,edx
602         mov eax,[esi+8]
603         sub eax,[edi+8]
604         imul eax
605         add eax,ebx
606         adc edx,ecx
607         call quad_sqrt_asm ; asm version, takes eax,edx
608         pop edi
609         pop esi
610         pop ebx
611         ret
612
613
614 ;computes an approximation of the magnitude of a vector
615 ;uses dist = largest + next_largest*3/8 + smallest*3/16
616         align 4
617 _vm_vec_mag_quick:
618         push    ebx
619         push    esi
620         mov     esi,[esp+12]
621         mov     eax,[esi]
622         or      eax,eax
623         jns     eax_ok2
624         neg     eax
625 eax_ok2:
626
627         mov     ebx,[esi+4]
628         or      ebx,ebx
629         jns     ebx_ok2
630         neg     ebx
631 ebx_ok2:
632
633         mov     ecx,[esi+8]
634         or      ecx,ecx
635         jns     ecx_ok2
636         neg     ecx
637 ecx_ok2:
638
639 mag_quick_eax_ebx_ecx:
640
641         cmp     eax,ebx
642         jg      no_swap_ab
643         xchg    eax,ebx
644 no_swap_ab:     cmp     ebx,ecx
645         jg      do_add
646         xchg    ebx,ecx
647         cmp     eax,ebx
648         jg      do_add
649         xchg    eax,ebx
650
651 do_add: sar     ebx,2   ;    b*1/4
652         sar     ecx,3   ;            c*1/8
653         add     ebx,ecx ;    b*1/4 + c*1/8
654         add     eax,ebx ;a + b*1/4 + c*1/8
655         sar     ebx,1   ;    b*1/8 + c*1/16
656         add     eax,ebx ;a + b*3/4 + c*3/16
657
658         pop     esi
659         pop     ebx
660         ret
661
662
663 ;computes an approximation of the distance between two points.
664 ;uses dist = largest + next_largest*3/8 + smallest*3/16
665         align   4
666 _vm_vec_dist_quick:
667         push    ebx
668         push    esi
669         push    edi
670
671         mov     esi,[esp+16]
672         mov     edi,[esp+20]
673
674         mov     ebx,[esi]
675         sub     ebx,[edi]
676         jns     ebx_ok
677         neg     ebx
678 ebx_ok:
679
680         mov     ecx,[esi+4]
681         sub     ecx,[edi+4]
682         jns     ecx_ok
683         neg     ecx
684 ecx_ok:
685         mov     eax,[esi+8]
686         sub     eax,[edi+8]
687         jns     eax_ok
688         neg     eax
689 eax_ok:
690         pop     edi
691         jmp     mag_quick_eax_ebx_ecx
692
693
694 ;return the normalized direction vector between two points
695 ;dest = normalized(end - start).
696 ;takes edi=dest, esi=endpoint, ebx=startpoint.  Returns mag of dir vec
697 ;NOTE: the order of the parameters matches the vector subtraction
698 _vm_vec_normalized_dir:
699         push    ebx
700         push    esi
701         push    edi
702         push    ebp
703         mov     edi,[esp+20]
704         mov     esi,[esp+24]
705         mov     ebp,[esp+28]
706
707         mov     eax,[esi]
708         sub     eax,[ebp]
709         mov     [edi],eax
710         imul    eax
711         mov     ebx,eax
712         mov     ecx,edx
713
714         mov     eax,[esi+4]
715         sub     eax,[ebp+4]
716         mov     [edi+4],eax
717         imul    eax
718         add     ebx,eax
719         adc     ecx,edx
720
721         mov     eax,[esi+8]
722         sub     eax,[ebp+8]
723         mov     [edi+8],eax
724         imul    eax
725         add     eax,ebx
726         adc     edx,ecx
727
728         call    quad_sqrt_asm
729
730         mov     ecx,eax ;mag in ecx
731         jecxz   no_div2
732
733 %assign i 0
734 %rep 3
735         mov eax,[edi+i]
736         fixdiv ecx
737         mov [edi+i],eax
738 %assign i i+4
739 %endrep
740 no_div2:
741         mov     eax,ecx
742         pop     ebp
743         pop     edi
744         pop     esi
745         pop     ebx
746         ret
747
748
749 ;normalize a vector in place.
750 ;returns mag(!)
751 _vm_vec_normalize:
752         push    ebx
753         push    esi
754         push    edi
755         mov     edi,[esp+16]
756         mov     esi,edi
757         jmp     vm_vec_copy_normalize_nopar
758
759 ;normalize a vector.  takes edi=dest, esi=vector
760 ;returns ecx=mag of source vec
761 _vm_vec_copy_normalize:
762         push    ebx
763         push    esi
764         push    edi
765         mov     edi,[esp+16]
766         mov     esi,[esp+20]
767 vm_vec_copy_normalize_nopar:
768
769         mov     eax,[esi]
770         imul    eax
771         mov     ebx,eax
772         mov     ecx,edx
773
774         mov     eax,[esi+4]
775         imul    eax
776         add     ebx,eax
777         adc     ecx,edx
778
779         mov     eax,[esi+8]
780         imul    eax
781         add     eax,ebx
782         adc     edx,ecx
783
784         call    quad_sqrt_asm
785
786         mov     ecx,eax ;mag in ecx
787         jecxz   no_div
788
789 %assign i 0
790 %rep 3
791         mov eax,[esi+i]
792         fixdiv ecx
793         mov [edi+i],eax
794 %assign i i+4
795 %endrep
796 no_div:
797         mov     eax,ecx
798         pop     edi
799         pop     esi
800         pop     ebx
801         ret
802
803
804 ;normalize a vector in place.
805 ;uses approx. dist
806 _vm_vec_normalize_quick:
807         push    esi
808         push    edi
809         mov     edi,[esp+12]
810         mov     esi,edi
811         jmp     vm_vec_copy_normalize_quick_nopar
812
813 ;save as vm_vec_normalized_dir, but with quick sqrt
814 ;takes dest, endpoint, startpoint.  Returns mag of dir vec
815 _vm_vec_normalized_dir_quick:
816         push    esi
817         push    edi
818         mov     edi,[esp+12]
819         mov     esi,[esp+16]
820         mov     edx,[esp+20]
821 %assign i 0
822 %rep 3
823         mov eax,[esi+i]
824         sub eax,[edx+i]
825         mov [edi+i],eax
826 %assign i i+4
827 %endrep
828         mov     esi,edi
829         jmp     vm_vec_copy_normalize_quick_nopar
830
831 ;normalize a vector.
832 ;uses approx. dist
833 _vm_vec_copy_normalize_quick:
834         push    esi
835         push    edi
836
837         mov     edi,[esp+12]
838         mov     esi,[esp+16]
839 vm_vec_copy_normalize_quick_nopar:
840         push    esi
841         call    _vm_vec_mag_quick
842         pop     ecx     ;remove par
843
844         mov     ecx,eax ;mag in ecx
845         jecxz   no_div_q
846
847 %assign i 0
848 %rep 3
849         mov eax,[esi+i]
850         fixdiv ecx
851         mov [edi+i],eax
852 %assign i i+4
853 %endrep
854
855 no_div_q:
856         mov eax,ecx
857         pop edi
858         pop esi
859         ret
860
861
862 ;compute dot product of two vectors. takes esi,edi=vectors, returns eax=dotprod
863 _vm_vec_dotprod:
864         push    ebx
865         push    esi
866         push    edi
867         mov     esi,[esp+16]
868         mov     edi,[esp+20]
869
870         mov     eax,[esi]
871         imul    dword [edi]
872         mov     ebx,eax
873         mov     ecx,edx
874
875         mov     eax,[esi+4]
876         imul    dword [edi+4]
877         add     ebx,eax
878         adc     ecx,edx
879
880         mov     eax,[esi+8]
881         imul    dword [edi+8]
882         add     eax,ebx
883         adc     edx,ecx
884
885         shrd    eax,edx,16
886
887         ;ifndef NDEBUG  ;check for overflow
888         ;always do overflow check, and return saturated value
889         sar     edx,16  ;get real sign from high word
890         mov     ebx,edx
891         cdq             ;get sign of our result 
892         cmp     bx,dx   ;same sign?
893         je      no_oflow
894         ;;debug_brk     'overflow in vm_vec_dotprod'
895         mov     eax,7fffffffh
896         or      ebx,ebx ;check desired sign
897         jns     no_oflow
898         neg     eax
899 no_oflow:
900         ;endif
901         pop     edi
902         pop     esi
903         pop     ebx
904         ret
905
906
907 ;computes cross product of two vectors.
908 ;Note: this magnitude of the resultant vector is the
909 ;product of the magnitudes of the two source vectors.  This means it is
910 ;quite easy for this routine to overflow and underflow.  Be careful that
911 ;your inputs are ok.
912 ; takes dest, src vectors
913 ; returns dest
914 _vm_vec_crossprod:
915         push    ebx
916         push    esi
917         push    edi
918         push    ebp
919         mov     ebp,[esp+20]
920         mov     esi,[esp+24]
921         mov     edi,[esp+28]
922         %ifndef  NDEBUG
923          cmp    ebp,esi
924          break_if       e,'crossprod: dest==src0'
925          cmp    ebp,edi
926          break_if       e,'crossprod: dest==src1'
927         %endif
928
929         mov     eax,[edi+4]
930         imul    dword [esi+8]
931         mov     ebx,eax
932         mov     ecx,edx
933         mov     eax,[edi+8]
934         imul    dword [esi+4]
935         sub     eax,ebx
936         sbb     edx,ecx
937         shrd    eax,edx,16
938         %ifndef  NDEBUG  ;check for overflow
939          mov    ebx,edx ;save
940          cdq            ;get sign of result
941          shr    ebx,16  ;get high 16 of quad result
942          cmp    dx,bx   ;sign extension the same?
943          break_if       ne,'overflow in crossprod'
944         %endif
945         mov     [ebp],eax
946
947         mov     eax,[edi+8]
948         imul    dword [esi]
949         mov     ebx,eax
950         mov     ecx,edx
951         mov     eax,[edi]
952         imul    dword [esi+8]
953         sub     eax,ebx
954         sbb     edx,ecx
955         shrd    eax,edx,16
956         %ifndef  NDEBUG  ;check for overflow
957          mov    ebx,edx ;save
958          cdq            ;get sign of result
959          shr    ebx,16  ;get high 16 of quad result
960          cmp    dx,bx   ;sign extension the same?
961          break_if       ne,'overflow in crossprod'
962         %endif
963         mov     [ebp+4],eax
964
965         mov     eax,[edi]
966         imul    dword [esi+4]
967         mov     ebx,eax
968         mov     ecx,edx
969         mov     eax,[edi+4]
970         imul    dword [esi]
971         sub     eax,ebx
972         sbb     edx,ecx
973         shrd    eax,edx,16
974         %ifndef  NDEBUG  ;check for overflow
975          mov    ebx,edx ;save
976          cdq            ;get sign of result
977          shr    ebx,16  ;get high 16 of quad result
978          cmp    dx,bx   ;sign extension the same?
979          break_if       ne,'overflow in crossprod'
980         %endif
981         mov     [ebp+8],eax
982
983         mov     eax,ebp ;return dest in eax
984
985         pop     ebp
986         pop     edi
987         pop     esi
988         pop     ebx
989         ret
990
991
992 ;computes surface normal from three points. takes ebx=dest, eax,esi,edi=vecs
993 ;returns eax=dest. Result vector is normalized.
994 _vm_vec_normal:
995         push    dword [esp+16+00];src2
996         push    dword [esp+12+04];src1
997         push    dword [esp+08+08];src0
998         push    dword [esp+04+12];dest
999         call    _vm_vec_perp     ;get unnormalized
1000         add     esp,16
1001         push    eax              ;dest
1002         call    _vm_vec_normalize
1003         pop     eax
1004         ret
1005
1006
1007 ;make sure a vector is reasonably sized to go into a cross product
1008 ;takes vector in esi
1009 ;trashes eax,ebx,cl,edx
1010 check_vec:
1011         mov     eax,[esi]
1012         abs_eax
1013         mov     ebx,eax
1014         mov     eax,[esi+4]
1015         abs_eax
1016         or      ebx,eax
1017         mov     eax,[esi+8]
1018         abs_eax
1019         or      ebx,eax
1020         jz      null_vector
1021
1022         xor     cl,cl   ;init shift count
1023
1024         test    ebx,0fffc0000h  ;too big
1025         jz      not_too_big
1026 check_4_down:   test    ebx,000f00000h
1027         jz      check_2_down
1028         add     cl,4
1029         sar     ebx,4
1030         jmp     check_4_down
1031 check_2_down:   test    ebx,0fffc0000h
1032         jz      not_2_down
1033         add     cl,2
1034         sar     ebx,2
1035         jmp     check_2_down
1036 not_2_down:
1037         sar     dword [esi],cl
1038         sar     dword [esi+4],cl
1039         sar     dword [esi+8],cl
1040         ret
1041
1042 ;maybe too small...
1043 not_too_big:    test    ebx,0ffff8000h
1044         jnz     not_too_small
1045 check_4_up:     test    ebx,0fffff000h
1046         jnz     check_2_up
1047         add     cl,4
1048         sal     ebx,4
1049         jmp     check_4_up
1050 check_2_up:     test    ebx,0ffff8000h
1051         jnz     not_2_up
1052         add     cl,2
1053         sal     ebx,2
1054         jmp     check_2_up
1055 not_2_up:
1056         sal     dword [esi],cl
1057         sal     dword [esi+4],cl
1058         sal     dword [esi+8],cl
1059
1060 not_too_small:  ret
1061
1062 null_vector:
1063 ; debug_brk commented out by mk on 05/04/94
1064 ;**     debug_brk       "null vector in check_vec"
1065         ret
1066
1067
1068 ;computes surface normal from three points. takes ebx=dest, eax,esi,edi=vecs
1069 ;returns eax=dest. Result vector is NOT normalized, but this routine does
1070 ;make an effort that cross product does not overflow or underflow  
1071 _vm_vec_perp:
1072         push    ebx
1073         push    esi
1074         push    edi
1075         ; skip dest
1076         mov     ebx,[esp+20] ;src0
1077         mov     ecx,[esp+24] ;src1
1078         mov     edx,[esp+28] ;src2
1079
1080         mov     esi,tempv0
1081         mov     edi,tempv1
1082 %assign i 0 ;tempv1=src2-src1
1083 %rep 3
1084         mov     eax,[edx+i]
1085         sub     eax,[ecx+i]
1086         mov     [edi+i],eax
1087 %assign i i+4
1088 %endrep
1089 %assign i 0 ;tempv0=src1-src0
1090 %rep 3
1091         mov     eax,[ecx+i]
1092         sub     eax,[ebx+i]
1093         mov     [esi+i],eax
1094 %assign i i+4
1095 %endrep
1096         ; esi=tempv0, edi=tempv1
1097         call    check_vec       ;make sure reasonable value
1098         xchg    esi,edi
1099         call    check_vec       ;make sure reasonable value
1100         ; edi=tempv0, esi=tempv1
1101         push    esi              ;tempv1
1102         push    edi              ;tempv0
1103         push    dword [esp+16+8] ;dest
1104         call    _vm_vec_crossprod
1105         add     esp,12
1106         ; eax=dest
1107         pop     edi
1108         pop     esi
1109         pop     ebx
1110         ret
1111
1112
1113 ;compute a rotation matrix from three angles. takes edi=dest matrix,
1114 ;esi=angles vector.  returns dest matrix.
1115 _vm_angles_2_matrix:
1116         push    ebx
1117         push    esi
1118         push    edi
1119         mov     edi,[esp+16];dest
1120         mov     esi,[esp+20];angles
1121
1122 ;get sines & cosines
1123         mov     ax,[esi+pitch]
1124         call    fix_sincos_asm
1125         mov     [sinp],eax
1126         mov     [cosp],ebx
1127
1128         mov     ax,[esi+bank]
1129         call    fix_sincos_asm
1130         mov     [sinb],eax
1131         mov     [cosb],ebx
1132
1133         mov     ax,[esi+head]
1134         call    fix_sincos_asm
1135         mov     [sinh],eax
1136         mov     [cosh],ebx
1137
1138 ;alternate entry point with sines & cosines already computed.  
1139 ;Note all the registers already pushed.
1140 sincos_2_matrix:
1141
1142 ;now calculate the 9 elements
1143
1144         mov     eax,[sinb]
1145         fixmul  dword [sinh]
1146         mov     ecx,eax ;save sbsh
1147         fixmul  dword [sinp]
1148         mov     ebx,eax
1149         mov     eax,[cosb]
1150         fixmul  dword [cosh]
1151         mov     esi,eax ;save cbch
1152         add     eax,ebx
1153         mov     [edi+m1],eax    ;m1=cbch+sbspsh
1154
1155         mov     eax,esi ;get cbch
1156         fixmul  dword [sinp]
1157         add     eax,ecx ;add sbsh
1158         mov     [edi+m8],eax    ;m8=sbsh+cbchsp
1159
1160
1161         mov     eax,[cosb]
1162         fixmul  dword [sinh]
1163         mov     ecx,eax ;save cbsh
1164         fixmul  dword [sinp]
1165         mov     ebx,eax
1166         mov     eax,[sinb]
1167         fixmul  dword [cosh]
1168         mov     esi,eax ;save sbch
1169         sub     ebx,eax
1170         mov     [edi+m2],ebx    ;m2=cbshsp-sbch
1171
1172         mov     eax,esi ;get sbch
1173         fixmul  dword [sinp]
1174         sub     eax,ecx ;sub from cbsh
1175         mov     [edi+m7],eax    ;m7=sbchsp-cbsh
1176
1177
1178         mov     eax,[sinh]
1179         fixmul  dword [cosp]
1180         mov     [edi+m3],eax    ;m3=shcp
1181
1182         mov     eax,[sinb]
1183         fixmul  dword [cosp]
1184         mov     [edi+m4],eax    ;m4=sbcp
1185
1186         mov     eax,[cosb]
1187         fixmul  dword [cosp]
1188         mov     [edi+m5],eax    ;m5=cbcp
1189
1190         mov     eax,[sinp]
1191         neg     eax
1192         mov     [edi+m6],eax    ;m6=-sp
1193
1194         mov     eax,[cosh]
1195         fixmul  dword [cosp]
1196         mov     [edi+m9],eax    ;m9=chcp
1197
1198         mov     eax,edi
1199         pop     edi
1200         pop     esi
1201         pop     ebx
1202         ret
1203
1204 %macro m2m 2
1205         mov eax,%2
1206         mov %1,eax
1207 %endmacro
1208
1209 %macro m2m_neg 2
1210         mov eax,%2
1211         neg eax
1212         mov %1,eax
1213 %endmacro
1214
1215 ;create a rotation matrix from one or two vectors. 
1216 ;requires forward vec, and assumes zero bank if up & right vecs==NULL
1217 ;up/right vector need not be exactly perpendicular to forward vec
1218 ;takes edi=matrix, esi=forward vec, eax=up vec, ebx=right vec. 
1219 ;returns edi=matrix.  trashes eax,ebx,esi
1220 ;Note: this routine loses precision as the forward vector approaches 
1221 ;straigt up or down (I think)
1222 _vm_vector_2_matrix:
1223         push    ebx
1224         push    esi
1225         push    edi
1226         mov     edi,[esp+16]
1227         mov     esi,[esp+20];fvec
1228         mov     eax,[esp+24];uvec
1229         mov     ebx,[esp+28];rvec
1230
1231         %ifndef  NDEBUG
1232          or     esi,esi
1233          break_if       z,"vm_vector_2_matrix: forward vec cannot be NULL!"
1234         %endif
1235
1236         or      eax,eax ;up vector present?
1237         jnz     near use_up_vec      ;..yep
1238
1239         or      ebx,ebx ;right vector present?
1240         jz      near just_forward_vec        ;..nope
1241 ;use_right_vec
1242         push    edi     ;save matrix
1243
1244         push    esi
1245         push    dword zvec
1246         call    _vm_vec_copy_normalize
1247         add     esp,8
1248         or      eax,eax
1249         jz      near bad_vector3
1250
1251         push    ebx
1252         push    dword xvec
1253         call    _vm_vec_copy_normalize
1254         add     esp,8
1255         or      eax,eax
1256         jz      bad_vector2
1257
1258         push    dword xvec;src1
1259         push    dword zvec;src0
1260         push    dword yvec;dest
1261         call    _vm_vec_crossprod        ;get y = z cross x
1262         add     esp,12
1263
1264 ;normalize new perpendicular vector
1265         push    eax ;get new vec (up) in esi
1266         call    _vm_vec_normalize
1267         pop     ecx
1268         or      eax,eax
1269         jz      bad_vector2
1270
1271 ;now recompute right vector, in case it wasn't entirely perpendiclar
1272
1273         push    dword zvec;src1
1274         push    dword yvec;src0
1275         push    dword xvec;dest
1276         call    _vm_vec_crossprod        ;x = y cross z
1277         add     esp,12
1278
1279         pop     edi     ;get matrix back
1280
1281         jmp     copy_into_matrix
1282
1283
1284 ;one of the non-forward vectors caused a problem, so ignore them and
1285 ;use just the forward vector
1286 bad_vector2:
1287         pop     edi
1288         lea     esi,[edi+fvec]
1289         vm_copy esi,zvec
1290         jmp     just_forward_vec_norm
1291
1292 ;use forward and up vectors
1293 use_up_vec:
1294         push    edi     ;save matrix
1295
1296         push    eax
1297         push    dword yvec
1298         call    _vm_vec_copy_normalize
1299         add     esp,8
1300         or      eax,eax
1301         jz      bad_vector2
1302
1303         push    esi
1304         push    dword zvec
1305         call    _vm_vec_copy_normalize
1306         add     esp,8
1307         or      eax,eax
1308         jz      near bad_vector3
1309
1310         push    dword zvec;src1
1311         push    dword yvec;src0
1312         push    dword xvec;dest
1313         call    _vm_vec_crossprod        ;get x = y cross z
1314         add     esp,12
1315
1316 ;normalize new perpendicular vector
1317         push    eax ;get new vec (up) in esi
1318         call    _vm_vec_normalize
1319         pop     ecx
1320         or      eax,eax
1321         jz      bad_vector2
1322
1323 ;now recompute right vector, in case it wasn't entirely perpendiclar
1324
1325         push    dword xvec;src1
1326         push    dword zvec;src0
1327         push    dword yvec;dest
1328         call    _vm_vec_crossprod        ;y = z cross x
1329         add     esp,12
1330
1331         pop     edi     ;get matrix back
1332
1333 copy_into_matrix:
1334         vm_copy edi+rvec,xvec
1335         vm_copy edi+uvec,yvec
1336         vm_copy edi+fvec,zvec
1337         mov     eax,edi
1338         pop     edi
1339         pop     esi
1340         pop     ebx
1341         ret
1342
1343 bad_vector3:
1344         pop     edi
1345 bad_vector:
1346         mov     eax,edi
1347         pop     edi
1348         pop     esi
1349         pop     ebx
1350         debug_brk       '0-len vec in vec_2_mat'
1351         ret
1352
1353 ;only the forward vector is present
1354 just_forward_vec:
1355         push    esi
1356         lea     esi,[edi+fvec]
1357         push    esi
1358         call    _vm_vec_copy_normalize
1359         add     esp,8
1360         or      eax,eax
1361         jz      bad_vector
1362 just_forward_vec_norm:
1363
1364         mov     eax,[esi]
1365         or      eax,[esi+8]     ;check both x & z == 0
1366         jnz     not_up
1367
1368 ;forward vector is straight up (or down)
1369
1370         mov     dword [edi+m1],f1_0
1371         mov     eax,[esi+4]     ;get y componant
1372         cdq             ;get y sign
1373         mov     eax,-f1_0
1374         xor     eax,edx
1375         sub     eax,edx ;make sign correct
1376         mov     [edi+m8],eax
1377         xor     eax,eax
1378         mov     [edi+m4],eax
1379         mov     [edi+m7],eax
1380         mov     [edi+m2],eax
1381         mov     [edi+m5],eax
1382         jmp     done_v2m
1383
1384 not_up:
1385         m2m     [edi+0],[esi+8]
1386         mov     dword [edi+4],0
1387         m2m_neg [edi+8],[esi+0]
1388         push    edi
1389         call    _vm_vec_normalize
1390         pop     ecx
1391
1392         lea     eax,[edi+uvec]
1393         push    edi             ;scr1 = x
1394         push    esi             ;src0 = z
1395         push    eax             ;dest = y
1396         call    _vm_vec_crossprod
1397         add     esp,12
1398
1399 done_v2m:
1400         mov     eax,edi
1401         pop     edi
1402         pop     esi
1403         pop     ebx
1404         ret
1405
1406
1407 ;multiply (dot) two vectors. assumes dest ptr in ebp, src pointers in esi,edi.
1408 ;trashes ebx,ecx,edx
1409 %macro vv_mul  7
1410 ;        1    2  3  4  5  6  7
1411 ;macro   dest,x0,y0,z0,x1,y1,z1
1412         mov     eax,[esi+%2]
1413         imul    dword [edi+%5]
1414         mov     ebx,eax
1415         mov     ecx,edx
1416
1417         mov     eax,[esi+%3]
1418         imul    dword [edi+%6]
1419         add     ebx,eax
1420         adc     ecx,edx
1421
1422         mov     eax,[esi+%4]
1423         imul    dword [edi+%7]
1424         add     ebx,eax
1425         adc     ecx,edx
1426
1427         shrd    ebx,ecx,16      ;fixup ebx
1428         mov     [ebp+%1],ebx
1429
1430 %endmacro
1431
1432 ;rotate a vector by a rotation matrix
1433 ;eax=dest vector, esi=src vector, edi=matrix. returns eax=dest vector
1434 _vm_vec_rotate:
1435         %ifndef  NDEBUG
1436          cmp    eax,esi
1437          break_if       e,'vec_rotate: dest==src'
1438         %endif
1439         push    ebx
1440         push    esi
1441         push    edi
1442         push    ebp
1443         mov     ebp,[esp+20];dest vec
1444         mov     esi,[esp+24];src vec
1445         mov     edi,[esp+28];matrix
1446
1447 ;compute x
1448         vv_mul  0, 0,4,8, m1,m4,m7
1449         vv_mul  4, 0,4,8, m2,m5,m8
1450         vv_mul  8, 0,4,8, m3,m6,m9
1451
1452         mov     eax,ebp ;return eax=dest
1453         pop     ebp
1454         pop     edi
1455         pop     esi
1456         pop     ebx
1457         ret
1458
1459
1460 ;transpose a matrix in place.  Takes matrix. returns matrix
1461 _vm_transpose_matrix:
1462         mov     ecx,[esp+4]
1463
1464         mov     eax,[ecx+m2]
1465         xchg    eax,[ecx+m4]
1466         mov     [ecx+m2],eax
1467
1468         mov     eax,[ecx+m3]
1469         xchg    eax,[ecx+m7]
1470         mov     [ecx+m3],eax
1471
1472         mov     eax,[ecx+m6]
1473         xchg    eax,[ecx+m8]
1474         mov     [ecx+m6],eax
1475         mov     eax,ecx
1476         ret
1477
1478
1479
1480 ;copy and transpose a matrix.  Takes edi=dest, esi=src. returns edi=dest
1481 _vm_copy_transpose_matrix:
1482         mov     edx,[esp+4];dest
1483         mov     ecx,[esp+8];src
1484
1485         mov     eax,[ecx+m1]
1486         mov     [edx+m1],eax
1487
1488         mov     eax,[ecx+m2]
1489         mov     [edx+m4],eax
1490
1491         mov     eax,[ecx+m3]
1492         mov     [edx+m7],eax
1493
1494         mov     eax,[ecx+m4]
1495         mov     [edx+m2],eax
1496
1497         mov     eax,[ecx+m5]
1498         mov     [edx+m5],eax
1499
1500         mov     eax,[ecx+m6]
1501         mov     [edx+m8],eax
1502
1503         mov     eax,[ecx+m7]
1504         mov     [edx+m3],eax
1505
1506         mov     eax,[ecx+m8]
1507         mov     [edx+m6],eax
1508
1509         mov     eax,[ecx+m9]
1510         mov     [edx+m9],eax
1511         mov     eax,edx
1512         ret
1513
1514
1515
1516 ;mulitply 2 matrices, fill in dest.  returns ptr to dest
1517 ;takes dest, src0, scr1
1518 _vm_matrix_x_matrix:
1519         %ifndef  NDEBUG
1520          cmp    eax,esi
1521          break_if       e,'matrix_x_matrix: dest==src0'
1522          cmp    eax,edi
1523          break_if       e,'matrix_x_matrix: dest==src1'
1524         %endif
1525         push    ebx
1526         push    esi
1527         push    edi
1528         push    ebp
1529         mov     ebp,[esp+20] ;ebp=dest
1530         mov     esi,[esp+24] ;esi=src0
1531         mov     edi,[esp+28] ;edi=src1
1532
1533 ;;This code would do the same as the nine lines below it, but I'm sure
1534 ;;Mike would disapprove
1535 ;;      for     s0,<<m1,m2,m3>,<m4,m5,m6>,<m7,m8,m9>>
1536 ;;       for    s1,<<m1,m4,m7>,<m2,m5,m8>,<m3,m6,m9>>
1537 ;;        vv_mul        @ArgI(1,s0)+@ArgI(1,s1), s0, s1
1538 ;;       endm
1539 ;;      endm
1540
1541         vv_mul  m1, m1,m2,m3, m1,m4,m7
1542         vv_mul  m2, m1,m2,m3, m2,m5,m8
1543         vv_mul  m3, m1,m2,m3, m3,m6,m9
1544
1545         vv_mul  m4, m4,m5,m6, m1,m4,m7
1546         vv_mul  m5, m4,m5,m6, m2,m5,m8
1547         vv_mul  m6, m4,m5,m6, m3,m6,m9
1548
1549         vv_mul  m7, m7,m8,m9, m1,m4,m7
1550         vv_mul  m8, m7,m8,m9, m2,m5,m8
1551         vv_mul  m9, m7,m8,m9, m3,m6,m9
1552
1553         mov     eax,ebp ;eax=ptr to dest
1554         pop     ebp
1555         pop     edi
1556         pop     esi
1557         pop     ebx
1558         ret
1559
1560 ;computes the delta angle between two vectors
1561 ;two entry points: normalized and non-normalized vectors
1562 ;takes esi,edi=vectors, eax=optional forward vector
1563 ;returns ax=delta angle
1564 ;if the forward vector is NULL, the absolute values of the delta angle
1565 ;is returned.  If it is specified, the rotation around that vector from
1566 ;esi to edi is returned. 
1567
1568 _vm_vec_delta_ang:
1569         push    ebx
1570         push    esi
1571         push    edi
1572         mov     esi,[esp+16]
1573         mov     edi,[esp+20]
1574
1575         push    esi
1576         call    _vm_vec_normalize
1577         pop     ecx
1578         push    edi
1579         call    _vm_vec_normalize
1580         pop     ecx
1581         jmp     do_vda_dot
1582
1583 _vm_vec_delta_ang_norm:
1584         push    ebx
1585         push    esi
1586         push    edi
1587         mov     esi,[esp+16]
1588         mov     edi,[esp+20]
1589 do_vda_dot:
1590         push    edi
1591         push    esi
1592         call    _vm_vec_dotprod
1593         add     esp,8
1594         call    fix_acos_asm    ;now angle in ax
1595         mov     ebx,[esp+24]    ;get forward vec
1596         or      ebx,ebx ;null?
1597         jz      done_vda        ;..yes
1598 ;do cross product to find sign of angle
1599         push    eax     ;save angle
1600         ;esi,edi still set
1601         push    edi;src1
1602         push    esi;src0
1603         push    dword tempv0      ;new vec
1604         call    _vm_vec_crossprod
1605         add     esp,12
1606         push    ebx     ;forward vec
1607         push    eax     ;new vector
1608         call    _vm_vec_dotprod  ;eax=dotprod
1609         add     esp,8
1610
1611         cdq             ;get sign
1612         pop     eax     ;get angle
1613         xor     eax,edx
1614         sub     eax,edx ;make sign correct
1615 done_vda:
1616         pop     edi
1617         pop     esi
1618         pop     ebx
1619         ret
1620
1621
1622 ;compute a rotation matrix from the forward vector and a rotation around
1623 ;that vector. takes esi=vector, ax=angle, edi=matrix. returns edi=dest matrix. 
1624 ;trashes esi,eax
1625 _vm_vec_ang_2_matrix:
1626         push    ebx
1627         push    esi
1628         push    edi
1629         mov     esi,[esp+16]
1630         mov     eax,[esp+20]
1631         mov     edi,[esp+24]
1632
1633         call    fix_sincos_asm
1634         mov     [sinb],eax
1635         mov     [cosb],ebx
1636
1637
1638 ;extract heading & pitch from vector
1639
1640         mov     eax,[esi+4]     ;m6=-sp
1641         neg     eax
1642         mov     [sinp],eax
1643         fixmul  eax
1644         sub     eax,f1_0
1645         neg     eax
1646         call    long_sqrt_asm   ;eax=cp
1647         sal     eax,8
1648         mov     [cosp],eax
1649         mov     ebx,eax
1650
1651         mov     eax,[esi+0]     ;sh
1652         fixdiv  ebx
1653         mov     [sinh],eax
1654
1655         mov     eax,[esi+8]     ;ch
1656         fixdiv  ebx
1657         mov     [cosh],eax
1658
1659         jmp     sincos_2_matrix
1660
1661 %if 0
1662 ;compute the distance from a point to a plane.  takes the normalized normal
1663 ;of the plane (ebx), a point on the plane (edi), and the point to check (esi).
1664 ;returns distance in eax
1665 ;distance is signed, so negative dist is on the back of the plane
1666 vm_dist_to_plane:
1667         pushm   esi,edi
1668
1669         lea     eax,tempv0
1670         call    vm_vec_sub      ;vecs in esi,edi
1671
1672         mov     esi,eax ;vector plane -> point
1673         mov     edi,ebx ;normal
1674         call    vm_vec_dotprod
1675
1676         popm    esi,edi
1677         ret
1678
1679 ;extract the angles from a matrix.  takes esi=matrix, fills in edi=angvec
1680 vm_extract_angles_matrix:
1681         pushm   eax,ebx,edx,ecx
1682
1683 ;extract heading & pitch from forward vector
1684
1685         mov     eax,[esi].fvec.z        ;ch
1686         mov     ebx,[esi].fvec.x        ;sh
1687
1688         mov     ecx,ebx ;check for z==x==0
1689         or      ecx,eax
1690         jz      zero_head       ;zero, use head=0
1691         call    fix_atan2
1692 zero_head:      mov     [edi].head,ax   ;save heading
1693         
1694         call    fix_sincos_asm  ;get back sh
1695
1696         push    eax     ;save sine
1697         abs_eax
1698         mov     ecx,eax ;save abs(sine)
1699         mov     eax,ebx
1700         abs_eax         ;abs(cos)
1701         cmp     eax,ecx ;which is larger?
1702         pop     eax     ;get sine back
1703         jg      use_cos
1704
1705 ;sine is larger, so use it
1706         mov     ebx,eax ;ebx=sine heading
1707         mov     eax,[esi].m3    ;cp = shcp / sh
1708         jmp     get_cosp
1709
1710 ;cosine is larger, so use it
1711 use_cos:
1712
1713         mov     eax,[esi].fvec.z        ;get chcp
1714 get_cosp:       fixdiv  ebx     ;cp = chcp / ch
1715
1716
1717         push    eax     ;save cp
1718
1719         ;eax = x (cos p)
1720         mov     ebx,[esi].fvec.y        ;fvec.y = -sp
1721         neg     ebx     ;ebx = y (sin)
1722         mov     ecx,ebx ;check for z==x==0
1723         or      ecx,eax
1724         jz      zero_pitch      ;bogus vec, set p=0
1725         call    fix_atan2
1726 zero_pitch:     mov     [edi].pitch,ax
1727
1728         pop     ecx     ;get cp
1729         jecxz   cp_zero
1730
1731         mov     eax,[esi].m4    ;m4 = sbcp
1732         fixdiv  ecx     ;get sb
1733         mov     ebx,eax ;save sb
1734
1735         mov     eax,[esi].m5    ;get cbcp
1736         fixdiv  ecx     ;get cb
1737         mov     ecx,ebx ;check for z==x==0
1738         or      ecx,eax
1739         jz      zero_bank       ;bogus vec, set n=0
1740         call    fix_atan2
1741 zero_bank:      mov     [edi].bank,ax
1742
1743 m_extract_done:
1744         popm    eax,ebx,edx,ecx
1745
1746         ret
1747
1748 ;the cosine of pitch is zero.  we're pitched straight up. say no bank
1749 cp_zero:        mov     [edi].bank,0    ;no bank
1750
1751         popm    eax,ebx,edx,ecx
1752         ret
1753
1754
1755 ;extract the angles from a vector, assuming zero bank. 
1756 ;takes esi=vec, edi=angvec
1757 ;note versions for normalized and not normalized vector
1758 ;unnormalized version TRASHES ESI
1759 vm_extract_angles_vector:
1760         push    edi
1761         lea     edi,tempv0
1762         call    vm_vec_copy_normalize   ;ecx=mag
1763         mov     esi,edi
1764         pop     edi
1765         jecxz   extract_done
1766
1767 vm_extract_angles_vector_normalized:
1768         pushm   eax,ebx
1769
1770         mov     [edi].bank,0    ;always zero bank
1771
1772         mov     eax,[esi].y
1773         neg     eax
1774         call    fix_asin
1775         mov     [edi].pitch,ax  ;p = asin(-y)
1776
1777         mov     eax,[esi].z
1778         mov     ebx,[esi].x
1779         or      ebx,eax
1780         jz      zero_head2      ;check for up vector
1781
1782         mov     ebx,[esi].x     ;get x again
1783         call    fix_atan2
1784 zero_head2:     mov     [edi].head,ax   ;h = atan2(x,z) (or zero)
1785
1786
1787         popm    eax,ebx
1788 extract_done:   ret
1789
1790 %endif