home *** CD-ROM | disk | FTP | other *** search
/ Amiga ACS 1998 #6 / amigaacscoverdisc1998-061998.iso / games / descent / source / main / fvi.c < prev    next >
Text File  |  1998-06-08  |  46KB  |  1,536 lines

  1. /*
  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. #define NEW_FVI_STUFF 1
  15.  
  16. /*
  17.  * $Source: f:/miner/source/main/rcs/fvi.c $
  18.  * $Revision: 2.3 $
  19.  * $Author: john $
  20.  * $Date: 1995/03/24 14:49:04 $
  21.  * 
  22.  * New home for find_vector_intersection()
  23.  * 
  24.  * $Log: fvi.c $
  25.  * Revision 2.3  1995/03/24  14:49:04  john
  26.  * Added cheat for player to go thru walls.
  27.  * 
  28.  * Revision 2.2  1995/03/21  17:58:32  john
  29.  * Fixed bug with normals..
  30.  * 
  31.  * 
  32.  * Revision 2.1  1995/03/20  18:15:37  john
  33.  * Added code to not store the normals in the segment structure.
  34.  * 
  35.  * Revision 2.0  1995/02/27  11:27:41  john
  36.  * New version 2.0, which has no anonymous unions, builds with
  37.  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
  38.  * 
  39.  * Revision 1.49  1995/02/22  14:45:47  allender
  40.  * remove anonymous unions from object structure
  41.  * 
  42.  * Revision 1.48  1995/02/22  13:24:50  john
  43.  * Removed the vecmat anonymous unions.
  44.  * 
  45.  * Revision 1.47  1995/02/07  16:17:26  matt
  46.  * Disabled all robot-robot collisions except those involving two green
  47.  * guys.  Used to do collisions if either robot was green guy.
  48.  * 
  49.  * Revision 1.46  1995/02/02  14:07:53  matt
  50.  * Fixed confusion about which segment you are touching when you're 
  51.  * touching a wall.  This manifested itself in spurious lava burns.
  52.  * 
  53.  * Revision 1.45  1995/02/02  13:45:53  matt
  54.  * Made a bunch of lint-inspired changes
  55.  * 
  56.  * Revision 1.44  1995/01/24  12:10:17  matt
  57.  * Fudged collisions for player/player, and player weapon/other player in
  58.  * coop games.
  59.  * 
  60.  * Revision 1.43  1995/01/14  19:16:45  john
  61.  * First version of new bitmap paging code.
  62.  * 
  63.  * Revision 1.42  1994/12/15  12:22:40  matt
  64.  * Small change which may or may not help
  65.  * 
  66.  * Revision 1.41  1994/12/14  11:45:51  matt
  67.  * Fixed (hopefully) little bug with invalid segnum
  68.  * 
  69.  * Revision 1.40  1994/12/13  17:12:01  matt
  70.  * Increased edge tolerance a bunch more
  71.  * 
  72.  * Revision 1.39  1994/12/13  14:37:59  matt
  73.  * Fixed another stupid little bug
  74.  * 
  75.  * Revision 1.38  1994/12/13  13:25:44  matt
  76.  * Increased tolerance massively to avoid catching on corners
  77.  * 
  78.  * Revision 1.37  1994/12/13  12:02:20  matt
  79.  * Fixed small bug
  80.  * 
  81.  * Revision 1.36  1994/12/13  11:17:35  matt
  82.  * Lots of changes to hopefully fix objects leaving the mine.  Note that
  83.  * this code should be considered somewhat experimental - one problem I
  84.  * know about is that you can get stuck on edges more easily than before.
  85.  * There may be other problems I don't know about yet.
  86.  * 
  87.  * Revision 1.35  1994/12/12  01:20:57  matt
  88.  * Added hack in object-object collisions that treats claw guys as
  89.  * if they have 3/4 of their actual radius.
  90.  * 
  91.  * Revision 1.34  1994/12/04  22:48:39  matt
  92.  * Physics & FVI now only build seglist for player objects, and they 
  93.  * responsilby deal with buffer full conditions
  94.  * 
  95.  * Revision 1.33  1994/12/04  22:07:05  matt
  96.  * Added better handing of buffer full condition
  97.  * 
  98.  * Revision 1.32  1994/12/01  21:06:33  matt
  99.  * Several important changes:
  100.  *  (1) Checking against triangulated sides has been standardized a bit
  101.  *  (2) Code has been added to de-triangulate some sides
  102.  *  (3) BIG ONE: the tolerance for checking a point against a plane has
  103.  *      been drastically relaxed
  104.  * 
  105.  * 
  106.  * Revision 1.31  1994/11/27  23:15:03  matt
  107.  * Made changes for new mprintf calling convention
  108.  * 
  109.  * Revision 1.30  1994/11/19  15:20:30  mike
  110.  * rip out unused code and data
  111.  * 
  112.  * Revision 1.29  1994/11/16  12:18:17  mike
  113.  * hack for green_guy:green_guy collision detection.
  114.  * 
  115.  * Revision 1.28  1994/11/10  13:08:54  matt
  116.  * Added support for new run-length-encoded bitmaps
  117.  * 
  118.  * Revision 1.27  1994/10/31  12:27:51  matt
  119.  * Added new function object_intersects_wall()
  120.  * 
  121.  * Revision 1.26  1994/10/20  13:59:27  matt
  122.  * Added assert
  123.  * 
  124.  * Revision 1.25  1994/10/09  23:51:09  matt
  125.  * Made find_hitpoint_uv() work with triangulated sides
  126.  * 
  127.  * Revision 1.24  1994/09/25  00:39:29  matt
  128.  * Took out mprintf's
  129.  * 
  130.  * Revision 1.23  1994/09/25  00:37:53  matt
  131.  * Made the 'find the point in the bitmap where something hit' system
  132.  * publicly accessible.
  133.  * 
  134.  * Revision 1.22  1994/09/21  16:58:22  matt
  135.  * Fixed bug in trans wall check that was checking against verically 
  136.  * flipped bitmap (i.e., the y coord was negative when checking).
  137.  * 
  138.  * Revision 1.21  1994/09/02  11:31:40  matt
  139.  * Fixed object/object collisions, so you can't fly through robots anymore.
  140.  * Cleaned up object damage system.
  141.  * 
  142.  * Revision 1.20  1994/08/26  09:42:03  matt
  143.  * Increased the size of a buffer
  144.  * 
  145.  * Revision 1.19  1994/08/11  18:57:53  mike
  146.  * Convert shorts to ints for optimization.
  147.  * 
  148.  * Revision 1.18  1994/08/08  21:38:24  matt
  149.  * Put in small optimization
  150.  * 
  151.  * Revision 1.17  1994/08/08  12:21:52  yuan
  152.  * Fixed assert
  153.  * 
  154.  * Revision 1.16  1994/08/08  11:47:04  matt
  155.  * Cleaned up fvi and physics a little
  156.  * 
  157.  * Revision 1.15  1994/08/04  00:21:04  matt
  158.  * Cleaned up fvi & physics error handling; put in code to make sure objects
  159.  * are in correct segment; simplified segment finding for objects and points
  160.  * 
  161.  * Revision 1.14  1994/08/02  19:04:26  matt
  162.  * Cleaned up vertex list functions
  163.  * 
  164.  * Revision 1.13  1994/08/02  09:56:28  matt
  165.  * Put in check for bad value find_plane_line_intersection()
  166.  * 
  167.  * Revision 1.12  1994/08/01  17:27:26  matt
  168.  * Added support for triangulated walls in trans point check
  169.  * 
  170.  * Revision 1.11  1994/08/01  13:30:40  matt
  171.  * Made fvi() check holes in transparent walls, and changed fvi() calling
  172.  * parms to take all input data in query structure.
  173.  * 
  174.  * Revision 1.10  1994/07/13  21:47:17  matt
  175.  * FVI() and physics now keep lists of segments passed through which the
  176.  * trigger code uses.
  177.  * 
  178.  * Revision 1.9  1994/07/09  21:21:40  matt
  179.  * Fixed, hopefull, bugs in sphere-to-vector intersection code
  180.  * 
  181.  * Revision 1.8  1994/07/08  14:26:42  matt
  182.  * Non-needed powerups don't get picked up now; this required changing FVI to
  183.  * take a list of ingore objects rather than just one ignore object.
  184.  * 
  185.  * Revision 1.7  1994/07/06  20:02:37  matt
  186.  * Made change to match gameseg that uses lowest point number as reference
  187.  * point when checking against a plane
  188.  * 
  189.  * Revision 1.6  1994/06/29  15:43:58  matt
  190.  * When computing intersection of vector and sphere, use the radii of both
  191.  * objects.
  192.  * 
  193.  * Revision 1.5  1994/06/14  15:57:58  matt
  194.  * Took out asserts, and added other hacks, pending real bug fixes
  195.  * 
  196.  * Revision 1.4  1994/06/13  23:10:08  matt
  197.  * Fixed problems with triangulated sides
  198.  * 
  199.  * Revision 1.3  1994/06/09  12:11:14  matt
  200.  * Fixed confusing use of two variables, hit_objnum & fvi_hit_object, to
  201.  * keep the same information in different ways.
  202.  * 
  203.  * Revision 1.2  1994/06/09  09:58:38  matt
  204.  * Moved find_vector_intersection() from physics.c to new file fvi.c
  205.  * 
  206.  * Revision 1.1  1994/06/09  09:25:57  matt
  207.  * Initial revision
  208.  * 
  209.  * 
  210.  */
  211.  
  212.  
  213. #pragma off (unreferenced)
  214. static char rcsid[] = "$Id: fvi.c 2.3 1995/03/24 14:49:04 john Exp $";
  215. #pragma on (unreferenced)
  216.  
  217. #include <stdlib.h>
  218. #include <malloc.h>
  219. #include <string.h>
  220.  
  221. #include "error.h"
  222. #include "mono.h"
  223.  
  224. #include "inferno.h"
  225. #include "fvi.h"
  226. #include "segment.h"
  227. #include "object.h"
  228. #include "wall.h"
  229. #include "laser.h"
  230. #include "rle.h"
  231. #include "robot.h"
  232. #include "piggy.h"
  233. #include "player.h"
  234.  
  235. extern int Physics_cheat_flag;
  236.  
  237. #define face_type_num(nfaces,face_num,tri_edge) ((nfaces==1)?0:(tri_edge*2 + face_num))
  238.  
  239. int oflow_check(fix a,fix b);
  240.  
  241. #pragma aux oflow_check parm [eax] [ebx] value [eax] modify exact [eax ebx edx] = \
  242.    "cdq"                \
  243.     "xor eax,edx"    \
  244.     "sub eax,edx"    \
  245.     "xchg eax,ebx"    \
  246.    "cdq"                \
  247.     "xor eax,edx"    \
  248.     "sub eax,edx"    \
  249.     "imul ebx"        \
  250.     "sar  edx,15"    \
  251.     "or   dx,dx"    \
  252.     "setnz al"        \
  253.     "movzx eax,al";
  254.  
  255.  
  256. //find the point on the specified plane where the line intersects
  257. //returns true if point found, false if line parallel to plane
  258. //new_pnt is the found point on the plane
  259. //plane_pnt & plane_norm describe the plane
  260. //p0 & p1 are the ends of the line
  261. int find_plane_line_intersection(vms_vector *new_pnt,vms_vector *plane_pnt,vms_vector *plane_norm,vms_vector *p0,vms_vector *p1,fix rad)
  262. {
  263.     vms_vector d,w;
  264.     fix num,den;
  265.  
  266.     vm_vec_sub(&d,p1,p0);
  267.     vm_vec_sub(&w,p0,plane_pnt);
  268.  
  269.     num =  vm_vec_dot(plane_norm,&w);
  270.     den = -vm_vec_dot(plane_norm,&d);
  271.  
  272. //Why does this assert hit so often
  273. //    Assert(num > -rad);
  274.  
  275.     num -= rad;            //move point out by rad
  276.  
  277.     //check for various bad values
  278.  
  279.     if ( (den==0) ||                    //moving parallel to wall, so can't hit it
  280.           (den>0) &&
  281.             ( (num>den) ||                //frac greater than one
  282.              (-num>>15)>=den) ||    //will overflow (large negative)
  283.           (den<0 && num<den))        //frac greater than one
  284.         return 0;
  285.  
  286. //if (num>0) {mprintf(1,"HEY! num>0 in FVI!!!"); return 0;}
  287. //??    Assert(num>=0);
  288. //    Assert(num >= den);
  289.  
  290.     //do check for potenial overflow
  291.     {
  292.         fix k;
  293.  
  294.         if (labs(num)/(f1_0/2) >= labs(den)) {Int3(); return 0;}
  295.         k = fixdiv(num,den);
  296.  
  297.         Assert(k<=f1_0);        //should be trapped above
  298.  
  299. //        Assert(k>=0);
  300.         if (oflow_check(d.x,k) || oflow_check(d.y,k) || oflow_check(d.z,k)) return 0;
  301.         //Note: it is ok for k to be greater than 1, since this might mean
  302.         //that an object with a non-zero radius that moved from p0 to p1 
  303.         //actually hit the wall on the "other side" of p0.
  304.     }
  305.  
  306.     vm_vec_scale2(&d,num,den);
  307.  
  308.     vm_vec_add(new_pnt,p0,&d);
  309.  
  310.     //we should have vm_vec_scale2_add2()
  311.  
  312.     return 1;
  313.  
  314. }
  315.  
  316. typedef struct vec2d {
  317.     fix i,j;
  318. } vec2d;
  319.  
  320. //given largest componant of normal, return i & j
  321. //if largest componant is negative, swap i & j
  322. int ij_table[3][2] =        {
  323.                             {2,1},          //pos x biggest
  324.                             {0,2},          //pos y biggest
  325.                             {1,0},          //pos z biggest
  326.                         };
  327.  
  328. //intersection types
  329. #define IT_NONE 0       //doesn't touch face at all
  330. #define IT_FACE 1       //touches face
  331. #define IT_EDGE 2       //touches edge of face
  332. #define IT_POINT        3       //touches vertex
  333.  
  334. //see if a point in inside a face by projecting into 2d
  335. uint check_point_to_face(vms_vector *checkp,segment *sp, side *s,int facenum,int nv,int *vertex_list)
  336. {
  337.     vms_vector_array *checkp_array;
  338.     vms_vector_array norm;
  339.     vms_vector t;
  340.     int biggest;
  341. ///
  342.     int i,j,edge;
  343.     uint edgemask;
  344.     fix check_i,check_j;
  345.     vms_vector_array *v0,*v1;
  346.  
  347.     #ifdef COMPACT_SEGS
  348.         get_side_normal(sp, s-sp->sides, facenum, (vms_vector *)&norm );
  349.     #else
  350.         memcpy( &norm, &s->normals[facenum], sizeof(vms_vector_array));
  351.     #endif
  352.     checkp_array = (vms_vector_array *)checkp;
  353.  
  354.     //now do 2d check to see if point is in side
  355.  
  356.     //project polygon onto plane by finding largest component of normal
  357.     t.x = labs(norm.xyz[0]); t.y = labs(norm.xyz[1]); t.z = labs(norm.xyz[2]);
  358.  
  359.     if (t.x > t.y) if (t.x > t.z) biggest=0; else biggest=2;
  360.     else if (t.y > t.z) biggest=1; else biggest=2;
  361.  
  362.     if (norm.xyz[biggest] > 0) {
  363.         i = ij_table[biggest][0];
  364.         j = ij_table[biggest][1];
  365.     }
  366.     else {
  367.         i = ij_table[biggest][1];
  368.         j = ij_table[biggest][0];
  369.     }
  370.  
  371.     //now do the 2d problem in the i,j plane
  372.  
  373.     check_i = checkp_array->xyz[i];
  374.     check_j = checkp_array->xyz[j];
  375.  
  376.     for (edge=edgemask=0;edge<nv;edge++) {
  377.         vec2d edgevec,checkvec;
  378.         fix d;
  379.  
  380.         v0 = (vms_vector_array *)&Vertices[vertex_list[facenum*3+edge]];
  381.         v1 = (vms_vector_array *)&Vertices[vertex_list[facenum*3+((edge+1)%nv)]];
  382.  
  383.         edgevec.i = v1->xyz[i] - v0->xyz[i];
  384.         edgevec.j = v1->xyz[j] - v0->xyz[j];
  385.  
  386.         checkvec.i = check_i - v0->xyz[i];
  387.         checkvec.j = check_j - v0->xyz[j];
  388.  
  389.         d = fixmul(checkvec.i,edgevec.j) - fixmul(checkvec.j,edgevec.i);
  390.  
  391.         if (d < 0)                      //we are outside of triangle
  392.             edgemask |= (1<<edge);
  393.     }
  394.  
  395.     return edgemask;
  396.  
  397. }
  398.  
  399.  
  400. //check if a sphere intersects a face
  401. check_sphere_to_face(vms_vector *pnt,segment *sp, side *s,int facenum,int nv,fix rad,int *vertex_list)
  402. {
  403.     vms_vector checkp=*pnt;
  404.     uint edgemask;
  405.  
  406.     //now do 2d check to see if point is in side
  407.  
  408.     edgemask = check_point_to_face(pnt,sp,s,facenum,nv,vertex_list);
  409.  
  410.     //we've gone through all the sides, are we inside?
  411.  
  412.     if (edgemask == 0)
  413.         return IT_FACE;
  414.     else {
  415.         vms_vector edgevec,checkvec;            //this time, real 3d vectors
  416.         vms_vector closest_point;
  417.         fix edgelen,d,dist;
  418.         vms_vector *v0,*v1;
  419.         int itype;
  420.         int edgenum;
  421.  
  422.         //get verts for edge we're behind
  423.  
  424.         for (edgenum=0;!(edgemask&1);(edgemask>>=1),edgenum++);
  425.  
  426.         v0 = &Vertices[vertex_list[facenum*3+edgenum]];
  427.         v1 = &Vertices[vertex_list[facenum*3+((edgenum+1)%nv)]];
  428.  
  429.         //check if we are touching an edge or point
  430.  
  431.         vm_vec_sub(&checkvec,&checkp,v0);
  432.         edgelen = vm_vec_normalized_dir(&edgevec,v1,v0);
  433.         
  434.         //find point dist from planes of ends of edge
  435.  
  436.         d = vm_vec_dot(&edgevec,&checkvec);
  437.  
  438.         if (d+rad < 0) return IT_NONE;                  //too far behind start point
  439.  
  440.         if (d-rad > edgelen) return IT_NONE;    //too far part end point
  441.  
  442.         //find closest point on edge to check point
  443.  
  444.         itype = IT_POINT;
  445.  
  446.         if (d < 0) closest_point = *v0;
  447.         else if (d > edgelen) closest_point = *v1;
  448.         else {
  449.             itype = IT_EDGE;
  450.  
  451.             //vm_vec_scale(&edgevec,d);
  452.             //vm_vec_add(&closest_point,v0,&edgevec);
  453.  
  454.             vm_vec_scale_add(&closest_point,v0,&edgevec,d);
  455.         }
  456.  
  457.         dist = vm_vec_dist(&checkp,&closest_point);
  458.  
  459.         if (dist <= rad)
  460.             return (itype==IT_POINT)?IT_NONE:itype;
  461.         else
  462.             return IT_NONE;
  463.     }
  464.  
  465.  
  466. }
  467.  
  468. //returns true if line intersects with face. fills in newp with intersection
  469. //point on plane, whether or not line intersects side
  470. //facenum determines which of four possible faces we have
  471. //note: the seg parm is temporary, until the face itself has a point field
  472. int check_line_to_face(vms_vector *newp,vms_vector *p0,vms_vector *p1,segment *seg,int side,int facenum,int nv,fix rad)
  473. {
  474.     vms_vector checkp;
  475.     int pli;
  476.     struct side *s=&seg->sides[side];
  477.     int vertex_list[6];
  478.     int num_faces;
  479.     int vertnum;
  480.     vms_vector norm;
  481.  
  482.     #ifdef COMPACT_SEGS
  483.         get_side_normal(seg, side, facenum, &norm );
  484.     #else
  485.         norm = seg->sides[side].normals[facenum];
  486.     #endif
  487.  
  488.     create_abs_vertex_lists(&num_faces,vertex_list,seg-Segments,side);
  489.  
  490.     //use lowest point number
  491.     if (num_faces==2) {
  492.         vertnum = min(vertex_list[0],vertex_list[2]);
  493.     }
  494.     else {
  495.         int i;
  496.         vertnum = vertex_list[0];
  497.         for (i=1;i<4;i++)
  498.             if (vertex_list[i] < vertnum)
  499.                 vertnum = vertex_list[i];
  500.     }
  501.  
  502.     pli = find_plane_line_intersection(newp,&Vertices[vertnum],&norm,p0,p1,rad);
  503.  
  504.     if (!pli) return IT_NONE;
  505.  
  506.     checkp = *newp;
  507.  
  508.     //if rad != 0, project the point down onto the plane of the polygon
  509.  
  510.     if (rad!=0)
  511.         vm_vec_scale_add2(&checkp,&norm,-rad);
  512.  
  513.     return check_sphere_to_face(&checkp,seg,s,facenum,nv,rad,vertex_list);
  514.  
  515. }
  516.  
  517. //returns the value of a determinant
  518. fix calc_det_value(vms_matrix *det)
  519. {
  520.     return     fixmul(det->rvec.x,fixmul(det->uvec.y,det->fvec.z)) -
  521.                  fixmul(det->rvec.x,fixmul(det->uvec.z,det->fvec.y)) -
  522.                  fixmul(det->rvec.y,fixmul(det->uvec.x,det->fvec.z)) +
  523.                  fixmul(det->rvec.y,fixmul(det->uvec.z,det->fvec.x)) +
  524.                  fixmul(det->rvec.z,fixmul(det->uvec.x,det->fvec.y)) -
  525.                  fixmul(det->rvec.z,fixmul(det->uvec.y,det->fvec.x));
  526. }
  527.  
  528. //computes the parameters of closest approach of two lines 
  529. //fill in two parameters, t0 & t1.  returns 0 if lines are parallel, else 1
  530. check_line_to_line(fix *t1,fix *t2,vms_vector *p1,vms_vector *v1,vms_vector *p2,vms_vector *v2)
  531. {
  532.     vms_matrix det;
  533.     fix d,cross_mag2;        //mag squared cross product
  534.  
  535.     vm_vec_sub(&det.rvec,p2,p1);
  536.     vm_vec_cross(&det.fvec,v1,v2);
  537.     cross_mag2 = vm_vec_dot(&det.fvec,&det.fvec);
  538.  
  539.     if (cross_mag2 == 0)
  540.         return 0;            //lines are parallel
  541.  
  542.     det.uvec = *v2;
  543.     d = calc_det_value(&det);
  544.     if (oflow_check(d,cross_mag2))
  545.         return 0;
  546.     else
  547.         *t1 = fixdiv(d,cross_mag2);
  548.  
  549.     det.uvec = *v1;
  550.     d = calc_det_value(&det);
  551.     if (oflow_check(d,cross_mag2))
  552.         return 0;
  553.     else
  554.         *t2 = fixdiv(d,cross_mag2);
  555.  
  556.     return 1;        //found point
  557. }
  558.  
  559. #ifdef NEW_FVI_STUFF
  560. int disable_new_fvi_stuff=0;
  561. #else
  562. #define disable_new_fvi_stuff 1
  563. #endif
  564.  
  565. //this version is for when the start and end positions both poke through
  566. //the plane of a side.  In this case, we must do checks against the edge
  567. //of faces
  568. int special_check_line_to_face(vms_vector *newp,vms_vector *p0,vms_vector *p1,segment *seg,int side,int facenum,int nv,fix rad)
  569. {
  570.     vms_vector move_vec;
  571.     fix edge_t,move_t,edge_t2,move_t2,closest_dist;
  572.     fix edge_len,move_len;
  573.     int vertex_list[6];
  574.     int num_faces,edgenum;
  575.     uint edgemask;
  576.     vms_vector *edge_v0,*edge_v1,edge_vec;
  577.     struct side *s=&seg->sides[side];
  578.     vms_vector closest_point_edge,closest_point_move;
  579.  
  580.     if (disable_new_fvi_stuff)
  581.         return check_line_to_face(newp,p0,p1,seg,side,facenum,nv,rad);
  582.  
  583.     //calc some basic stuff
  584.  
  585.     create_abs_vertex_lists(&num_faces,vertex_list,seg-Segments,side);
  586.     vm_vec_sub(&move_vec,p1,p0);
  587.  
  588.     //figure out which edge(s) to check against
  589.  
  590.     edgemask = check_point_to_face(p0,seg,s,facenum,nv,vertex_list);
  591.  
  592.     if (edgemask == 0)
  593.         return check_line_to_face(newp,p0,p1,seg,side,facenum,nv,rad);
  594.  
  595.     for (edgenum=0;!(edgemask&1);edgemask>>=1,edgenum++);
  596.  
  597.     edge_v0 = &Vertices[vertex_list[facenum*3+edgenum]];
  598.     edge_v1 = &Vertices[vertex_list[facenum*3+((edgenum+1)%nv)]];
  599.  
  600.     vm_vec_sub(&edge_vec,edge_v1,edge_v0);
  601.  
  602.     //is the start point already touching the edge?
  603.  
  604.     //??
  605.  
  606.     //first, find point of closest approach of vec & edge
  607.  
  608.     edge_len = vm_vec_normalize(&edge_vec);
  609.     move_len = vm_vec_normalize(&move_vec);
  610.  
  611.     check_line_to_line(&edge_t,&move_t,edge_v0,&edge_vec,p0,&move_vec);
  612.  
  613.     //make sure t values are in valid range
  614.  
  615.     if (move_t<0 || move_t>move_len+rad)
  616.         return IT_NONE;
  617.  
  618.     if (move_t > move_len)
  619.         move_t2 = move_len;
  620.     else
  621.         move_t2 = move_t;
  622.  
  623.     if (edge_t < 0)        //saturate at points
  624.         edge_t2 = 0;
  625.     else
  626.         edge_t2 = edge_t;
  627.     
  628.     if (edge_t2 > edge_len)        //saturate at points
  629.         edge_t2 = edge_len;
  630.     
  631.     //now, edge_t & move_t determine closest points.  calculate the points.
  632.  
  633.     vm_vec_scale_add(&closest_point_edge,edge_v0,&edge_vec,edge_t2);
  634.     vm_vec_scale_add(&closest_point_move,p0,&move_vec,move_t2);
  635.  
  636.     //find dist between closest points
  637.  
  638.     closest_dist = vm_vec_dist(&closest_point_edge,&closest_point_move);
  639.  
  640.     //could we hit with this dist?
  641.  
  642.     //note massive tolerance here
  643. //    if (closest_dist < (rad*18)/20) {        //we hit.  figure out where
  644.     if (closest_dist < (rad*15)/20) {        //we hit.  figure out where
  645.  
  646.         //now figure out where we hit
  647.  
  648.         vm_vec_scale_add(newp,p0,&move_vec,move_t-rad);
  649.  
  650.         return IT_EDGE;
  651.  
  652.     }
  653.     else
  654.         return IT_NONE;            //no hit
  655.  
  656. }
  657.  
  658. //maybe this routine should just return the distance and let the caller
  659. //decide it it's close enough to hit
  660. //determine if and where a vector intersects with a sphere
  661. //vector defined by p0,p1 
  662. //returns dist if intersects, and fills in intp
  663. //else returns 0
  664. int check_vector_to_sphere_1(vms_vector *intp,vms_vector *p0,vms_vector *p1,vms_vector *sphere_pos,fix sphere_rad)
  665. {
  666.     vms_vector d,dn,w,closest_point;
  667.     fix mag_d,dist,w_dist,int_dist;
  668.  
  669.     //this routine could be optimized if it's taking too much time!
  670.  
  671.     vm_vec_sub(&d,p1,p0);
  672.     vm_vec_sub(&w,sphere_pos,p0);
  673.  
  674.     mag_d = vm_vec_copy_normalize(&dn,&d);
  675.  
  676.     if (mag_d == 0) {
  677.         int_dist = vm_vec_mag(&w);
  678.         *intp = *p0;
  679.         return (int_dist<sphere_rad)?int_dist:0;
  680.     }
  681.  
  682.     w_dist = vm_vec_dot(&dn,&w);
  683.  
  684.     if (w_dist < 0)        //moving away from object
  685.          return 0;
  686.  
  687.     if (w_dist > mag_d+sphere_rad)
  688.         return 0;        //cannot hit
  689.  
  690.     vm_vec_scale_add(&closest_point,p0,&dn,w_dist);
  691.  
  692.     dist = vm_vec_dist(&closest_point,sphere_pos);
  693.  
  694.     if (dist < sphere_rad) {
  695.         fix dist2,rad2,shorten;
  696.  
  697.         dist2 = fixmul(dist,dist);
  698.         rad2 = fixmul(sphere_rad,sphere_rad);
  699.  
  700.         shorten = fix_sqrt(rad2 - dist2);
  701.  
  702.         int_dist = w_dist-shorten;
  703.  
  704.         if (int_dist > mag_d || int_dist < 0) {
  705.             //past one or the other end of vector, which means we're inside
  706.  
  707.             *intp = *p0;        //don't move at all
  708.             return 1;
  709.         }
  710.  
  711.         vm_vec_scale_add(intp,p0,&dn,int_dist);         //calc intersection point
  712.  
  713. //        {
  714. //            fix dd = vm_vec_dist(intp,sphere_pos);
  715. //            Assert(dd == sphere_rad);
  716. //            mprintf(0,"dd=%x, rad=%x, delta=%x\n",dd,sphere_rad,dd-sphere_rad);
  717. //        }
  718.  
  719.  
  720.         return int_dist;
  721.     }
  722.     else
  723.         return 0;
  724. }
  725.  
  726. //$$fix get_sphere_int_dist(vms_vector *w,fix dist,fix rad);
  727. //$$
  728. //$$#pragma aux get_sphere_int_dist parm [esi] [ebx] [ecx] value [eax] modify exact [eax ebx ecx edx] = \
  729. //$$    "mov eax,ebx"        \
  730. //$$    "imul eax"            \
  731. //$$                            \
  732. //$$    "mov ebx,eax"        \
  733. //$$   "mov eax,ecx"        \
  734. //$$    "mov ecx,edx"        \
  735. //$$                            \
  736. //$$    "imul eax"            \
  737. //$$                            \
  738. //$$    "sub eax,ebx"        \
  739. //$$    "sbb edx,ecx"        \
  740. //$$                            \
  741. //$$    "call quad_sqrt"    \
  742. //$$                            \
  743. //$$    "push eax"            \
  744. //$$                            \
  745. //$$    "push ebx"            \
  746. //$$    "push ecx"            \
  747. //$$                            \
  748. //$$    "mov eax,[esi]"    \
  749. //$$    "imul eax"            \
  750. //$$    "mov ebx,eax"        \
  751. //$$    "mov ecx,edx"        \
  752. //$$    "mov eax,4[esi]"    \
  753. //$$    "imul eax"            \
  754. //$$    "add ebx,eax"        \
  755. //$$    "adc ecx,edx"        \
  756. //$$    "mov eax,8[esi]"    \
  757. //$$    "imul eax"            \
  758. //$$    "add eax,ebx"        \
  759. //$$    "adc edx,ecx"        \
  760. //$$                            \
  761. //$$    "pop ecx"            \
  762. //$$    "pop ebx"            \
  763. //$$                            \
  764. //$$    "sub eax,ebx"        \
  765. //$$    "sbb edx,ecx"        \
  766. //$$                            \
  767. //$$    "call quad_sqrt"    \
  768. //$$                            \
  769. //$$    "pop ebx"            \
  770. //$$    "sub eax,ebx";
  771. //$$
  772. //$$
  773. //$$//determine if and where a vector intersects with a sphere
  774. //$$//vector defined by p0,p1 
  775. //$$//returns dist if intersects, and fills in intp. if no intersect, return 0
  776. //$$fix check_vector_to_sphere_2(vms_vector *intp,vms_vector *p0,vms_vector *p1,vms_vector *sphere_pos,fix sphere_rad)
  777. //$${
  778. //$$    vms_vector d,w,c;
  779. //$$    fix mag_d,dist,mag_c,mag_w;
  780. //$$    vms_vector wn,dn;
  781. //$$
  782. //$$    vm_vec_sub(&d,p1,p0);
  783. //$$    vm_vec_sub(&w,sphere_pos,p0);
  784. //$$
  785. //$$    //wn = w; mag_w = vm_vec_normalize(&wn);
  786. //$$    //dn = d; mag_d = vm_vec_normalize(&dn);
  787. //$$
  788. //$$    mag_w = vm_vec_copy_normalize(&wn,&w);
  789. //$$    mag_d = vm_vec_copy_normalize(&dn,&d);
  790. //$$
  791. //$$    //vm_vec_cross(&c,&w,&d);
  792. //$$    vm_vec_cross(&c,&wn,&dn);
  793. //$$
  794. //$$    mag_c = vm_vec_mag(&c);
  795. //$$    //mag_d = vm_vec_mag(&d);
  796. //$$
  797. //$$    //dist = fixdiv(mag_c,mag_d);
  798. //$$
  799. //$$dist = fixmul(mag_c,mag_w);
  800. //$$
  801. //$$    if (dist < sphere_rad) {        //we intersect.  find point of intersection
  802. //$$        fix int_dist;                   //length of vector to intersection point
  803. //$$        fix k;                                  //portion of p0p1 we want
  804. //$$//@@        fix dist2,rad2,shorten,mag_w2;
  805. //$$
  806. //$$//@@        mag_w2 = vm_vec_dot(&w,&w);     //the square of the magnitude
  807. //$$//@@        //WHAT ABOUT OVERFLOW???
  808. //$$//@@        dist2 = fixmul(dist,dist);
  809. //$$//@@        rad2 = fixmul(sphere_rad,sphere_rad);
  810. //$$//@@        shorten = fix_sqrt(rad2 - dist2);
  811. //$$//@@        int_dist = fix_sqrt(mag_w2 - dist2) - shorten;
  812. //$$
  813. //$$        int_dist = get_sphere_int_dist(&w,dist,sphere_rad);
  814. //$$
  815. //$$if (labs(int_dist) > mag_d)    //I don't know why this would happen
  816. //$$    if (int_dist > 0)
  817. //$$        k = f1_0;
  818. //$$    else
  819. //$$        k = -f1_0;
  820. //$$else
  821. //$$        k = fixdiv(int_dist,mag_d);
  822. //$$
  823. //$$//        vm_vec_scale(&d,k);                     //vec from p0 to intersection point
  824. //$$//        vm_vec_add(intp,p0,&d);         //intersection point
  825. //$$        vm_vec_scale_add(intp,p0,&d,k);    //calc new intersection point
  826. //$$
  827. //$$        return int_dist;
  828. //$$    }
  829. //$$    else
  830. //$$        return 0;       //no intersection
  831. //$$}
  832.  
  833. //determine if a vector intersects with an object
  834. //if no intersects, returns 0, else fills in intp and returns dist
  835. fix check_vector_to_object(vms_vector *intp,vms_vector *p0,vms_vector *p1,fix rad,object *obj,object *otherobj)
  836. {
  837.     fix size = obj->size;
  838.  
  839.     if (obj->type == OBJ_ROBOT && Robot_info[obj->id].attack_type)
  840.         size = (size*3)/4;
  841.  
  842.     //if obj is player, and bumping into other player or a weapon of another coop player, reduce radius
  843.     if (obj->type == OBJ_PLAYER && 
  844.              ((otherobj->type == OBJ_PLAYER) ||
  845.              ((Game_mode&GM_MULTI_COOP) && otherobj->type == OBJ_WEAPON && otherobj->ctype.laser_info.parent_type == OBJ_PLAYER)))
  846.         size = size/2;
  847.  
  848.     return check_vector_to_sphere_1(intp,p0,p1,&obj->pos,size+rad);
  849.  
  850. }
  851.  
  852.  
  853. #define MAX_SEGS_VISITED 100
  854. int n_segs_visited;
  855. short segs_visited[MAX_SEGS_VISITED];
  856.  
  857. int fvi_nest_count;
  858.  
  859. //these vars are used to pass vars from fvi_sub() to find_vector_intersection()
  860. int fvi_hit_object;    // object number of object hit in last find_vector_intersection call.
  861. int fvi_hit_seg;        // what segment the hit point is in
  862. int fvi_hit_side;        // what side was hit
  863. int fvi_hit_side_seg;// what seg the hitside is in
  864. vms_vector wall_norm;    //ptr to surface normal of hit wall
  865. int fvi_hit_seg2;        // what segment the hit point is in
  866.  
  867. int fvi_sub(vms_vector *intp,int *ints,vms_vector *p0,int startseg,vms_vector *p1,fix rad,short thisobjnum,int *ignore_obj_list,int flags,int *seglist,int *n_segs,int entry_seg);
  868.  
  869. //What the hell is fvi_hit_seg for???
  870.  
  871. //Find out if a vector intersects with anything.
  872. //Fills in hit_data, an fvi_info structure (see header file).
  873. //Parms:
  874. //  p0 & startseg     describe the start of the vector
  875. //  p1                     the end of the vector
  876. //  rad                     the radius of the cylinder
  877. //  thisobjnum         used to prevent an object with colliding with itself
  878. //  ingore_obj            ignore collisions with this object
  879. //  check_obj_flag    determines whether collisions with objects are checked
  880. //Returns the hit_data->hit_type
  881. int find_vector_intersection(fvi_query *fq,fvi_info *hit_data)
  882. {
  883.     int hit_type,hit_seg,hit_seg2;
  884.     vms_vector hit_pnt;
  885.     int i;
  886.  
  887.     Assert(fq->ignore_obj_list != -1);
  888.     Assert((fq->startseg <= Highest_segment_index) && (fq->startseg >= 0));
  889.  
  890.     fvi_hit_seg = -1;
  891.     fvi_hit_side = -1;
  892.  
  893.     fvi_hit_object = -1;
  894.  
  895.     //check to make sure start point is in seg its supposed to be in
  896.     //Assert(check_point_in_seg(p0,startseg,0).centermask==0);    //start point not in seg
  897.  
  898.     // Viewer is not in segment as claimed, so say there is no hit.
  899.     if(!(get_seg_masks(fq->p0,fq->startseg,0).centermask==0)) {
  900.  
  901.         hit_data->hit_type = HIT_BAD_P0;
  902.         hit_data->hit_pnt = *fq->p0;
  903.         hit_data->hit_seg = fq->startseg;
  904.         hit_data->hit_side = hit_data->hit_object = 0;
  905.         hit_data->hit_side_seg = -1;
  906.  
  907.         return hit_data->hit_type;
  908.     }
  909.  
  910.     segs_visited[0] = fq->startseg;
  911.  
  912.     n_segs_visited=1;
  913.  
  914.     fvi_nest_count = 0;
  915.  
  916.     hit_seg2 = fvi_hit_seg2 = -1;
  917.  
  918.     hit_type = fvi_sub(&hit_pnt,&hit_seg2,fq->p0,fq->startseg,fq->p1,fq->rad,fq->thisobjnum,fq->ignore_obj_list,fq->flags,hit_data->seglist,&hit_data->n_segs,-2);
  919.     //!!hit_seg = find_point_seg(&hit_pnt,fq->startseg);
  920.     if (hit_seg2!=-1 && !get_seg_masks(&hit_pnt,hit_seg2,0).centermask)
  921.         hit_seg = hit_seg2;
  922.     else
  923.         hit_seg = find_point_seg(&hit_pnt,fq->startseg);
  924.  
  925. //MATT: TAKE OUT THIS HACK AND FIX THE BUGS!
  926.     if (hit_type == HIT_WALL && hit_seg==-1)
  927.         if (fvi_hit_seg2!=-1 && get_seg_masks(&hit_pnt,fvi_hit_seg2,0).centermask==0)
  928.             hit_seg = fvi_hit_seg2;
  929.  
  930.     if (hit_seg == -1) {
  931.         int new_hit_type;
  932.         int new_hit_seg2=-1;
  933.         vms_vector new_hit_pnt;
  934.  
  935.         //because of code that deal with object with non-zero radius has
  936.         //problems, try using zero radius and see if we hit a wall
  937.  
  938.         new_hit_type = fvi_sub(&new_hit_pnt,&new_hit_seg2,fq->p0,fq->startseg,fq->p1,0,fq->thisobjnum,fq->ignore_obj_list,fq->flags,hit_data->seglist,&hit_data->n_segs,-2);
  939.  
  940.         if (new_hit_seg2 != -1) {
  941.             hit_seg = new_hit_seg2;
  942.             hit_pnt = new_hit_pnt;
  943.         }
  944.     }
  945.  
  946.  
  947. if (hit_seg!=-1 && fq->flags&FQ_GET_SEGLIST)
  948.     if (hit_seg != hit_data->seglist[hit_data->n_segs-1] && hit_data->n_segs<MAX_FVI_SEGS-1)
  949.         hit_data->seglist[hit_data->n_segs++] = hit_seg;
  950.  
  951. if (hit_seg!=-1 && fq->flags&FQ_GET_SEGLIST)
  952.     for (i=0;i<hit_data->n_segs && i<MAX_FVI_SEGS-1;i++)
  953.         if (hit_data->seglist[i] == hit_seg) {
  954.             hit_data->n_segs = i+1;
  955.             break;
  956.         }
  957.  
  958. //I'm sorry to say that sometimes the seglist isn't correct.  I did my
  959. //best.  Really.
  960.  
  961.  
  962. //{    //verify hit list
  963. //
  964. //    int i,ch;
  965. //
  966. //    Assert(hit_data->seglist[0] == startseg);
  967. //
  968. //    for (i=0;i<hit_data->n_segs-1;i++) {
  969. //        for (ch=0;ch<6;ch++)
  970. //            if (Segments[hit_data->seglist[i]].children[ch] == hit_data->seglist[i+1])
  971. //                break;
  972. //        Assert(ch<6);
  973. //    }
  974. //
  975. //    Assert(hit_data->seglist[hit_data->n_segs-1] == hit_seg);
  976. //}
  977.     
  978.  
  979. //MATT: PUT THESE ASSERTS BACK IN AND FIX THE BUGS!
  980. //!!    Assert(hit_seg!=-1);
  981. //!!    Assert(!((hit_type==HIT_WALL) && (hit_seg == -1)));
  982.     //When this assert happens, get Matt.  Matt:  Look at hit_seg2 & 
  983.     //fvi_hit_seg.  At least one of these should be set.  Why didn't 
  984.     //find_new_seg() find something?
  985.  
  986. //    Assert(fvi_hit_seg==-1 || fvi_hit_seg == hit_seg);
  987.  
  988.     Assert(!(hit_type==HIT_OBJECT && fvi_hit_object==-1));
  989.  
  990.     hit_data->hit_type        = hit_type;
  991.     hit_data->hit_pnt         = hit_pnt;
  992.     hit_data->hit_seg         = hit_seg;
  993.     hit_data->hit_side         = fvi_hit_side;    //looks at global
  994.     hit_data->hit_side_seg    = fvi_hit_side_seg;    //looks at global
  995.     hit_data->hit_object        = fvi_hit_object;    //looks at global
  996.     hit_data->hit_wallnorm    = wall_norm;        //looks at global
  997.  
  998. //    if(hit_seg!=-1 && get_seg_masks(&hit_data->hit_pnt,hit_data->hit_seg,0).centermask!=0)
  999. //        Int3();
  1000.  
  1001.     return hit_type;
  1002.  
  1003. }
  1004.  
  1005. //--unused-- fix check_dist(vms_vector *v0,vms_vector *v1)
  1006. //--unused-- {
  1007. //--unused--     return vm_vec_dist(v0,v1);
  1008. //--unused-- }
  1009.  
  1010. obj_in_list(int objnum,int *obj_list)
  1011. {
  1012.     int t;
  1013.  
  1014.     while ((t=*obj_list)!=-1 && t!=objnum) obj_list++;
  1015.  
  1016.     return (t==objnum);
  1017.  
  1018. }
  1019.  
  1020. int check_trans_wall(vms_vector *pnt,segment *seg,int sidenum,int facenum);
  1021.  
  1022. int fvi_sub(vms_vector *intp,int *ints,vms_vector *p0,int startseg,vms_vector *p1,fix rad,short thisobjnum,int *ignore_obj_list,int flags,int *seglist,int *n_segs,int entry_seg)
  1023. {
  1024.     segment *seg;                //the segment we're looking at
  1025.     int startmask,endmask;    //mask of faces
  1026.     //@@int sidemask;                //mask of sides - can be on back of face but not side
  1027.     int centermask;            //where the center point is
  1028.     int objnum;
  1029.     segmasks masks;
  1030.     vms_vector hit_point,closest_hit_point;     //where we hit
  1031.     fix d,closest_d=0x7fffffff;                    //distance to hit point
  1032.     int hit_type=HIT_NONE;                            //what sort of hit
  1033.     int hit_seg=-1;
  1034.     int hit_none_seg=-1;
  1035.     int hit_none_n_segs=0;
  1036.     int hit_none_seglist[MAX_FVI_SEGS];
  1037.     int cur_nest_level = fvi_nest_count;
  1038.  
  1039.     //fvi_hit_object = -1;
  1040.  
  1041.     if ( stackavail() < 1024 )                      
  1042.     {
  1043.         mprintf( (0, "In fvi_sub, stack left is < 1k !\n" ));
  1044.         Int3();
  1045.     }
  1046.  
  1047.     if (flags&FQ_GET_SEGLIST)
  1048.         *seglist = startseg; 
  1049.     *n_segs=1;
  1050.  
  1051.     seg = &Segments[startseg];
  1052.  
  1053.     fvi_nest_count++;
  1054.  
  1055.     //first, see if vector hit any objects in this segment
  1056.     if (flags & FQ_CHECK_OBJS)
  1057.         for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next)
  1058.             if (    !(Objects[objnum].flags & OF_SHOULD_BE_DEAD) &&
  1059.                      !(thisobjnum == objnum ) &&
  1060.                      (ignore_obj_list==NULL || !obj_in_list(objnum,ignore_obj_list)) &&
  1061.                      !laser_are_related( objnum, thisobjnum ) &&
  1062.                      !((thisobjnum  > -1)    &&
  1063.                           (CollisionResult[Objects[thisobjnum].type][Objects[objnum].type] == RESULT_NOTHING ) &&
  1064.                           (CollisionResult[Objects[objnum].type][Objects[thisobjnum].type] == RESULT_NOTHING ))) {
  1065.                 int fudged_rad = rad;
  1066.  
  1067.                 //    If this is a robot:robot collision, only do it if both of them have attack_type != 0 (eg, green guy)
  1068.                 if (Objects[thisobjnum].type == OBJ_ROBOT)
  1069.                     if (Objects[objnum].type == OBJ_ROBOT)
  1070.                         if (!(Robot_info[Objects[objnum].id].attack_type && Robot_info[Objects[thisobjnum].id].attack_type))
  1071.                             continue;
  1072.  
  1073.                 if (Objects[thisobjnum].type == OBJ_ROBOT && Robot_info[Objects[thisobjnum].id].attack_type)
  1074.                     fudged_rad = (rad*3)/4;
  1075.  
  1076.                 //if obj is player, and bumping into other player or a weapon of another coop player, reduce radius
  1077.                 if (Objects[thisobjnum].type == OBJ_PLAYER && 
  1078.                         ((Objects[objnum].type == OBJ_PLAYER) ||
  1079.                         ((Game_mode&GM_MULTI_COOP) &&  Objects[objnum].type == OBJ_WEAPON && Objects[objnum].ctype.laser_info.parent_type == OBJ_PLAYER)))
  1080.                     fudged_rad = rad/2;    //(rad*3)/4;
  1081.  
  1082.                 d = check_vector_to_object(&hit_point,p0,p1,fudged_rad,&Objects[objnum],&Objects[thisobjnum]);
  1083.  
  1084.                 if (d)          //we have intersection
  1085.                     if (d < closest_d) {
  1086.                         fvi_hit_object = objnum; 
  1087.                         Assert(fvi_hit_object!=-1);
  1088.                         closest_d = d; 
  1089.                         closest_hit_point = hit_point; 
  1090.                         hit_type=HIT_OBJECT;
  1091.                     }
  1092.             }
  1093.  
  1094.     if (    (thisobjnum > -1 ) && (CollisionResult[Objects[thisobjnum].type][OBJ_WALL] == RESULT_NOTHING ) )
  1095.         rad = 0;        //HACK - ignore when edges hit walls
  1096.  
  1097.     //now, check segment walls
  1098.  
  1099.     startmask = get_seg_masks(p0,startseg,rad).facemask;
  1100.  
  1101.     masks = get_seg_masks(p1,startseg,rad);    //on back of which faces?
  1102.     endmask = masks.facemask;
  1103.     //@@sidemask = masks.sidemask;
  1104.     centermask = masks.centermask;
  1105.  
  1106.     if (centermask==0) hit_none_seg = startseg;
  1107.  
  1108.     if (endmask != 0) {                             //on the back of at least one face
  1109.  
  1110.         int side,bit,face;
  1111.  
  1112.         //for each face we are on the back of, check if intersected
  1113.  
  1114.         for (side=0,bit=1;side<6 && endmask>=bit;side++) {
  1115.             int num_faces;
  1116.             num_faces = get_num_faces(&seg->sides[side]);
  1117.  
  1118.             if (num_faces == 0)
  1119.                 num_faces = 1;
  1120.  
  1121.             // commented out by mk on 02/13/94:: if ((num_faces=seg->sides[side].num_faces)==0) num_faces=1;
  1122.  
  1123.             for (face=0;face<2;face++,bit<<=1) {
  1124.  
  1125.                 if (endmask & bit) {            //on the back of this face
  1126.                     int face_hit_type;      //in what way did we hit the face?
  1127.  
  1128.  
  1129.                     if (seg->children[side] == entry_seg)
  1130.                         continue;        //don't go back through entry side
  1131.  
  1132.                     //did we go through this wall/door?
  1133.  
  1134.                     //#ifdef NEW_FVI_STUFF
  1135.                     if (startmask & bit)        //start was also though.  Do extra check
  1136.                         face_hit_type = special_check_line_to_face( &hit_point,
  1137.                                         p0,p1,seg,side,
  1138.                                         face,
  1139.                                         ((num_faces==1)?4:3),rad);
  1140.                     else
  1141.                     //#endif
  1142.                         //NOTE LINK TO ABOVE!!
  1143.                         face_hit_type = check_line_to_face( &hit_point,
  1144.                                         p0,p1,seg,side,
  1145.                                         face,
  1146.                                         ((num_faces==1)?4:3),rad);
  1147.  
  1148.     
  1149.                     if (face_hit_type) {            //through this wall/door
  1150.                         int wid_flag;
  1151.  
  1152.                         //if what we have hit is a door, check the adjoining seg
  1153.  
  1154.                         if ( (thisobjnum == Players[Player_num].objnum) && (Physics_cheat_flag==0xBADA55) )    {
  1155.                             wid_flag = WALL_IS_DOORWAY(seg, side);
  1156.                             if (seg->children[side] >= 0 ) 
  1157.                                  wid_flag |= WID_FLY_FLAG;
  1158.                         } else {
  1159.                             wid_flag = WALL_IS_DOORWAY(seg, side);
  1160.                         }
  1161.  
  1162.                         if ((wid_flag & WID_FLY_FLAG) ||
  1163.                             ((wid_flag == WID_TRANSPARENT_WALL) && 
  1164.                                 ((flags & FQ_TRANSWALL) || (flags & FQ_TRANSPOINT && check_trans_wall(&hit_point,seg,side,face))))) {
  1165.  
  1166.                             int newsegnum;
  1167.                             vms_vector sub_hit_point;
  1168.                             int sub_hit_type,sub_hit_seg;
  1169.                             vms_vector save_wall_norm = wall_norm;
  1170.                             int save_hit_objnum=fvi_hit_object;
  1171.                             int i;
  1172.  
  1173.                             //do the check recursively on the next seg.
  1174.  
  1175.                             newsegnum = seg->children[side];
  1176.  
  1177.                             for (i=0;i<n_segs_visited && newsegnum!=segs_visited[i];i++);
  1178.  
  1179.                             if (i==n_segs_visited) {                //haven't visited here yet
  1180.                                 int temp_seglist[MAX_FVI_SEGS],temp_n_segs;
  1181.                                 
  1182.                                 segs_visited[n_segs_visited++] = newsegnum;
  1183.  
  1184.                                 if (n_segs_visited >= MAX_SEGS_VISITED)
  1185.                                     goto quit_looking;        //we've looked a long time, so give up
  1186.  
  1187.                                 sub_hit_type = fvi_sub(&sub_hit_point,&sub_hit_seg,p0,newsegnum,p1,rad,thisobjnum,ignore_obj_list,flags,temp_seglist,&temp_n_segs,startseg);
  1188.  
  1189.                                 if (sub_hit_type != HIT_NONE) {
  1190.  
  1191.                                     d = vm_vec_dist(&sub_hit_point,p0);
  1192.  
  1193.                                     if (d < closest_d) {
  1194.  
  1195.                                         closest_d = d; 
  1196.                                         closest_hit_point = sub_hit_point;
  1197.                                         hit_type = sub_hit_type;
  1198.                                         if (sub_hit_seg!=-1) hit_seg = sub_hit_seg;
  1199.  
  1200.                                         //copy seglist
  1201.                                         if (flags&FQ_GET_SEGLIST) {
  1202.                                             int ii;
  1203.                                             for (ii=0;i<temp_n_segs && *n_segs<MAX_FVI_SEGS-1;)
  1204.                                                 seglist[(*n_segs)++] = temp_seglist[ii++];
  1205.                                         }
  1206.  
  1207.                                         Assert(*n_segs < MAX_FVI_SEGS);
  1208.                                     }
  1209.                                     else {
  1210.                                         wall_norm = save_wall_norm;     //global could be trashed
  1211.                                         fvi_hit_object = save_hit_objnum;
  1212.                                      }
  1213.  
  1214.                                 }
  1215.                                 else {
  1216.                                     wall_norm = save_wall_norm;     //global could be trashed
  1217.                                     if (sub_hit_seg!=-1) hit_none_seg = sub_hit_seg;
  1218.                                     //copy seglist
  1219.                                     if (flags&FQ_GET_SEGLIST) {
  1220.                                         int ii;
  1221.                                         for (ii=0;ii<temp_n_segs && ii<MAX_FVI_SEGS-1;ii++)
  1222.                                             hit_none_seglist[ii] = temp_seglist[ii];
  1223.                                     }
  1224.                                     hit_none_n_segs = temp_n_segs;
  1225.                                 }
  1226.                             }
  1227.                         }
  1228.                         else {          //a wall
  1229.                                                                 
  1230.                                 //is this the closest hit?
  1231.     
  1232.                                 d = vm_vec_dist(&hit_point,p0);
  1233.     
  1234.                                 if (d < closest_d) {
  1235.                                     closest_d = d; 
  1236.                                     closest_hit_point = hit_point;
  1237.                                     hit_type = HIT_WALL;
  1238.                                     
  1239.                                     #ifdef COMPACT_SEGS
  1240.                                         get_side_normal(seg, side, face, &wall_norm );
  1241.                                     #else
  1242.                                         wall_norm = seg->sides[side].normals[face];    
  1243.                                     #endif
  1244.                                     
  1245.     
  1246.                                     if (get_seg_masks(&hit_point,startseg,rad).centermask==0)
  1247.                                         hit_seg = startseg;             //hit in this segment
  1248.                                     else
  1249.                                         fvi_hit_seg2 = startseg;
  1250.  
  1251.                                     //@@else     {
  1252.                                     //@@    mprintf( 0, "Warning on line 991 in physics.c\n" );
  1253.                                     //@@    hit_seg = startseg;             //hit in this segment
  1254.                                     //@@    //Int3();
  1255.                                     //@@}
  1256.  
  1257.                                     fvi_hit_seg = hit_seg;
  1258.                                     fvi_hit_side =  side;
  1259.                                     fvi_hit_side_seg = startseg;
  1260.  
  1261.                                 }
  1262.                         }
  1263.                     }
  1264.                 }
  1265.             }
  1266.         }
  1267.     }
  1268.  
  1269. //      Assert(centermask==0 || hit_seg!=startseg);
  1270.  
  1271. //      Assert(sidemask==0);            //Error("Didn't find side we went though");
  1272.  
  1273. quit_looking:
  1274.     ;
  1275.  
  1276.     if (hit_type == HIT_NONE) {     //didn't hit anything, return end point
  1277.         int i;
  1278.  
  1279.         *intp = *p1;
  1280.         *ints = hit_none_seg;
  1281.         //MATT: MUST FIX THIS!!!!
  1282.         //Assert(!centermask);
  1283.  
  1284.         if (hit_none_seg!=-1) {            ///(centermask == 0)
  1285.             if (flags&FQ_GET_SEGLIST)
  1286.                 //copy seglist
  1287.                 for (i=0;i<hit_none_n_segs && *n_segs<MAX_FVI_SEGS-1;)
  1288.                     seglist[(*n_segs)++] = hit_none_seglist[i++];
  1289.         }
  1290.         else
  1291.             if (cur_nest_level!=0)
  1292.                 *n_segs=0;
  1293.  
  1294.     }
  1295.     else {
  1296.         *intp = closest_hit_point;
  1297.         if (hit_seg==-1)
  1298.             if (fvi_hit_seg2 != -1)
  1299.                 *ints = fvi_hit_seg2;
  1300.             else
  1301.                 *ints = hit_none_seg;
  1302.         else
  1303.             *ints = hit_seg;
  1304.     }
  1305.  
  1306.     Assert(!(hit_type==HIT_OBJECT && fvi_hit_object==-1));
  1307.  
  1308.     return hit_type;
  1309.  
  1310. }
  1311.  
  1312. //--unused-- //compute the magnitude of a 2d vector
  1313. //--unused-- fix mag2d(vec2d *v);
  1314. //--unused-- #pragma aux mag2d parm [esi] value [eax] modify exact [eax ebx ecx edx] = \
  1315. //--unused--     "mov    eax,[esi]"        \
  1316. //--unused--     "imul    eax"                \
  1317. //--unused--     "mov    ebx,eax"            \
  1318. //--unused--     "mov    ecx,edx"            \
  1319. //--unused--     "mov    eax,4[esi]"        \
  1320. //--unused--     "imul    eax"                \
  1321. //--unused--     "add    eax,ebx"            \
  1322. //--unused--     "adc    edx,ecx"            \
  1323. //--unused--     "call    quad_sqrt";
  1324.  
  1325. //--unused-- //returns mag
  1326. //--unused-- fix normalize_2d(vec2d *v)
  1327. //--unused-- {
  1328. //--unused--     fix mag;
  1329. //--unused-- 
  1330. //--unused--     mag = mag2d(v);
  1331. //--unused-- 
  1332. //--unused--     v->i = fixdiv(v->i,mag);
  1333. //--unused--     v->j = fixdiv(v->j,mag);
  1334. //--unused-- 
  1335. //--unused--     return mag;
  1336. //--unused-- }
  1337.  
  1338. #include "textures.h"
  1339. #include "texmerge.h"
  1340.  
  1341. #define cross(v0,v1) (fixmul((v0)->i,(v1)->j) - fixmul((v0)->j,(v1)->i))
  1342.  
  1343. //finds the uv coords of the given point on the given seg & side
  1344. //fills in u & v
  1345. find_hitpoint_uv(fix *u,fix *v,vms_vector *pnt,segment *seg,int sidenum,int facenum)
  1346. {
  1347.     vms_vector_array *pnt_array;
  1348.     vms_vector_array normal_array;
  1349.     int segnum = seg-Segments;
  1350.     int num_faces;
  1351.     int biggest,ii,jj;
  1352.     side *side = &seg->sides[sidenum];
  1353.     int vertex_list[6],vertnum_list[6];
  1354.      vec2d p1,vec0,vec1,checkp;    //@@,checkv;
  1355.     uvl uvls[3];
  1356.     fix k0,k1;
  1357.     int i;
  1358.  
  1359.     //mprintf(0,"\ncheck_trans_wall  vec=%x,%x,%x\n",pnt->x,pnt->y,pnt->z);
  1360.  
  1361.     //do lasers pass through illusory walls?
  1362.  
  1363.     //when do I return 0 & 1 for non-transparent walls?
  1364.  
  1365.     create_abs_vertex_lists(&num_faces,vertex_list,segnum,sidenum);
  1366.     create_all_vertnum_lists(&num_faces,vertnum_list,segnum,sidenum);
  1367.  
  1368.     //now the hard work.
  1369.  
  1370.     //1. find what plane to project this wall onto to make it a 2d case
  1371.  
  1372.     #ifdef COMPACT_SEGS
  1373.         get_side_normal(seg, sidenum, facenum, (vms_vector *)&normal_array );
  1374.     #else
  1375.         memcpy( &normal_array, &side->normals[facenum], sizeof(vms_vector_array) );
  1376.     #endif
  1377.       biggest = 0;
  1378.  
  1379.     if (abs(normal_array.xyz[1]) > abs(normal_array.xyz[biggest])) biggest = 1;
  1380.     if (abs(normal_array.xyz[2]) > abs(normal_array.xyz[biggest])) biggest = 2;
  1381.  
  1382.     if (biggest == 0) ii=1; else ii=0;
  1383.     if (biggest == 2) jj=1; else jj=2;
  1384.  
  1385.     //2. compute u,v of intersection point
  1386.  
  1387.     //vec from 1 -> 0
  1388.     pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+1]];
  1389.     p1.i = pnt_array->xyz[ii];
  1390.     p1.j = pnt_array->xyz[jj];
  1391.  
  1392.     pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+0]];
  1393.     vec0.i = pnt_array->xyz[ii] - p1.i;
  1394.     vec0.j = pnt_array->xyz[jj] - p1.j;
  1395.  
  1396.     //vec from 1 -> 2
  1397.     pnt_array = (vms_vector_array *)&Vertices[vertex_list[facenum*3+2]];
  1398.     vec1.i = pnt_array->xyz[ii] - p1.i;
  1399.     vec1.j = pnt_array->xyz[jj] - p1.j;
  1400.  
  1401.     //vec from 1 -> checkpoint
  1402.     pnt_array = (vms_vector_array *)pnt;
  1403.     checkp.i = pnt_array->xyz[ii];
  1404.     checkp.j = pnt_array->xyz[jj];
  1405.  
  1406.     //@@checkv.i = checkp.i - p1.i;
  1407.     //@@checkv.j = checkp.j - p1.j;
  1408.  
  1409.     //mprintf(0," vec0   = %x,%x  ",vec0.i,vec0.j);
  1410.     //mprintf(0," vec1   = %x,%x  ",vec1.i,vec1.j);
  1411.     //mprintf(0," checkv = %x,%x\n",checkv.i,checkv.j);
  1412.  
  1413.     k1 = -fixdiv(cross(&checkp,&vec0) + cross(&vec0,&p1),cross(&vec0,&vec1));
  1414.     if (vec0.i)
  1415.         k0 = fixdiv(fixmul(-k1,vec1.i) + checkp.i - p1.i,vec0.i);
  1416.     else
  1417.         k0 = fixdiv(fixmul(-k1,vec1.j) + checkp.j - p1.j,vec0.j);
  1418.  
  1419.     //mprintf(0," k0,k1  = %x,%x\n",k0,k1);
  1420.  
  1421.     for (i=0;i<3;i++)
  1422.         uvls[i] = side->uvls[vertnum_list[facenum*3+i]];
  1423.  
  1424.     *u = uvls[1].u + fixmul( k0,uvls[0].u - uvls[1].u) + fixmul(k1,uvls[2].u - uvls[1].u);
  1425.     *v = uvls[1].v + fixmul( k0,uvls[0].v - uvls[1].v) + fixmul(k1,uvls[2].v - uvls[1].v);
  1426.  
  1427.     //mprintf(0," u,v    = %x,%x\n",*u,*v);
  1428. }
  1429.  
  1430. //check if a particular point on a wall is a transparent pixel
  1431. //returns 1 if can pass though the wall, else 0
  1432. int check_trans_wall(vms_vector *pnt,segment *seg,int sidenum,int facenum)
  1433. {
  1434.     grs_bitmap *bm;
  1435.     side *side = &seg->sides[sidenum];
  1436.     int bmx,bmy;
  1437.     fix u,v;
  1438.  
  1439.     Assert(WALL_IS_DOORWAY(seg,sidenum) == WID_TRANSPARENT_WALL);
  1440.  
  1441.     find_hitpoint_uv(&u,&v,pnt,seg,sidenum,facenum);
  1442.  
  1443.     if (side->tmap_num2 != 0)    {
  1444.         bm = texmerge_get_cached_bitmap( side->tmap_num, side->tmap_num2 );
  1445.     } else {
  1446.         bm = &GameBitmaps[Textures[side->tmap_num].index];
  1447.         PIGGY_PAGE_IN( Textures[side->tmap_num] );
  1448.     }
  1449.  
  1450.     if (bm->bm_flags & BM_FLAG_RLE)
  1451.         bm = rle_expand_texture(bm);
  1452.  
  1453.     bmx = ((unsigned) f2i(u*bm->bm_w)) % bm->bm_w;
  1454.     bmy = ((unsigned) f2i(v*bm->bm_h)) % bm->bm_h;
  1455.  
  1456. //note: the line above had -v, but that was wrong, so I changed it.  if 
  1457. //something doesn't work, and you want to make it negative again, you 
  1458. //should figure out what's going on.
  1459.  
  1460.     //mprintf(0," bmx,y  = %d,%d, color=%x\n",bmx,bmy,bm->bm_data[bmy*64+bmx]);
  1461.  
  1462.     return (bm->bm_data[bmy*bm->bm_w+bmx] == 255);
  1463. }
  1464.  
  1465. //new function for Mike
  1466. //note: n_segs_visited must be set to zero before this is called
  1467. int sphere_intersects_wall(vms_vector *pnt,int segnum,fix rad)
  1468. {
  1469.     int facemask;
  1470.     segment *seg;
  1471.  
  1472.     segs_visited[n_segs_visited++] = segnum;
  1473.  
  1474.     facemask = get_seg_masks(pnt,segnum,rad).facemask;
  1475.  
  1476.     seg = &Segments[segnum];
  1477.  
  1478.     if (facemask != 0) {                //on the back of at least one face
  1479.  
  1480.         int side,bit,face;
  1481.  
  1482.         //for each face we are on the back of, check if intersected
  1483.  
  1484.         for (side=0,bit=1;side<6 && facemask>=bit;side++) {
  1485.  
  1486.             for (face=0;face<2;face++,bit<<=1) {
  1487.  
  1488.                 if (facemask & bit) {            //on the back of this face
  1489.                     int face_hit_type;      //in what way did we hit the face?
  1490.                     int num_faces,vertex_list[6];
  1491.  
  1492.                     //did we go through this wall/door?
  1493.  
  1494.                     create_abs_vertex_lists(&num_faces,vertex_list,seg-Segments,side);
  1495.  
  1496.                     face_hit_type = check_sphere_to_face( pnt,seg,&seg->sides[side],
  1497.                                         face,((num_faces==1)?4:3),rad,vertex_list);
  1498.  
  1499.                     if (face_hit_type) {            //through this wall/door
  1500.                         int child,i;
  1501.  
  1502.                         //if what we have hit is a door, check the adjoining seg
  1503.  
  1504.                         child = seg->children[side];
  1505.  
  1506.                         for (i=0;i<n_segs_visited && child!=segs_visited[i];i++);
  1507.  
  1508.                         if (i==n_segs_visited) {                //haven't visited here yet
  1509.  
  1510.                             if (!IS_CHILD(child))
  1511.                                 return 1;
  1512.                             else {
  1513.  
  1514.                                 if (sphere_intersects_wall(pnt,child,rad))
  1515.                                     return 1;
  1516.                             }
  1517.                         }
  1518.                     }
  1519.                 }
  1520.             }
  1521.         }
  1522.     }
  1523.  
  1524.     return 0;
  1525. }
  1526.  
  1527. //Returns true if the object is through any walls
  1528. int object_intersects_wall(object *objp)
  1529. {
  1530.     n_segs_visited = 0;
  1531.  
  1532.     return sphere_intersects_wall(&objp->pos,objp->segnum,objp->size);
  1533. }
  1534.  
  1535. 
  1536.