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