tr_trace.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. //#define TEST_TRACE
  24. /*
  25. =================
  26. R_LocalTrace
  27. If we resort the vertexes so all silverts come first, we can save some work here.
  28. =================
  29. */
  30. localTrace_t R_LocalTrace( const idVec3 &start, const idVec3 &end, const float radius, const srfTriangles_t *tri ) {
  31. int i, j;
  32. byte * cullBits;
  33. idPlane planes[4];
  34. localTrace_t hit;
  35. int c_testEdges, c_testPlanes, c_intersect;
  36. idVec3 startDir;
  37. byte totalOr;
  38. float radiusSqr;
  39. #ifdef TEST_TRACE
  40. idTimer trace_timer;
  41. trace_timer.Start();
  42. #endif
  43. hit.fraction = 1.0f;
  44. // create two planes orthogonal to each other that intersect along the trace
  45. startDir = end - start;
  46. startDir.Normalize();
  47. startDir.NormalVectors( planes[0].Normal(), planes[1].Normal() );
  48. planes[0][3] = - start * planes[0].Normal();
  49. planes[1][3] = - start * planes[1].Normal();
  50. // create front and end planes so the trace is on the positive sides of both
  51. planes[2] = startDir;
  52. planes[2][3] = - start * planes[2].Normal();
  53. planes[3] = -startDir;
  54. planes[3][3] = - end * planes[3].Normal();
  55. // catagorize each point against the four planes
  56. cullBits = (byte *) _alloca16( tri->numVerts );
  57. SIMDProcessor->TracePointCull( cullBits, totalOr, radius, planes, tri->verts, tri->numVerts );
  58. // if we don't have points on both sides of both the ray planes, no intersection
  59. if ( ( totalOr ^ ( totalOr >> 4 ) ) & 3 ) {
  60. //common->Printf( "nothing crossed the trace planes\n" );
  61. return hit;
  62. }
  63. // if we don't have any points between front and end, no intersection
  64. if ( ( totalOr ^ ( totalOr >> 1 ) ) & 4 ) {
  65. //common->Printf( "trace didn't reach any triangles\n" );
  66. return hit;
  67. }
  68. // scan for triangles that cross both planes
  69. c_testPlanes = 0;
  70. c_testEdges = 0;
  71. c_intersect = 0;
  72. radiusSqr = Square( radius );
  73. startDir = end - start;
  74. if ( !tri->facePlanes || !tri->facePlanesCalculated ) {
  75. R_DeriveFacePlanes( const_cast<srfTriangles_t *>( tri ) );
  76. }
  77. for ( i = 0, j = 0; i < tri->numIndexes; i += 3, j++ ) {
  78. float d1, d2, f, d;
  79. float edgeLengthSqr;
  80. idPlane * plane;
  81. idVec3 point;
  82. idVec3 dir[3];
  83. idVec3 cross;
  84. idVec3 edge;
  85. byte triOr;
  86. // get sidedness info for the triangle
  87. triOr = cullBits[ tri->indexes[i+0] ];
  88. triOr |= cullBits[ tri->indexes[i+1] ];
  89. triOr |= cullBits[ tri->indexes[i+2] ];
  90. // if we don't have points on both sides of both the ray planes, no intersection
  91. if ( ( triOr ^ ( triOr >> 4 ) ) & 3 ) {
  92. continue;
  93. }
  94. // if we don't have any points between front and end, no intersection
  95. if ( ( triOr ^ ( triOr >> 1 ) ) & 4 ) {
  96. continue;
  97. }
  98. c_testPlanes++;
  99. plane = &tri->facePlanes[j];
  100. d1 = plane->Distance( start );
  101. d2 = plane->Distance( end );
  102. if ( d1 <= d2 ) {
  103. continue; // comning at it from behind or parallel
  104. }
  105. if ( d1 < 0.0f ) {
  106. continue; // starts past it
  107. }
  108. if ( d2 > 0.0f ) {
  109. continue; // finishes in front of it
  110. }
  111. f = d1 / ( d1 - d2 );
  112. if ( f < 0.0f ) {
  113. continue; // shouldn't happen
  114. }
  115. if ( f >= hit.fraction ) {
  116. continue; // have already hit something closer
  117. }
  118. c_testEdges++;
  119. // find the exact point of impact with the plane
  120. point = start + f * startDir;
  121. // see if the point is within the three edges
  122. // if radius > 0 the triangle is expanded with a circle in the triangle plane
  123. dir[0] = tri->verts[ tri->indexes[i+0] ].xyz - point;
  124. dir[1] = tri->verts[ tri->indexes[i+1] ].xyz - point;
  125. cross = dir[0].Cross( dir[1] );
  126. d = plane->Normal() * cross;
  127. if ( d > 0.0f ) {
  128. if ( radiusSqr <= 0.0f ) {
  129. continue;
  130. }
  131. edge = tri->verts[ tri->indexes[i+0] ].xyz - tri->verts[ tri->indexes[i+1] ].xyz;
  132. edgeLengthSqr = edge.LengthSqr();
  133. if ( cross.LengthSqr() > edgeLengthSqr * radiusSqr ) {
  134. continue;
  135. }
  136. d = edge * dir[0];
  137. if ( d < 0.0f ) {
  138. edge = tri->verts[ tri->indexes[i+0] ].xyz - tri->verts[ tri->indexes[i+2] ].xyz;
  139. d = edge * dir[0];
  140. if ( d < 0.0f ) {
  141. if ( dir[0].LengthSqr() > radiusSqr ) {
  142. continue;
  143. }
  144. }
  145. } else if ( d > edgeLengthSqr ) {
  146. edge = tri->verts[ tri->indexes[i+1] ].xyz - tri->verts[ tri->indexes[i+2] ].xyz;
  147. d = edge * dir[1];
  148. if ( d < 0.0f ) {
  149. if ( dir[1].LengthSqr() > radiusSqr ) {
  150. continue;
  151. }
  152. }
  153. }
  154. }
  155. dir[2] = tri->verts[ tri->indexes[i+2] ].xyz - point;
  156. cross = dir[1].Cross( dir[2] );
  157. d = plane->Normal() * cross;
  158. if ( d > 0.0f ) {
  159. if ( radiusSqr <= 0.0f ) {
  160. continue;
  161. }
  162. edge = tri->verts[ tri->indexes[i+1] ].xyz - tri->verts[ tri->indexes[i+2] ].xyz;
  163. edgeLengthSqr = edge.LengthSqr();
  164. if ( cross.LengthSqr() > edgeLengthSqr * radiusSqr ) {
  165. continue;
  166. }
  167. d = edge * dir[1];
  168. if ( d < 0.0f ) {
  169. edge = tri->verts[ tri->indexes[i+1] ].xyz - tri->verts[ tri->indexes[i+0] ].xyz;
  170. d = edge * dir[1];
  171. if ( d < 0.0f ) {
  172. if ( dir[1].LengthSqr() > radiusSqr ) {
  173. continue;
  174. }
  175. }
  176. } else if ( d > edgeLengthSqr ) {
  177. edge = tri->verts[ tri->indexes[i+2] ].xyz - tri->verts[ tri->indexes[i+0] ].xyz;
  178. d = edge * dir[2];
  179. if ( d < 0.0f ) {
  180. if ( dir[2].LengthSqr() > radiusSqr ) {
  181. continue;
  182. }
  183. }
  184. }
  185. }
  186. cross = dir[2].Cross( dir[0] );
  187. d = plane->Normal() * cross;
  188. if ( d > 0.0f ) {
  189. if ( radiusSqr <= 0.0f ) {
  190. continue;
  191. }
  192. edge = tri->verts[ tri->indexes[i+2] ].xyz - tri->verts[ tri->indexes[i+0] ].xyz;
  193. edgeLengthSqr = edge.LengthSqr();
  194. if ( cross.LengthSqr() > edgeLengthSqr * radiusSqr ) {
  195. continue;
  196. }
  197. d = edge * dir[2];
  198. if ( d < 0.0f ) {
  199. edge = tri->verts[ tri->indexes[i+2] ].xyz - tri->verts[ tri->indexes[i+1] ].xyz;
  200. d = edge * dir[2];
  201. if ( d < 0.0f ) {
  202. if ( dir[2].LengthSqr() > radiusSqr ) {
  203. continue;
  204. }
  205. }
  206. } else if ( d > edgeLengthSqr ) {
  207. edge = tri->verts[ tri->indexes[i+0] ].xyz - tri->verts[ tri->indexes[i+1] ].xyz;
  208. d = edge * dir[0];
  209. if ( d < 0.0f ) {
  210. if ( dir[0].LengthSqr() > radiusSqr ) {
  211. continue;
  212. }
  213. }
  214. }
  215. }
  216. // we hit it
  217. c_intersect++;
  218. hit.fraction = f;
  219. hit.normal = plane->Normal();
  220. hit.point = point;
  221. hit.indexes[0] = tri->indexes[i];
  222. hit.indexes[1] = tri->indexes[i+1];
  223. hit.indexes[2] = tri->indexes[i+2];
  224. }
  225. #ifdef TEST_TRACE
  226. trace_timer.Stop();
  227. common->Printf( "testVerts:%i c_testPlanes:%i c_testEdges:%i c_intersect:%i msec:%1.4f\n",
  228. tri->numVerts, c_testPlanes, c_testEdges, c_intersect, trace_timer.Milliseconds() );
  229. #endif
  230. return hit;
  231. }
  232. /*
  233. =================
  234. RB_DrawExpandedTriangles
  235. =================
  236. */
  237. void RB_DrawExpandedTriangles( const srfTriangles_t *tri, const float radius, const idVec3 &vieworg ) {
  238. int i, j, k;
  239. idVec3 dir[6], normal, point;
  240. for ( i = 0; i < tri->numIndexes; i += 3 ) {
  241. idVec3 p[3] = { tri->verts[ tri->indexes[ i + 0 ] ].xyz, tri->verts[ tri->indexes[ i + 1 ] ].xyz, tri->verts[ tri->indexes[ i + 2 ] ].xyz };
  242. dir[0] = p[0] - p[1];
  243. dir[1] = p[1] - p[2];
  244. dir[2] = p[2] - p[0];
  245. normal = dir[0].Cross( dir[1] );
  246. if ( normal * p[0] < normal * vieworg ) {
  247. continue;
  248. }
  249. dir[0] = normal.Cross( dir[0] );
  250. dir[1] = normal.Cross( dir[1] );
  251. dir[2] = normal.Cross( dir[2] );
  252. dir[0].Normalize();
  253. dir[1].Normalize();
  254. dir[2].Normalize();
  255. qglBegin( GL_LINE_LOOP );
  256. for ( j = 0; j < 3; j++ ) {
  257. k = ( j + 1 ) % 3;
  258. dir[4] = ( dir[j] + dir[k] ) * 0.5f;
  259. dir[4].Normalize();
  260. dir[3] = ( dir[j] + dir[4] ) * 0.5f;
  261. dir[3].Normalize();
  262. dir[5] = ( dir[4] + dir[k] ) * 0.5f;
  263. dir[5].Normalize();
  264. point = p[k] + dir[j] * radius;
  265. qglVertex3f( point[0], point[1], point[2] );
  266. point = p[k] + dir[3] * radius;
  267. qglVertex3f( point[0], point[1], point[2] );
  268. point = p[k] + dir[4] * radius;
  269. qglVertex3f( point[0], point[1], point[2] );
  270. point = p[k] + dir[5] * radius;
  271. qglVertex3f( point[0], point[1], point[2] );
  272. point = p[k] + dir[k] * radius;
  273. qglVertex3f( point[0], point[1], point[2] );
  274. }
  275. qglEnd();
  276. }
  277. }
  278. /*
  279. ================
  280. RB_ShowTrace
  281. Debug visualization
  282. ================
  283. */
  284. void RB_ShowTrace( drawSurf_t **drawSurfs, int numDrawSurfs ) {
  285. int i;
  286. const srfTriangles_t *tri;
  287. const drawSurf_t *surf;
  288. idVec3 start, end;
  289. idVec3 localStart, localEnd;
  290. localTrace_t hit;
  291. float radius;
  292. if ( r_showTrace.GetInteger() == 0 ) {
  293. return;
  294. }
  295. if ( r_showTrace.GetInteger() == 2 ) {
  296. radius = 5.0f;
  297. } else {
  298. radius = 0.0f;
  299. }
  300. // determine the points of the trace
  301. start = backEnd.viewDef->renderView.vieworg;
  302. end = start + 4000 * backEnd.viewDef->renderView.viewaxis[0];
  303. // check and draw the surfaces
  304. qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
  305. GL_TexEnv( GL_MODULATE );
  306. globalImages->whiteImage->Bind();
  307. // find how many are ambient
  308. for ( i = 0 ; i < numDrawSurfs ; i++ ) {
  309. surf = drawSurfs[i];
  310. tri = surf->geo;
  311. if ( tri == NULL || tri->verts == NULL ) {
  312. continue;
  313. }
  314. // transform the points into local space
  315. R_GlobalPointToLocal( surf->space->modelMatrix, start, localStart );
  316. R_GlobalPointToLocal( surf->space->modelMatrix, end, localEnd );
  317. // check the bounding box
  318. if ( !tri->bounds.Expand( radius ).LineIntersection( localStart, localEnd ) ) {
  319. continue;
  320. }
  321. qglLoadMatrixf( surf->space->modelViewMatrix );
  322. // highlight the surface
  323. GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
  324. qglColor4f( 1, 0, 0, 0.25 );
  325. RB_DrawElementsImmediate( tri );
  326. // draw the bounding box
  327. GL_State( GLS_DEPTHFUNC_ALWAYS );
  328. qglColor4f( 1, 1, 1, 1 );
  329. RB_DrawBounds( tri->bounds );
  330. if ( radius != 0.0f ) {
  331. // draw the expanded triangles
  332. qglColor4f( 0.5f, 0.5f, 1.0f, 1.0f );
  333. RB_DrawExpandedTriangles( tri, radius, localStart );
  334. }
  335. // check the exact surfaces
  336. hit = R_LocalTrace( localStart, localEnd, radius, tri );
  337. if ( hit.fraction < 1.0 ) {
  338. qglColor4f( 1, 1, 1, 1 );
  339. RB_DrawBounds( idBounds( hit.point ).Expand( 1 ) );
  340. }
  341. }
  342. }