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