pmovetst.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "quakedef.h"
  16. static hull_t box_hull;
  17. static dclipnode_t box_clipnodes[6];
  18. static mplane_t box_planes[6];
  19. extern vec3_t player_mins;
  20. extern vec3_t player_maxs;
  21. /*
  22. ===================
  23. PM_InitBoxHull
  24. Set up the planes and clipnodes so that the six floats of a bounding box
  25. can just be stored out and get a proper hull_t structure.
  26. ===================
  27. */
  28. void PM_InitBoxHull (void)
  29. {
  30. int i;
  31. int side;
  32. box_hull.clipnodes = box_clipnodes;
  33. box_hull.planes = box_planes;
  34. box_hull.firstclipnode = 0;
  35. box_hull.lastclipnode = 5;
  36. for (i=0 ; i<6 ; i++)
  37. {
  38. box_clipnodes[i].planenum = i;
  39. side = i&1;
  40. box_clipnodes[i].children[side] = CONTENTS_EMPTY;
  41. if (i != 5)
  42. box_clipnodes[i].children[side^1] = i + 1;
  43. else
  44. box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
  45. box_planes[i].type = i>>1;
  46. box_planes[i].normal[i>>1] = 1;
  47. }
  48. }
  49. /*
  50. ===================
  51. PM_HullForBox
  52. To keep everything totally uniform, bounding boxes are turned into small
  53. BSP trees instead of being compared directly.
  54. ===================
  55. */
  56. hull_t *PM_HullForBox (vec3_t mins, vec3_t maxs)
  57. {
  58. box_planes[0].dist = maxs[0];
  59. box_planes[1].dist = mins[0];
  60. box_planes[2].dist = maxs[1];
  61. box_planes[3].dist = mins[1];
  62. box_planes[4].dist = maxs[2];
  63. box_planes[5].dist = mins[2];
  64. return &box_hull;
  65. }
  66. /*
  67. ==================
  68. PM_HullPointContents
  69. ==================
  70. */
  71. int PM_HullPointContents (hull_t *hull, int num, vec3_t p)
  72. {
  73. float d;
  74. dclipnode_t *node;
  75. mplane_t *plane;
  76. while (num >= 0)
  77. {
  78. if (num < hull->firstclipnode || num > hull->lastclipnode)
  79. Sys_Error ("PM_HullPointContents: bad node number");
  80. node = hull->clipnodes + num;
  81. plane = hull->planes + node->planenum;
  82. if (plane->type < 3)
  83. d = p[plane->type] - plane->dist;
  84. else
  85. d = DotProduct (plane->normal, p) - plane->dist;
  86. if (d < 0)
  87. num = node->children[1];
  88. else
  89. num = node->children[0];
  90. }
  91. return num;
  92. }
  93. /*
  94. ==================
  95. PM_PointContents
  96. ==================
  97. */
  98. int PM_PointContents (vec3_t p)
  99. {
  100. float d;
  101. dclipnode_t *node;
  102. mplane_t *plane;
  103. hull_t *hull;
  104. int num;
  105. hull = &pmove.physents[0].model->hulls[0];
  106. num = hull->firstclipnode;
  107. while (num >= 0)
  108. {
  109. if (num < hull->firstclipnode || num > hull->lastclipnode)
  110. Sys_Error ("PM_HullPointContents: bad node number");
  111. node = hull->clipnodes + num;
  112. plane = hull->planes + node->planenum;
  113. if (plane->type < 3)
  114. d = p[plane->type] - plane->dist;
  115. else
  116. d = DotProduct (plane->normal, p) - plane->dist;
  117. if (d < 0)
  118. num = node->children[1];
  119. else
  120. num = node->children[0];
  121. }
  122. return num;
  123. }
  124. /*
  125. ===============================================================================
  126. LINE TESTING IN HULLS
  127. ===============================================================================
  128. */
  129. // 1/32 epsilon to keep floating point happy
  130. #define DIST_EPSILON (0.03125)
  131. /*
  132. ==================
  133. PM_RecursiveHullCheck
  134. ==================
  135. */
  136. qboolean PM_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace)
  137. {
  138. dclipnode_t *node;
  139. mplane_t *plane;
  140. float t1, t2;
  141. float frac;
  142. int i;
  143. vec3_t mid;
  144. int side;
  145. float midf;
  146. // check for empty
  147. if (num < 0)
  148. {
  149. if (num != CONTENTS_SOLID)
  150. {
  151. trace->allsolid = false;
  152. if (num == CONTENTS_EMPTY)
  153. trace->inopen = true;
  154. else
  155. trace->inwater = true;
  156. }
  157. else
  158. trace->startsolid = true;
  159. return true; // empty
  160. }
  161. if (num < hull->firstclipnode || num > hull->lastclipnode)
  162. Sys_Error ("PM_RecursiveHullCheck: bad node number");
  163. //
  164. // find the point distances
  165. //
  166. node = hull->clipnodes + num;
  167. plane = hull->planes + node->planenum;
  168. if (plane->type < 3)
  169. {
  170. t1 = p1[plane->type] - plane->dist;
  171. t2 = p2[plane->type] - plane->dist;
  172. }
  173. else
  174. {
  175. t1 = DotProduct (plane->normal, p1) - plane->dist;
  176. t2 = DotProduct (plane->normal, p2) - plane->dist;
  177. }
  178. #if 1
  179. if (t1 >= 0 && t2 >= 0)
  180. return PM_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
  181. if (t1 < 0 && t2 < 0)
  182. return PM_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
  183. #else
  184. if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
  185. return PM_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
  186. if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
  187. return PM_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
  188. #endif
  189. // put the crosspoint DIST_EPSILON pixels on the near side
  190. if (t1 < 0)
  191. frac = (t1 + DIST_EPSILON)/(t1-t2);
  192. else
  193. frac = (t1 - DIST_EPSILON)/(t1-t2);
  194. if (frac < 0)
  195. frac = 0;
  196. if (frac > 1)
  197. frac = 1;
  198. midf = p1f + (p2f - p1f)*frac;
  199. for (i=0 ; i<3 ; i++)
  200. mid[i] = p1[i] + frac*(p2[i] - p1[i]);
  201. side = (t1 < 0);
  202. // move up to the node
  203. if (!PM_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
  204. return false;
  205. #ifdef PARANOID
  206. if (PM_HullPointContents (pm_hullmodel, mid, node->children[side])
  207. == CONTENTS_SOLID)
  208. {
  209. Con_Printf ("mid PointInHullSolid\n");
  210. return false;
  211. }
  212. #endif
  213. if (PM_HullPointContents (hull, node->children[side^1], mid)
  214. != CONTENTS_SOLID)
  215. // go past the node
  216. return PM_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
  217. if (trace->allsolid)
  218. return false; // never got out of the solid area
  219. //==================
  220. // the other side of the node is solid, this is the impact point
  221. //==================
  222. if (!side)
  223. {
  224. VectorCopy (plane->normal, trace->plane.normal);
  225. trace->plane.dist = plane->dist;
  226. }
  227. else
  228. {
  229. VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
  230. trace->plane.dist = -plane->dist;
  231. }
  232. while (PM_HullPointContents (hull, hull->firstclipnode, mid)
  233. == CONTENTS_SOLID)
  234. { // shouldn't really happen, but does occasionally
  235. frac -= 0.1;
  236. if (frac < 0)
  237. {
  238. trace->fraction = midf;
  239. VectorCopy (mid, trace->endpos);
  240. Con_DPrintf ("backup past 0\n");
  241. return false;
  242. }
  243. midf = p1f + (p2f - p1f)*frac;
  244. for (i=0 ; i<3 ; i++)
  245. mid[i] = p1[i] + frac*(p2[i] - p1[i]);
  246. }
  247. trace->fraction = midf;
  248. VectorCopy (mid, trace->endpos);
  249. return false;
  250. }
  251. /*
  252. ================
  253. PM_TestPlayerPosition
  254. Returns false if the given player position is not valid (in solid)
  255. ================
  256. */
  257. qboolean PM_TestPlayerPosition (vec3_t pos)
  258. {
  259. int i;
  260. physent_t *pe;
  261. vec3_t mins, maxs, test;
  262. hull_t *hull;
  263. for (i=0 ; i< pmove.numphysent ; i++)
  264. {
  265. pe = &pmove.physents[i];
  266. // get the clipping hull
  267. if (pe->model)
  268. hull = &pmove.physents[i].model->hulls[1];
  269. else
  270. {
  271. VectorSubtract (pe->mins, player_maxs, mins);
  272. VectorSubtract (pe->maxs, player_mins, maxs);
  273. hull = PM_HullForBox (mins, maxs);
  274. }
  275. VectorSubtract (pos, pe->origin, test);
  276. if (PM_HullPointContents (hull, hull->firstclipnode, test) == CONTENTS_SOLID)
  277. return false;
  278. }
  279. return true;
  280. }
  281. /*
  282. ================
  283. PM_PlayerMove
  284. ================
  285. */
  286. pmtrace_t PM_PlayerMove (vec3_t start, vec3_t end)
  287. {
  288. pmtrace_t trace, total;
  289. vec3_t offset;
  290. vec3_t start_l, end_l;
  291. hull_t *hull;
  292. int i;
  293. physent_t *pe;
  294. vec3_t mins, maxs;
  295. // fill in a default trace
  296. memset (&total, 0, sizeof(pmtrace_t));
  297. total.fraction = 1;
  298. total.ent = -1;
  299. VectorCopy (end, total.endpos);
  300. for (i=0 ; i< pmove.numphysent ; i++)
  301. {
  302. pe = &pmove.physents[i];
  303. // get the clipping hull
  304. if (pe->model)
  305. hull = &pmove.physents[i].model->hulls[1];
  306. else
  307. {
  308. VectorSubtract (pe->mins, player_maxs, mins);
  309. VectorSubtract (pe->maxs, player_mins, maxs);
  310. hull = PM_HullForBox (mins, maxs);
  311. }
  312. // PM_HullForEntity (ent, mins, maxs, offset);
  313. VectorCopy (pe->origin, offset);
  314. VectorSubtract (start, offset, start_l);
  315. VectorSubtract (end, offset, end_l);
  316. // fill in a default trace
  317. memset (&trace, 0, sizeof(pmtrace_t));
  318. trace.fraction = 1;
  319. trace.allsolid = true;
  320. // trace.startsolid = true;
  321. VectorCopy (end, trace.endpos);
  322. // trace a line through the apropriate clipping hull
  323. PM_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
  324. if (trace.allsolid)
  325. trace.startsolid = true;
  326. if (trace.startsolid)
  327. trace.fraction = 0;
  328. // did we clip the move?
  329. if (trace.fraction < total.fraction)
  330. {
  331. // fix trace up by the offset
  332. VectorAdd (trace.endpos, offset, trace.endpos);
  333. total = trace;
  334. total.ent = i;
  335. }
  336. }
  337. return total;
  338. }