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