light_trace.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "light.h"
  19. #define CURVE_FACET_ERROR 8
  20. int c_totalTrace;
  21. int c_cullTrace, c_testTrace;
  22. int c_testFacets;
  23. surfaceTest_t *surfaceTest[MAX_MAP_DRAW_SURFS];
  24. /*
  25. =====================
  26. CM_GenerateBoundaryForPoints
  27. =====================
  28. */
  29. void CM_GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
  30. vec3_t d1;
  31. // amke a perpendicular vector to the edge and the surface
  32. VectorSubtract( b, a, d1 );
  33. CrossProduct( plane, d1, boundary );
  34. VectorNormalize( boundary, boundary );
  35. boundary[3] = DotProduct( a, boundary );
  36. }
  37. /*
  38. =====================
  39. TextureMatrixFromPoints
  40. =====================
  41. */
  42. void TextureMatrixFromPoints( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
  43. int i, j;
  44. float t;
  45. float m[3][4];
  46. float s;
  47. // This is an incredibly stupid way of solving a three variable equation
  48. for ( i = 0 ; i < 2 ; i++ ) {
  49. m[0][0] = a->xyz[0];
  50. m[0][1] = a->xyz[1];
  51. m[0][2] = a->xyz[2];
  52. m[0][3] = a->st[i];
  53. m[1][0] = b->xyz[0];
  54. m[1][1] = b->xyz[1];
  55. m[1][2] = b->xyz[2];
  56. m[1][3] = b->st[i];
  57. m[2][0] = c->xyz[0];
  58. m[2][1] = c->xyz[1];
  59. m[2][2] = c->xyz[2];
  60. m[2][3] = c->st[i];
  61. if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
  62. for ( j = 0 ; j < 4 ; j ++ ) {
  63. t = m[0][j];
  64. m[0][j] = m[1][j];
  65. m[1][j] = t;
  66. }
  67. } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
  68. for ( j = 0 ; j < 4 ; j ++ ) {
  69. t = m[0][j];
  70. m[0][j] = m[2][j];
  71. m[2][j] = t;
  72. }
  73. }
  74. s = 1.0 / m[0][0];
  75. m[0][0] *= s;
  76. m[0][1] *= s;
  77. m[0][2] *= s;
  78. m[0][3] *= s;
  79. s = m[1][0];
  80. m[1][0] -= m[0][0] * s;
  81. m[1][1] -= m[0][1] * s;
  82. m[1][2] -= m[0][2] * s;
  83. m[1][3] -= m[0][3] * s;
  84. s = m[2][0];
  85. m[2][0] -= m[0][0] * s;
  86. m[2][1] -= m[0][1] * s;
  87. m[2][2] -= m[0][2] * s;
  88. m[2][3] -= m[0][3] * s;
  89. if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
  90. for ( j = 0 ; j < 4 ; j ++ ) {
  91. t = m[1][j];
  92. m[1][j] = m[2][j];
  93. m[2][j] = t;
  94. }
  95. }
  96. s = 1.0 / m[1][1];
  97. m[1][0] *= s;
  98. m[1][1] *= s;
  99. m[1][2] *= s;
  100. m[1][3] *= s;
  101. s = m[2][1];
  102. m[2][0] -= m[1][0] * s;
  103. m[2][1] -= m[1][1] * s;
  104. m[2][2] -= m[1][2] * s;
  105. m[2][3] -= m[1][3] * s;
  106. s = 1.0 / m[2][2];
  107. m[2][0] *= s;
  108. m[2][1] *= s;
  109. m[2][2] *= s;
  110. m[2][3] *= s;
  111. f->textureMatrix[i][2] = m[2][3];
  112. f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
  113. f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
  114. f->textureMatrix[i][3] = 0;
  115. /*
  116. s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
  117. if ( s > 0.01 ) {
  118. Error( "Bad textureMatrix" );
  119. }
  120. s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
  121. if ( s > 0.01 ) {
  122. Error( "Bad textureMatrix" );
  123. }
  124. s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
  125. if ( s > 0.01 ) {
  126. Error( "Bad textureMatrix" );
  127. }
  128. */
  129. }
  130. }
  131. /*
  132. =====================
  133. CM_GenerateFacetFor3Points
  134. =====================
  135. */
  136. qboolean CM_GenerateFacetFor3Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
  137. // if we can't generate a valid plane for the points, ignore the facet
  138. if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
  139. f->numBoundaries = 0;
  140. return qfalse;
  141. }
  142. // make boundaries
  143. f->numBoundaries = 3;
  144. CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
  145. CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
  146. CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, a->xyz );
  147. VectorCopy( a->xyz, f->points[0] );
  148. VectorCopy( b->xyz, f->points[1] );
  149. VectorCopy( c->xyz, f->points[2] );
  150. TextureMatrixFromPoints( f, a, b, c );
  151. return qtrue;
  152. }
  153. /*
  154. =====================
  155. CM_GenerateFacetFor4Points
  156. Attempts to use four points as a planar quad
  157. =====================
  158. */
  159. #define PLANAR_EPSILON 0.1
  160. qboolean CM_GenerateFacetFor4Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
  161. float dist;
  162. int i;
  163. vec4_t plane;
  164. // if we can't generate a valid plane for the points, ignore the facet
  165. if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
  166. f->numBoundaries = 0;
  167. return qfalse;
  168. }
  169. // if the fourth point is also on the plane, we can make a quad facet
  170. dist = DotProduct( d->xyz, f->surface ) - f->surface[3];
  171. if ( fabs( dist ) > PLANAR_EPSILON ) {
  172. f->numBoundaries = 0;
  173. return qfalse;
  174. }
  175. // make boundaries
  176. f->numBoundaries = 4;
  177. CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
  178. CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
  179. CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, d->xyz );
  180. CM_GenerateBoundaryForPoints( f->boundaries[3], f->surface, d->xyz, a->xyz );
  181. VectorCopy( a->xyz, f->points[0] );
  182. VectorCopy( b->xyz, f->points[1] );
  183. VectorCopy( c->xyz, f->points[2] );
  184. VectorCopy( d->xyz, f->points[3] );
  185. for (i = 1; i < 4; i++)
  186. {
  187. if ( !PlaneFromPoints( plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
  188. f->numBoundaries = 0;
  189. return qfalse;
  190. }
  191. if (DotProduct(f->surface, plane) < 0.9) {
  192. f->numBoundaries = 0;
  193. return qfalse;
  194. }
  195. }
  196. TextureMatrixFromPoints( f, a, b, c );
  197. return qtrue;
  198. }
  199. /*
  200. ===============
  201. SphereFromBounds
  202. ===============
  203. */
  204. void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
  205. vec3_t temp;
  206. VectorAdd( mins, maxs, origin );
  207. VectorScale( origin, 0.5, origin );
  208. VectorSubtract( maxs, origin, temp );
  209. *radius = VectorLength( temp );
  210. }
  211. /*
  212. ====================
  213. FacetsForTriangleSurface
  214. ====================
  215. */
  216. void FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
  217. int i;
  218. drawVert_t *v1, *v2, *v3, *v4;
  219. int count;
  220. int i1, i2, i3, i4, i5, i6;
  221. test->patch = qfalse;
  222. test->numFacets = dsurf->numIndexes / 3;
  223. test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
  224. test->shader = si;
  225. count = 0;
  226. for ( i = 0 ; i < test->numFacets ; i++ ) {
  227. i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
  228. i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
  229. i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
  230. v1 = &drawVerts[ dsurf->firstVert + i1 ];
  231. v2 = &drawVerts[ dsurf->firstVert + i2 ];
  232. v3 = &drawVerts[ dsurf->firstVert + i3 ];
  233. // try and make a quad out of two triangles
  234. if ( i != test->numFacets - 1 ) {
  235. i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
  236. i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
  237. i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
  238. if ( i4 == i3 && i5 == i2 ) {
  239. v4 = &drawVerts[ dsurf->firstVert + i6 ];
  240. if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v2, v4, v3 ) ) {
  241. count++;
  242. i++; // skip next tri
  243. continue;
  244. }
  245. }
  246. }
  247. if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v2, v3 ))
  248. count++;
  249. }
  250. // we may have turned some pairs into quads
  251. test->numFacets = count;
  252. }
  253. /*
  254. ====================
  255. FacetsForPatch
  256. ====================
  257. */
  258. void FacetsForPatch( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
  259. int i, j;
  260. drawVert_t *v1, *v2, *v3, *v4;
  261. int count;
  262. mesh_t srcMesh, *subdivided, *mesh;
  263. srcMesh.width = dsurf->patchWidth;
  264. srcMesh.height = dsurf->patchHeight;
  265. srcMesh.verts = &drawVerts[ dsurf->firstVert ];
  266. //subdivided = SubdivideMesh( mesh, CURVE_FACET_ERROR, 9999 );
  267. mesh = SubdivideMesh( srcMesh, 8, 999 );
  268. PutMeshOnCurve( *mesh );
  269. MakeMeshNormals( *mesh );
  270. subdivided = RemoveLinearMeshColumnsRows( mesh );
  271. FreeMesh(mesh);
  272. test->patch = qtrue;
  273. test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
  274. test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
  275. test->shader = si;
  276. count = 0;
  277. for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
  278. for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
  279. v1 = subdivided->verts + j * subdivided->width + i;
  280. v2 = v1 + 1;
  281. v3 = v1 + subdivided->width + 1;
  282. v4 = v1 + subdivided->width;
  283. if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v4, v3, v2 ) ) {
  284. count++;
  285. } else {
  286. if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v4, v3 ))
  287. count++;
  288. if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v3, v2 ))
  289. count++;
  290. }
  291. }
  292. }
  293. test->numFacets = count;
  294. FreeMesh(subdivided);
  295. }
  296. /*
  297. =====================
  298. InitSurfacesForTesting
  299. Builds structures to speed the ray tracing against surfaces
  300. =====================
  301. */
  302. void InitSurfacesForTesting( void ) {
  303. int i, j;
  304. dsurface_t *dsurf;
  305. surfaceTest_t *test;
  306. drawVert_t *dvert;
  307. shaderInfo_t *si;
  308. for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
  309. dsurf = &drawSurfaces[ i ];
  310. if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
  311. continue;
  312. }
  313. // don't make surfaces for transparent objects
  314. // because we want light to pass through them
  315. si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
  316. if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
  317. continue;
  318. }
  319. test = malloc( sizeof( *test ) );
  320. surfaceTest[i] = test;
  321. ClearBounds( test->mins, test->maxs );
  322. dvert = &drawVerts[ dsurf->firstVert ];
  323. for ( j = 0 ; j < dsurf->numVerts ; j++, dvert++ ) {
  324. AddPointToBounds( dvert->xyz, test->mins, test->maxs );
  325. }
  326. SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
  327. if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
  328. FacetsForTriangleSurface( dsurf, si, test );
  329. } else if ( dsurf->surfaceType == MST_PATCH ) {
  330. FacetsForPatch( dsurf, si, test );
  331. }
  332. }
  333. }
  334. /*
  335. =====================
  336. GenerateBoundaryForPoints
  337. =====================
  338. */
  339. void GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
  340. vec3_t d1;
  341. // amke a perpendicular vector to the edge and the surface
  342. VectorSubtract( b, a, d1 );
  343. CrossProduct( plane, d1, boundary );
  344. VectorNormalize( boundary, boundary );
  345. boundary[3] = DotProduct( a, boundary );
  346. }
  347. /*
  348. =================
  349. SetFacetFilter
  350. Given a point on a facet, determine the color filter
  351. for light passing through
  352. =================
  353. */
  354. void SetFacetFilter( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet, vec3_t point ) {
  355. float s, t;
  356. int is, it;
  357. byte *image;
  358. int b;
  359. // most surfaces are completely opaque
  360. if ( !(shader->surfaceFlags & SURF_ALPHASHADOW) ) {
  361. VectorClear( tr->trace->filter );
  362. return;
  363. }
  364. s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
  365. t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
  366. if ( !shader->pixels ) {
  367. // assume completely solid
  368. VectorClear( point );
  369. return;
  370. }
  371. s = s - floor( s );
  372. t = t - floor( t );
  373. is = s * shader->width;
  374. it = t * shader->height;
  375. image = shader->pixels + 4 * ( it * shader->width + is );
  376. // alpha filter
  377. b = image[3];
  378. // alpha test makes this a binary option
  379. b = b < 128 ? 0 : 255;
  380. tr->trace->filter[0] = tr->trace->filter[0] * (255-b) / 255;
  381. tr->trace->filter[1] = tr->trace->filter[1] * (255-b) / 255;
  382. tr->trace->filter[2] = tr->trace->filter[2] * (255-b) / 255;
  383. }
  384. /*
  385. ====================
  386. TraceAgainstFacet
  387. Shader is needed for translucent surfaces
  388. ====================
  389. */
  390. void TraceAgainstFacet( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet ) {
  391. int j;
  392. float d1, d2, d, f;
  393. vec3_t point;
  394. float dist;
  395. // ignore degenerate facets
  396. if ( facet->numBoundaries < 3 ) {
  397. return;
  398. }
  399. dist = facet->surface[3];
  400. // compare the trace endpoints against the facet plane
  401. d1 = DotProduct( tr->start, facet->surface ) - dist;
  402. if ( d1 > -1 && d1 < 1 ) {
  403. return; // don't self intersect
  404. }
  405. d2 = DotProduct( tr->end, facet->surface ) - dist;
  406. if ( d2 > -1 && d2 < 1 ) {
  407. return; // don't self intersect
  408. }
  409. // calculate the intersection fraction
  410. f = ( d1 - ON_EPSILON ) / ( d1 - d2 );
  411. if ( f <= 0 ) {
  412. return;
  413. }
  414. if ( f >= tr->trace->hitFraction ) {
  415. return; // we have hit something earlier
  416. }
  417. // calculate the intersection point
  418. for ( j = 0 ; j < 3 ; j++ ) {
  419. point[j] = tr->start[j] + f * ( tr->end[j] - tr->start[j] );
  420. }
  421. // check the point against the facet boundaries
  422. for ( j = 0 ; j < facet->numBoundaries ; j++ ) {
  423. // adjust the plane distance apropriately for mins/maxs
  424. dist = facet->boundaries[j][3];
  425. d = DotProduct( point, facet->boundaries[j] );
  426. if ( d > dist + ON_EPSILON ) {
  427. break; // outside the bounds
  428. }
  429. }
  430. if ( j != facet->numBoundaries ) {
  431. return; // we are outside the bounds of the facet
  432. }
  433. // we hit this facet
  434. // if this is a transparent surface, calculate filter value
  435. if ( shader->surfaceFlags & SURF_ALPHASHADOW ) {
  436. SetFacetFilter( tr, shader, facet, point );
  437. } else {
  438. // completely opaque
  439. VectorClear( tr->trace->filter );
  440. tr->trace->hitFraction = f;
  441. }
  442. // VectorCopy( facet->surface, tr->trace->plane.normal );
  443. // tr->trace->plane.dist = facet->surface[3];
  444. }
  445. /*
  446. ===============================================================
  447. LINE TRACING
  448. ===============================================================
  449. */
  450. #define TRACE_ON_EPSILON 0.1
  451. typedef struct tnode_s
  452. {
  453. int type;
  454. vec3_t normal;
  455. float dist;
  456. int children[2];
  457. int planeNum;
  458. } tnode_t;
  459. #define MAX_TNODES (MAX_MAP_NODES*4)
  460. tnode_t *tnodes, *tnode_p;
  461. /*
  462. ==============
  463. MakeTnode
  464. Converts the disk node structure into the efficient tracing structure
  465. ==============
  466. */
  467. void MakeTnode (int nodenum)
  468. {
  469. tnode_t *t;
  470. dplane_t *plane;
  471. int i;
  472. dnode_t *node;
  473. int leafNum;
  474. t = tnode_p++;
  475. node = dnodes + nodenum;
  476. plane = dplanes + node->planeNum;
  477. t->planeNum = node->planeNum;
  478. t->type = PlaneTypeForNormal( plane->normal );
  479. VectorCopy (plane->normal, t->normal);
  480. t->dist = plane->dist;
  481. for (i=0 ; i<2 ; i++)
  482. {
  483. if (node->children[i] < 0) {
  484. leafNum = -node->children[i] - 1;
  485. if ( dleafs[leafNum].cluster == -1 ) {
  486. // solid
  487. t->children[i] = leafNum | ( 1 << 31 ) | ( 1 << 30 );
  488. } else {
  489. t->children[i] = leafNum | ( 1 << 31 );
  490. }
  491. } else {
  492. t->children[i] = tnode_p - tnodes;
  493. MakeTnode (node->children[i]);
  494. }
  495. }
  496. }
  497. /*
  498. =============
  499. InitTrace
  500. Loads the node structure out of a .bsp file to be used for light occlusion
  501. =============
  502. */
  503. void InitTrace( void ) {
  504. // 32 byte align the structs
  505. tnodes = malloc( (MAX_TNODES+1) * sizeof(tnode_t));
  506. tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
  507. tnode_p = tnodes;
  508. MakeTnode (0);
  509. InitSurfacesForTesting();
  510. }
  511. /*
  512. ===================
  513. PointInSolid
  514. ===================
  515. */
  516. qboolean PointInSolid_r( vec3_t start, int node ) {
  517. tnode_t *tnode;
  518. float front;
  519. while ( !(node & (1<<31) ) ) {
  520. tnode = &tnodes[node];
  521. switch (tnode->type) {
  522. case PLANE_X:
  523. front = start[0] - tnode->dist;
  524. break;
  525. case PLANE_Y:
  526. front = start[1] - tnode->dist;
  527. break;
  528. case PLANE_Z:
  529. front = start[2] - tnode->dist;
  530. break;
  531. default:
  532. front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
  533. break;
  534. }
  535. if ( front == 0 ) {
  536. // exactly on node, must check both sides
  537. return (qboolean) ( PointInSolid_r( start, tnode->children[0] )
  538. | PointInSolid_r( start, tnode->children[1] ) );
  539. }
  540. if ( front > 0 ) {
  541. node = tnode->children[0];
  542. } else {
  543. node = tnode->children[1];
  544. }
  545. }
  546. if ( node & ( 1 << 30 ) ) {
  547. return qtrue;
  548. }
  549. return qfalse;
  550. }
  551. /*
  552. =============
  553. PointInSolid
  554. =============
  555. */
  556. qboolean PointInSolid( vec3_t start ) {
  557. return PointInSolid_r( start, 0 );
  558. }
  559. /*
  560. =============
  561. TraceLine_r
  562. Returns qtrue if something is hit and tracing can stop
  563. =============
  564. */
  565. int TraceLine_r( int node, const vec3_t start, const vec3_t stop, traceWork_t *tw ) {
  566. tnode_t *tnode;
  567. float front, back;
  568. vec3_t mid;
  569. float frac;
  570. int side;
  571. int r;
  572. if (node & (1<<31)) {
  573. if (node & ( 1 << 30 ) ) {
  574. VectorCopy (start, tw->trace->hit);
  575. tw->trace->passSolid = qtrue;
  576. return qtrue;
  577. } else {
  578. // save the node off for more exact testing
  579. if ( tw->numOpenLeafs == MAX_MAP_LEAFS ) {
  580. return qfalse;
  581. }
  582. tw->openLeafNumbers[ tw->numOpenLeafs ] = node & ~(3 << 30);
  583. tw->numOpenLeafs++;
  584. return qfalse;
  585. }
  586. }
  587. tnode = &tnodes[node];
  588. switch (tnode->type) {
  589. case PLANE_X:
  590. front = start[0] - tnode->dist;
  591. back = stop[0] - tnode->dist;
  592. break;
  593. case PLANE_Y:
  594. front = start[1] - tnode->dist;
  595. back = stop[1] - tnode->dist;
  596. break;
  597. case PLANE_Z:
  598. front = start[2] - tnode->dist;
  599. back = stop[2] - tnode->dist;
  600. break;
  601. default:
  602. front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
  603. back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
  604. break;
  605. }
  606. if (front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) {
  607. return TraceLine_r (tnode->children[0], start, stop, tw);
  608. }
  609. if (front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) {
  610. return TraceLine_r (tnode->children[1], start, stop, tw);
  611. }
  612. side = front < 0;
  613. frac = front / (front-back);
  614. mid[0] = start[0] + (stop[0] - start[0])*frac;
  615. mid[1] = start[1] + (stop[1] - start[1])*frac;
  616. mid[2] = start[2] + (stop[2] - start[2])*frac;
  617. r = TraceLine_r (tnode->children[side], start, mid, tw);
  618. if (r) {
  619. return r;
  620. }
  621. // trace->planeNum = tnode->planeNum;
  622. return TraceLine_r (tnode->children[!side], mid, stop, tw);
  623. }
  624. //==========================================================================================
  625. /*
  626. ================
  627. SphereCull
  628. ================
  629. */
  630. qboolean SphereCull( vec3_t start, vec3_t stop, vec3_t origin, float radius ) {
  631. vec3_t v;
  632. float d;
  633. vec3_t dir;
  634. float len;
  635. vec3_t on;
  636. VectorSubtract( stop, start, dir );
  637. len = VectorNormalize( dir, dir );
  638. VectorSubtract( origin, start, v );
  639. d = DotProduct( v, dir );
  640. if ( d > len + radius ) {
  641. return qtrue; // too far ahead
  642. }
  643. if ( d < -radius ) {
  644. return qtrue; // too far behind
  645. }
  646. VectorMA( start, d, dir, on );
  647. VectorSubtract( on, origin, v );
  648. len = VectorLength( v );
  649. if ( len > radius ) {
  650. return qtrue; // too far to the side
  651. }
  652. return qfalse; // must be traced against
  653. }
  654. /*
  655. ================
  656. TraceAgainstSurface
  657. ================
  658. */
  659. void TraceAgainstSurface( traceWork_t *tw, surfaceTest_t *surf ) {
  660. int i;
  661. // if surfaces are trans
  662. if ( SphereCull( tw->start, tw->end, surf->origin, surf->radius ) ) {
  663. if ( numthreads == 1 ) {
  664. c_cullTrace++;
  665. }
  666. return;
  667. }
  668. if ( numthreads == 1 ) {
  669. c_testTrace++;
  670. c_testFacets += surf->numFacets;
  671. }
  672. /*
  673. // MrE: backface culling
  674. if (!surf->patch && surf->numFacets) {
  675. // if the surface does not cast an alpha shadow
  676. if ( !(surf->shader->surfaceFlags & SURF_ALPHASHADOW) ) {
  677. vec3_t vec;
  678. VectorSubtract(tw->end, tw->start, vec);
  679. if (DotProduct(vec, surf->facets->surface) > 0)
  680. return;
  681. }
  682. }
  683. */
  684. // test against each facet
  685. for ( i = 0 ; i < surf->numFacets ; i++ ) {
  686. TraceAgainstFacet( tw, surf->shader, surf->facets + i );
  687. }
  688. }
  689. /*
  690. =============
  691. TraceLine
  692. Follow the trace just through the solid leafs first, and only
  693. if it passes that, trace against the objects inside the empty leafs
  694. Returns qtrue if the trace hit any
  695. traceWork_t is only a parameter to crutch up poor large local allocations on
  696. winNT and macOS. It should be allocated in the worker function, but never
  697. looked at.
  698. leave testAll false if all you care about is if it hit anything at all.
  699. if you need to know the exact first point of impact (for a sun trace), set
  700. testAll to true
  701. =============
  702. */
  703. extern qboolean patchshadows;
  704. void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace, qboolean testAll, traceWork_t *tw ) {
  705. int r;
  706. int i, j;
  707. dleaf_t *leaf;
  708. float oldHitFrac;
  709. surfaceTest_t *test;
  710. int surfaceNum;
  711. byte surfaceTested[MAX_MAP_DRAW_SURFS/8];
  712. ;
  713. if ( numthreads == 1 ) {
  714. c_totalTrace++;
  715. }
  716. // assume all light gets through, unless the ray crosses
  717. // a translucent surface
  718. trace->filter[0] = 1.0;
  719. trace->filter[1] = 1.0;
  720. trace->filter[2] = 1.0;
  721. VectorCopy( start, tw->start );
  722. VectorCopy( stop, tw->end );
  723. tw->trace = trace;
  724. tw->numOpenLeafs = 0;
  725. trace->passSolid = qfalse;
  726. trace->hitFraction = 1.0;
  727. r = TraceLine_r( 0, start, stop, tw );
  728. // if we hit a solid leaf, stop without testing the leaf
  729. // surfaces. Note that the plane and endpoint might not
  730. // be the first solid intersection along the ray.
  731. if ( r && !testAll ) {
  732. return;
  733. }
  734. if ( noSurfaces ) {
  735. return;
  736. }
  737. memset( surfaceTested, 0, (numDrawSurfaces+7)/8 );
  738. oldHitFrac = trace->hitFraction;
  739. for ( i = 0 ; i < tw->numOpenLeafs ; i++ ) {
  740. leaf = &dleafs[ tw->openLeafNumbers[ i ] ];
  741. for ( j = 0 ; j < leaf->numLeafSurfaces ; j++ ) {
  742. surfaceNum = dleafsurfaces[ leaf->firstLeafSurface + j ];
  743. // make sure we don't test the same ray against a surface more than once
  744. if ( surfaceTested[ surfaceNum>>3 ] & ( 1 << ( surfaceNum & 7) ) ) {
  745. continue;
  746. }
  747. surfaceTested[ surfaceNum>>3 ] |= ( 1 << ( surfaceNum & 7 ) );
  748. test = surfaceTest[ surfaceNum ];
  749. if ( !test ) {
  750. continue;
  751. }
  752. //
  753. if ( !tw->patchshadows && test->patch ) {
  754. continue;
  755. }
  756. TraceAgainstSurface( tw, test );
  757. }
  758. // if the trace is now solid, we can't possibly hit anything closer
  759. if ( trace->hitFraction < oldHitFrac ) {
  760. trace->passSolid = qtrue;
  761. break;
  762. }
  763. }
  764. for ( i = 0 ; i < 3 ; i++ ) {
  765. trace->hit[i] = start[i] + ( stop[i] - start[i] ) * trace->hitFraction;
  766. }
  767. }