home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / vecmat / vecmat.asm < prev    next >
Assembly Source File  |  1998-06-08  |  34KB  |  1,616 lines

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