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