Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

798 lines
21 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. // trace.c
  9. //=============================================================================
  10. #include "vrad.h"
  11. #include "trace.h"
  12. #include "Cmodel.h"
  13. #include "mathlib/vmatrix.h"
  14. //=============================================================================
  15. class CToolTrace : public CBaseTrace
  16. {
  17. public:
  18. CToolTrace() {}
  19. Vector mins;
  20. Vector maxs;
  21. Vector extents;
  22. texinfo_t *surface;
  23. qboolean ispoint;
  24. private:
  25. CToolTrace( const CToolTrace& );
  26. };
  27. // 1/32 epsilon to keep floating point happy
  28. #define DIST_EPSILON (0.03125)
  29. // JAYHL2: This used to be -1, but that caused lots of epsilon issues
  30. // around slow sloping planes. Perhaps Quake2 limited maps to a certain
  31. // slope / angle on walkable ground. It has to be a negative number
  32. // so that the tests work out.
  33. #define NEVER_UPDATED -9999
  34. //=============================================================================
  35. bool DM_RayDispIntersectTest( CVRADDispColl *pTree, Vector& rayStart, Vector& rayEnd, CToolTrace *pTrace );
  36. void DM_ClipBoxToBrush( CToolTrace *trace, const Vector & mins, const Vector & maxs, const Vector& p1, const Vector& p2, dbrush_t *brush );
  37. //=============================================================================
  38. float TraceLeafBrushes( int leafIndex, const Vector &start, const Vector &end, CBaseTrace &traceOut )
  39. {
  40. dleaf_t *pLeaf = dleafs + leafIndex;
  41. CToolTrace trace;
  42. memset( &trace, 0, sizeof(trace) );
  43. trace.ispoint = true;
  44. trace.startsolid = false;
  45. trace.fraction = 1.0;
  46. for ( int i = 0; i < pLeaf->numleafbrushes; i++ )
  47. {
  48. int brushnum = dleafbrushes[pLeaf->firstleafbrush+i];
  49. dbrush_t *b = &dbrushes[brushnum];
  50. if ( !(b->contents & MASK_OPAQUE))
  51. continue;
  52. Vector zeroExtents = vec3_origin;
  53. DM_ClipBoxToBrush( &trace, zeroExtents, zeroExtents, start, end, b);
  54. if ( trace.fraction != 1.0 || trace.startsolid )
  55. {
  56. if ( trace.startsolid )
  57. trace.fraction = 0.0f;
  58. traceOut = trace;
  59. return trace.fraction;
  60. }
  61. }
  62. traceOut = trace;
  63. return 1.0f;
  64. }
  65. DispTested_t s_DispTested[MAX_TOOL_THREADS+1];
  66. // this just uses the average coverage for the triangle
  67. class CCoverageCount : public ITransparentTriangleCallback
  68. {
  69. public:
  70. CCoverageCount()
  71. {
  72. m_coverage = Four_Zeros;
  73. }
  74. virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
  75. {
  76. float color = g_RtEnv.GetTriangleColor( hitID ).x;
  77. m_coverage = AddSIMD( m_coverage, AndSIMD ( *pHitMask, ReplicateX4 ( color ) ) );
  78. m_coverage = MinSIMD( m_coverage, Four_Ones );
  79. fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );
  80. // we should continue if the ones that hit the triangle have onesMask set to zero
  81. // so hitMask & onesMask != hitMask
  82. // so hitMask & onesMask == hitMask means we're done
  83. // so ts(hitMask & onesMask == hitMask) != 0xF says go on
  84. return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
  85. }
  86. fltx4 GetCoverage()
  87. {
  88. return m_coverage;
  89. }
  90. fltx4 GetFractionVisible()
  91. {
  92. return SubSIMD ( Four_Ones, m_coverage );
  93. }
  94. fltx4 m_coverage;
  95. };
  96. // this will sample the texture to get a coverage at the ray intersection point
  97. class CCoverageCountTexture : public CCoverageCount
  98. {
  99. public:
  100. virtual bool VisitTriangle_ShouldContinue( const TriIntersectData_t &triangle, const FourRays &rays, fltx4 *pHitMask, fltx4 *b0, fltx4 *b1, fltx4 *b2, int32 hitID )
  101. {
  102. int sign = TestSignSIMD( *pHitMask );
  103. float addedCoverage[4];
  104. for ( int s = 0; s < 4; s++)
  105. {
  106. addedCoverage[s] = 0.0f;
  107. if ( ( sign >> s) & 0x1 )
  108. {
  109. addedCoverage[s] = ComputeCoverageFromTexture( b0->m128_f32[s], b1->m128_f32[s], b2->m128_f32[s], hitID );
  110. }
  111. }
  112. m_coverage = AddSIMD( m_coverage, LoadUnalignedSIMD( addedCoverage ) );
  113. m_coverage = MinSIMD( m_coverage, Four_Ones );
  114. fltx4 onesMask = CmpEqSIMD( m_coverage, Four_Ones );
  115. // we should continue if the ones that hit the triangle have onesMask set to zero
  116. // so hitMask & onesMask != hitMask
  117. // so hitMask & onesMask == hitMask means we're done
  118. // so ts(hitMask & onesMask == hitMask) != 0xF says go on
  119. return 0xF != TestSignSIMD ( CmpEqSIMD ( AndSIMD( *pHitMask, onesMask ), *pHitMask ) );
  120. }
  121. };
  122. void TestLine( const FourVectors& start, const FourVectors& stop,
  123. fltx4 *pFractionVisible, int static_prop_index_to_ignore )
  124. {
  125. FourRays myrays;
  126. myrays.origin = start;
  127. myrays.direction = stop;
  128. myrays.direction -= myrays.origin;
  129. fltx4 len = myrays.direction.length();
  130. myrays.direction *= ReciprocalSIMD( len );
  131. RayTracingResult rt_result;
  132. CCoverageCountTexture coverageCallback;
  133. g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 );
  134. // Assume we can see the targets unless we get hits
  135. float visibility[4];
  136. for ( int i = 0; i < 4; i++ )
  137. {
  138. visibility[i] = 1.0f;
  139. if ( ( rt_result.HitIds[i] != -1 ) &&
  140. ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
  141. {
  142. visibility[i] = 0.0f;
  143. }
  144. }
  145. *pFractionVisible = LoadUnalignedSIMD( visibility );
  146. if ( g_bTextureShadows )
  147. *pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() );
  148. }
  149. void TestLine_IgnoreSky( const FourVectors& start, const FourVectors& stop,
  150. fltx4 *pFractionVisible, int static_prop_index_to_ignore )
  151. {
  152. FourRays myrays;
  153. myrays.origin = start;
  154. myrays.direction = stop;
  155. myrays.direction -= myrays.origin;
  156. fltx4 len = myrays.direction.length();
  157. myrays.direction *= ReciprocalSIMD( len );
  158. RayTracingResult rt_result;
  159. CCoverageCountTexture coverageCallback;
  160. g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_index_to_ignore, g_bTextureShadows ? &coverageCallback : 0 );
  161. // Assume we can see the targets unless we get hits
  162. float visibility[4];
  163. for ( int i = 0; i < 4; i++ )
  164. {
  165. visibility[i] = 1.0f;
  166. if ( ( rt_result.HitIds[i] != -1 ) &&
  167. ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
  168. {
  169. int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID;
  170. if ( !( id & TRACE_ID_SKY ) )
  171. {
  172. visibility[i] = 0.0f;
  173. }
  174. }
  175. }
  176. *pFractionVisible = LoadUnalignedSIMD( visibility );
  177. if ( g_bTextureShadows )
  178. *pFractionVisible = MinSIMD( *pFractionVisible, coverageCallback.GetFractionVisible() );
  179. }
  180. void TestLine_LightBlockers( const FourVectors& start, const FourVectors& stop,
  181. fltx4 *pFractionVisible )
  182. {
  183. FourRays myrays;
  184. myrays.origin = start;
  185. myrays.direction = stop;
  186. myrays.direction -= myrays.origin;
  187. fltx4 len = myrays.direction.length();
  188. myrays.direction *= ReciprocalSIMD( len );
  189. RayTracingResult rt_result;
  190. g_RtEnv_LightBlockers.Trace4Rays( myrays, Four_Zeros, len, &rt_result, -1, NULL );
  191. // Assume we can see the targets unless we get hits
  192. float visibility[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  193. if ( (rt_result.HitIds[0] != -1) &&
  194. (rt_result.HitDistance.m128_f32[0] < len.m128_f32[0]) )
  195. {
  196. fltx4 dotRaySurfaceN = rt_result.surface_normal * myrays.direction;
  197. if ( dotRaySurfaceN.m128_f32[0] > 0.0f )
  198. {
  199. visibility[0] = 0.0f;
  200. }
  201. }
  202. *pFractionVisible = LoadUnalignedSIMD( visibility );
  203. }
  204. /*
  205. ================
  206. DM_ClipBoxToBrush
  207. ================
  208. */
  209. void DM_ClipBoxToBrush( CToolTrace *trace, const Vector& mins, const Vector& maxs, const Vector& p1, const Vector& p2,
  210. dbrush_t *brush)
  211. {
  212. dplane_t *plane, *clipplane;
  213. float dist;
  214. Vector ofs;
  215. float d1, d2;
  216. float f;
  217. dbrushside_t *side, *leadside;
  218. if (!brush->numsides)
  219. return;
  220. float enterfrac = NEVER_UPDATED;
  221. float leavefrac = 1.f;
  222. clipplane = NULL;
  223. bool getout = false;
  224. bool startout = false;
  225. leadside = NULL;
  226. // Loop interchanged, so we don't have to check trace->ispoint every side.
  227. if ( !trace->ispoint )
  228. {
  229. for (int i=0 ; i<brush->numsides ; ++i)
  230. {
  231. side = &dbrushsides[brush->firstside+i];
  232. plane = dplanes + side->planenum;
  233. // FIXME: special case for axial
  234. // general box case
  235. // push the plane out apropriately for mins/maxs
  236. // FIXME: use signbits into 8 way lookup for each mins/maxs
  237. ofs.x = (plane->normal.x < 0) ? maxs.x : mins.x;
  238. ofs.y = (plane->normal.y < 0) ? maxs.y : mins.y;
  239. ofs.z = (plane->normal.z < 0) ? maxs.z : mins.z;
  240. // for (j=0 ; j<3 ; j++)
  241. // {
  242. // Set signmask to either 0 if the sign is negative, or 0xFFFFFFFF is the sign is positive:
  243. //int signmask = (((*(int *)&(plane->normal[j]))&0x80000000) >> 31) - 1;
  244. //float temp = maxs[j];
  245. //*(int *)&(ofs[j]) = (~signmask) & (*(int *)&temp);
  246. //float temp1 = mins[j];
  247. //*(int *)&(ofs[j]) |= (signmask) & (*(int *)&temp1);
  248. // }
  249. dist = DotProduct (ofs, plane->normal);
  250. dist = plane->dist - dist;
  251. d1 = DotProduct (p1, plane->normal) - dist;
  252. d2 = DotProduct (p2, plane->normal) - dist;
  253. // if completely in front of face, no intersection
  254. if (d1 > 0 && d2 > 0)
  255. return;
  256. if (d2 > 0)
  257. getout = true; // endpoint is not in solid
  258. if (d1 > 0)
  259. startout = true;
  260. if (d1 <= 0 && d2 <= 0)
  261. continue;
  262. // crosses face
  263. if (d1 > d2)
  264. { // enter
  265. f = (d1-DIST_EPSILON) / (d1-d2);
  266. if (f > enterfrac)
  267. {
  268. enterfrac = f;
  269. clipplane = plane;
  270. leadside = side;
  271. }
  272. }
  273. else
  274. { // leave
  275. f = (d1+DIST_EPSILON) / (d1-d2);
  276. if (f < leavefrac)
  277. leavefrac = f;
  278. }
  279. }
  280. }
  281. else
  282. {
  283. for (int i=0 ; i<brush->numsides ; ++i)
  284. {
  285. side = &dbrushsides[brush->firstside+i];
  286. plane = dplanes + side->planenum;
  287. // FIXME: special case for axial
  288. // special point case
  289. // don't ray trace against bevel planes
  290. if( side->bevel == 1 )
  291. continue;
  292. dist = plane->dist;
  293. d1 = DotProduct (p1, plane->normal) - dist;
  294. d2 = DotProduct (p2, plane->normal) - dist;
  295. // if completely in front of face, no intersection
  296. if (d1 > 0 && d2 > 0)
  297. return;
  298. if (d2 > 0)
  299. getout = true; // endpoint is not in solid
  300. if (d1 > 0)
  301. startout = true;
  302. if (d1 <= 0 && d2 <= 0)
  303. continue;
  304. // crosses face
  305. if (d1 > d2)
  306. { // enter
  307. f = (d1-DIST_EPSILON) / (d1-d2);
  308. if (f > enterfrac)
  309. {
  310. enterfrac = f;
  311. clipplane = plane;
  312. leadside = side;
  313. }
  314. }
  315. else
  316. { // leave
  317. f = (d1+DIST_EPSILON) / (d1-d2);
  318. if (f < leavefrac)
  319. leavefrac = f;
  320. }
  321. }
  322. }
  323. if (!startout)
  324. { // original point was inside brush
  325. trace->startsolid = true;
  326. if (!getout)
  327. trace->allsolid = true;
  328. return;
  329. }
  330. if (enterfrac < leavefrac)
  331. {
  332. if (enterfrac > NEVER_UPDATED && enterfrac < trace->fraction)
  333. {
  334. if (enterfrac < 0)
  335. enterfrac = 0;
  336. trace->fraction = enterfrac;
  337. trace->plane.dist = clipplane->dist;
  338. trace->plane.normal = clipplane->normal;
  339. trace->plane.type = clipplane->type;
  340. if (leadside->texinfo!=-1)
  341. trace->surface = &texinfo[leadside->texinfo];
  342. else
  343. trace->surface = 0;
  344. trace->contents = brush->contents;
  345. }
  346. }
  347. }
  348. void TestLine_DoesHitSky( FourVectors const& start, FourVectors const& stop,
  349. fltx4 *pFractionVisible, bool canRecurse, int static_prop_to_skip, bool bDoDebug )
  350. {
  351. FourRays myrays;
  352. myrays.origin = start;
  353. myrays.direction = stop;
  354. myrays.direction -= myrays.origin;
  355. fltx4 len = myrays.direction.length();
  356. myrays.direction *= ReciprocalSIMD( len );
  357. RayTracingResult rt_result;
  358. CCoverageCountTexture coverageCallback;
  359. g_RtEnv.Trace4Rays(myrays, Four_Zeros, len, &rt_result, TRACE_ID_STATICPROP | static_prop_to_skip, g_bTextureShadows? &coverageCallback : 0);
  360. if ( bDoDebug )
  361. {
  362. WriteTrace( "trace.txt", myrays, rt_result );
  363. }
  364. float aOcclusion[4];
  365. for ( int i = 0; i < 4; i++ )
  366. {
  367. aOcclusion[i] = 0.0f;
  368. if ( ( rt_result.HitIds[i] != -1 ) &&
  369. ( rt_result.HitDistance.m128_f32[i] < len.m128_f32[i] ) )
  370. {
  371. int id = g_RtEnv.OptimizedTriangleList[rt_result.HitIds[i]].m_Data.m_IntersectData.m_nTriangleID;
  372. if ( !( id & TRACE_ID_SKY ) )
  373. aOcclusion[i] = 1.0f;
  374. }
  375. }
  376. fltx4 occlusion = LoadUnalignedSIMD( aOcclusion );
  377. if (g_bTextureShadows)
  378. occlusion = MaxSIMD ( occlusion, coverageCallback.GetCoverage() );
  379. bool fullyOccluded = ( TestSignSIMD( CmpGeSIMD( occlusion, Four_Ones ) ) == 0xF );
  380. // if we hit sky, and we're not in a sky camera's area, try clipping into the 3D sky boxes
  381. if ( (! fullyOccluded) && canRecurse && (! g_bNoSkyRecurse ) )
  382. {
  383. FourVectors dir = stop;
  384. dir -= start;
  385. dir.VectorNormalize();
  386. int leafIndex = -1;
  387. leafIndex = PointLeafnum( start.Vec( 0 ) );
  388. if ( leafIndex >= 0 )
  389. {
  390. int area = dleafs[leafIndex].area;
  391. if (area >= 0 && area < numareas)
  392. {
  393. if (area_sky_cameras[area] < 0)
  394. {
  395. int cam;
  396. for (cam = 0; cam < num_sky_cameras; ++cam)
  397. {
  398. FourVectors skystart, skytrans, skystop;
  399. skystart.DuplicateVector( sky_cameras[cam].origin );
  400. skystop = start;
  401. skystop *= sky_cameras[cam].world_to_sky;
  402. skystart += skystop;
  403. skystop = dir;
  404. skystop *= MAX_TRACE_LENGTH;
  405. skystop += skystart;
  406. TestLine_DoesHitSky ( skystart, skystop, pFractionVisible, false, static_prop_to_skip, bDoDebug );
  407. occlusion = AddSIMD ( occlusion, Four_Ones );
  408. occlusion = SubSIMD ( occlusion, *pFractionVisible );
  409. }
  410. }
  411. }
  412. }
  413. }
  414. occlusion = MaxSIMD( occlusion, Four_Zeros );
  415. occlusion = MinSIMD( occlusion, Four_Ones );
  416. *pFractionVisible = SubSIMD( Four_Ones, occlusion );
  417. }
  418. //-----------------------------------------------------------------------------
  419. //-----------------------------------------------------------------------------
  420. int PointLeafnum_r( const Vector &point, int ndxNode )
  421. {
  422. // while loop here is to avoid recursion overhead
  423. while( ndxNode >= 0 )
  424. {
  425. dnode_t *pNode = dnodes + ndxNode;
  426. dplane_t *pPlane = dplanes + pNode->planenum;
  427. float dist;
  428. if( pPlane->type < 3 )
  429. {
  430. dist = point[pPlane->type] - pPlane->dist;
  431. }
  432. else
  433. {
  434. dist = DotProduct( pPlane->normal, point ) - pPlane->dist;
  435. }
  436. if( dist < 0.0f )
  437. {
  438. ndxNode = pNode->children[1];
  439. }
  440. else
  441. {
  442. ndxNode = pNode->children[0];
  443. }
  444. }
  445. return ( -1 - ndxNode );
  446. }
  447. //-----------------------------------------------------------------------------
  448. //-----------------------------------------------------------------------------
  449. int PointLeafnum( const Vector &point )
  450. {
  451. return PointLeafnum_r( point, 0 );
  452. }
  453. // this iterates the list of entities looking for _vradshadows 1
  454. // each brush entity containing this key is added to the raytracing environment
  455. // as a triangle soup model.
  456. dmodel_t *BrushmodelForEntity( entity_t *pEntity )
  457. {
  458. const char *pModelname = ValueForKey( pEntity, "model" );
  459. if ( Q_strlen(pModelname) > 1 )
  460. {
  461. int modelIndex = atol( pModelname + 1 );
  462. if ( modelIndex > 0 && modelIndex < nummodels )
  463. {
  464. return &dmodels[modelIndex];
  465. }
  466. }
  467. return NULL;
  468. }
  469. // Add one that casts textureshadows
  470. void AddTexturedBrushWinding( winding_t *w, const VMatrix &xform, texinfo_t *tx, int shadowMaterialIndex )
  471. {
  472. Vector2D uv[MAX_POINTS_ON_WINDING];
  473. int mappingWidth = 32;
  474. int mappingHeight = 32;
  475. GetShadowTextureMapping( shadowMaterialIndex, &mappingWidth, &mappingHeight );
  476. for ( int j = 0; j < w->numpoints; j++ )
  477. {
  478. // base texture coordinate
  479. uv[j].x = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[0] ) +
  480. tx->textureVecsTexelsPerWorldUnits[0][3];
  481. uv[j].x /= float(mappingWidth);
  482. uv[j].y = DotProduct( w->p[j].Base(), tx->textureVecsTexelsPerWorldUnits[1] ) +
  483. tx->textureVecsTexelsPerWorldUnits[1][3];
  484. uv[j].y /= float(mappingHeight);
  485. }
  486. Vector v0, v1, v2;
  487. for ( int j = 2; j < w->numpoints; j++ )
  488. {
  489. v0 = xform.VMul4x3(w->p[0]);
  490. v1 = xform.VMul4x3(w->p[j-1]);
  491. v2 = xform.VMul4x3(w->p[j]);
  492. float coverage = ComputeCoverageForTriangle(shadowMaterialIndex, uv[0], uv[j-1], uv[j] );
  493. int index = -1;
  494. unsigned short flags = 0;
  495. Vector fullCoverage(0,0,1);
  496. if ( coverage < 1.0 )
  497. {
  498. index = AddShadowTextureTriangle( shadowMaterialIndex, uv[0], uv[j-1], uv[j] );
  499. flags = FCACHETRI_TRANSPARENT;
  500. fullCoverage.x = coverage;
  501. }
  502. g_RtEnv.AddTriangle(TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage, flags, index);
  503. }
  504. }
  505. void AddBrushToRaytraceEnvironment( dbrush_t *pBrush, const VMatrix &xform )
  506. {
  507. int materialIndexList[256];
  508. bool bTextureShadows = false;
  509. if ( !( pBrush->contents & (MASK_OPAQUE) ) && !(g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE)) )
  510. return;
  511. if ( pBrush->contents & CONTENTS_LADDER )
  512. return;
  513. // load any transparent textures for shadows
  514. if ( g_bTextureShadows && (pBrush->contents & CONTENTS_GRATE) && pBrush->numsides < ARRAYSIZE(materialIndexList) )
  515. {
  516. for (int i = 0; i < pBrush->numsides; i++ )
  517. {
  518. dbrushside_t *side = &dbrushsides[pBrush->firstside + i];
  519. texinfo_t *tx = &texinfo[side->texinfo];
  520. dtexdata_t *pTexData = &dtexdata[tx->texdata];
  521. const char *pMaterialName = TexDataStringTable_GetString( pTexData->nameStringTableID );
  522. materialIndexList[i] = LoadShadowTexture( pMaterialName );
  523. if ( materialIndexList[i] >= 0 )
  524. {
  525. bTextureShadows = true;
  526. }
  527. }
  528. }
  529. Vector v0, v1, v2;
  530. for (int i = 0; i < pBrush->numsides; i++ )
  531. {
  532. dbrushside_t *side = &dbrushsides[pBrush->firstside + i];
  533. dplane_t *plane = &dplanes[side->planenum];
  534. texinfo_t *tx = &texinfo[side->texinfo];
  535. winding_t *w = BaseWindingForPlane (plane->normal, plane->dist);
  536. bool bIsLightBlocker = false;
  537. if ( tx->flags & SURF_SKY || side->dispinfo )
  538. continue;
  539. if ( ( pBrush->contents & ( CONTENTS_OPAQUE | CONTENTS_SOLID ) ) && ( tx->flags & SURF_NODRAW ) )
  540. {
  541. bIsLightBlocker = true;
  542. }
  543. for (int j=0 ; j<pBrush->numsides && w; j++)
  544. {
  545. if (i == j)
  546. continue;
  547. dbrushside_t *pOtherSide = &dbrushsides[pBrush->firstside + j];
  548. if (pOtherSide->bevel)
  549. continue;
  550. plane = &dplanes[pOtherSide->planenum^1];
  551. ChopWindingInPlace (&w, plane->normal, plane->dist, 0);
  552. }
  553. if ( w )
  554. {
  555. if ( bTextureShadows && materialIndexList[i] >= 0 )
  556. {
  557. AddTexturedBrushWinding( w, xform, tx, materialIndexList[i] );
  558. }
  559. else
  560. {
  561. // opaque
  562. Vector fullCoverage(1,1,1);
  563. for ( int j = 2; j < w->numpoints; j++ )
  564. {
  565. v0 = xform.VMul4x3(w->p[0]);
  566. v1 = xform.VMul4x3(w->p[j-1]);
  567. v2 = xform.VMul4x3(w->p[j]);
  568. g_RtEnv.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );
  569. // light blockers
  570. if ( bIsLightBlocker )
  571. {
  572. g_RtEnv_LightBlockers.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );
  573. g_RtEnv_RadiosityPatches.AddTriangle( TRACE_ID_OPAQUE, v0, v1, v2, fullCoverage );
  574. }
  575. }
  576. }
  577. FreeWinding( w );
  578. }
  579. }
  580. }
  581. // recurse the bsp and build a list of brushes at the leaves under this node
  582. void GetBrushes_r( int node, CUtlVector<int> &list )
  583. {
  584. if ( node < 0 )
  585. {
  586. int leafIndex = -1 - node;
  587. // Add the solids in the leaf
  588. for ( int i = 0; i < dleafs[leafIndex].numleafbrushes; i++ )
  589. {
  590. int brushIndex = dleafbrushes[dleafs[leafIndex].firstleafbrush + i];
  591. if ( list.Find(brushIndex) < 0 )
  592. {
  593. list.AddToTail( brushIndex );
  594. }
  595. }
  596. }
  597. else
  598. {
  599. // recurse
  600. dnode_t *pnode = dnodes + node;
  601. GetBrushes_r( pnode->children[0], list );
  602. GetBrushes_r( pnode->children[1], list );
  603. }
  604. }
  605. void AddBrushes( dmodel_t *pModel, const VMatrix &xform )
  606. {
  607. if ( pModel )
  608. {
  609. CUtlVector<int> brushList;
  610. GetBrushes_r( pModel->headnode, brushList );
  611. for ( int i = 0; i < brushList.Count(); i++ )
  612. {
  613. int ndxBrush = brushList[i];
  614. AddBrushToRaytraceEnvironment( &dbrushes[ndxBrush], xform );
  615. }
  616. }
  617. }
  618. // Adds the brush entities that cast shadows to the raytrace environment
  619. void ExtractBrushEntityShadowCasters()
  620. {
  621. for ( int i = 0; i < num_entities; i++ )
  622. {
  623. if ( IntForKey( &entities[i], "vrad_brush_cast_shadows" ) != 0 )
  624. {
  625. Vector origin;
  626. QAngle angles;
  627. GetVectorForKey( &entities[i], "origin", origin );
  628. GetAnglesForKey( &entities[i], "angles", angles );
  629. VMatrix xform;
  630. xform.SetupMatrixOrgAngles( origin, angles );
  631. AddBrushes( BrushmodelForEntity( &entities[i] ), xform );
  632. }
  633. }
  634. }
  635. void AddBrushesForRayTrace( void )
  636. {
  637. if ( !nummodels )
  638. return;
  639. VMatrix identity;
  640. identity.Identity();
  641. CUtlVector<int> brushList;
  642. GetBrushes_r ( dmodels[0].headnode, brushList );
  643. for ( int i = 0; i < brushList.Count(); i++ )
  644. {
  645. dbrush_t *brush = &dbrushes[brushList[i]];
  646. AddBrushToRaytraceEnvironment ( brush, identity );
  647. }
  648. for ( int i = 0; i < dmodels[0].numfaces; i++ )
  649. {
  650. int ndxFace = dmodels[0].firstface + i;
  651. dface_t *face = &g_pFaces[ndxFace];
  652. texinfo_t *tx = &texinfo[face->texinfo];
  653. if ( !( tx->flags & SURF_SKY ) )
  654. continue;
  655. Vector points[MAX_POINTS_ON_WINDING];
  656. for ( int j = 0; j < face->numedges; j++ )
  657. {
  658. if ( j >= MAX_POINTS_ON_WINDING )
  659. Error( "***** ERROR! MAX_POINTS_ON_WINDING reached!" );
  660. if ( face->firstedge + j >= ARRAYSIZE( dsurfedges ) )
  661. Error( "***** ERROR! face->firstedge + j >= ARRAYSIZE( dsurfedges )!" );
  662. int surfEdge = dsurfedges[face->firstedge + j];
  663. unsigned short v;
  664. if (surfEdge < 0)
  665. v = dedges[-surfEdge].v[1];
  666. else
  667. v = dedges[surfEdge].v[0];
  668. if ( v >= ARRAYSIZE( dvertexes ) )
  669. Error( "***** ERROR! v(%u) >= ARRAYSIZE( dvertexes(%d) )!", ( unsigned int )v, ARRAYSIZE( dvertexes ) );
  670. dvertex_t *dv = &dvertexes[v];
  671. points[j] = dv->point;
  672. }
  673. for ( int j = 2; j < face->numedges; j++ )
  674. {
  675. Vector fullCoverage;
  676. fullCoverage.x = 1.0f;
  677. g_RtEnv.AddTriangle ( TRACE_ID_SKY, points[0], points[j - 1], points[j], fullCoverage );
  678. }
  679. }
  680. }