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