Team Fortress 2 Source Code as on 22/4/2020
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.

455 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. // TODO: Should all of this Map_Vis* stuff be an interface?
  8. //
  9. #include "quakedef.h"
  10. #include "gl_model_private.h"
  11. #include "view_shared.h"
  12. #include "cmodel_engine.h"
  13. #include "tier0/vprof.h"
  14. #include "utllinkedlist.h"
  15. #include "ivrenderview.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. static ConVar r_novis( "r_novis","0", FCVAR_CHEAT , "Turn off the PVS." );
  19. static ConVar r_lockpvs( "r_lockpvs", "0", FCVAR_CHEAT, "Lock the PVS so you can fly around and inspect what is being drawn." );
  20. // ----------------------------------------------------------------------
  21. // Renderer interface to vis
  22. // ----------------------------------------------------------------------
  23. int r_visframecount = 0;
  24. //-----------------------------------------------------------------------------
  25. // Purpose: For each cluster to be OR'd into vis, remember the origin, the last viewcluster
  26. // for that origin and the current one, so we can tell when vis is dirty and needs to be
  27. // recomputed
  28. //-----------------------------------------------------------------------------
  29. typedef struct
  30. {
  31. Vector origin;
  32. int viewcluster;
  33. int oldviewcluster;
  34. } VISCLUSTER;
  35. //-----------------------------------------------------------------------------
  36. // Purpose: Stores info for updating vis data for the map
  37. //-----------------------------------------------------------------------------
  38. typedef struct
  39. {
  40. // Number of relevant vis clusters
  41. int nClusters;
  42. // Last number ( if != nClusters, recompute vis )
  43. int oldnClusters;
  44. // List of clusters to merge together for final vis
  45. VISCLUSTER rgVisClusters[ MAX_VIS_LEAVES ];
  46. // Composite vis data
  47. byte rgCurrentVis[ MAX_MAP_LEAFS/8 ];
  48. bool bSkyVisible;
  49. bool bForceFullSky;
  50. } VISINFO;
  51. static VISINFO vis;
  52. // I think this is enough. We should have enough here to cover what we might have in a frame, including:
  53. // 1) water reflection
  54. // 2) camera/monitor (actually, this is merged with the regular world)
  55. // 3) 3dskybox
  56. // 4) regular world
  57. const int VISCACHE_SIZE = 8;
  58. class VisCacheEntry
  59. {
  60. public:
  61. VisCacheEntry() { nClusters = 0; }
  62. int nClusters;
  63. int originclusters[MAX_VIS_LEAVES];
  64. CUtlVector< unsigned short > leaflist;
  65. CUtlVector< unsigned short > nodelist;
  66. };
  67. static CUtlLinkedList< VisCacheEntry > viscache( 0, VISCACHE_SIZE );
  68. static void SortVisViewClusters()
  69. {
  70. for (int i = 1; i < vis.nClusters; ++i)
  71. {
  72. int t = vis.rgVisClusters[i].viewcluster;
  73. int j = i;
  74. while (j > 0 && vis.rgVisClusters[j-1].viewcluster > t)
  75. {
  76. vis.rgVisClusters[j].viewcluster = vis.rgVisClusters[j-1].viewcluster;
  77. --j;
  78. }
  79. vis.rgVisClusters[j].viewcluster = t;
  80. }
  81. }
  82. static void VisMark_Cached( const VisCacheEntry &cache, const worldbrushdata_t &worldbrush )
  83. {
  84. int count, visframe;
  85. visframe = r_visframecount;
  86. count = cache.leaflist.Count();
  87. const unsigned short * RESTRICT pSrc = cache.leaflist.Base();
  88. #if _X360
  89. const int offsetLeaf = offsetof(mleaf_t, visframe);
  90. const int offsetNode = offsetof(mnode_t, visframe);
  91. #endif
  92. while ( count >= 8 )
  93. {
  94. #if _X360
  95. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[0]) );
  96. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[1]) );
  97. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[2]) );
  98. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[3]) );
  99. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[4]) );
  100. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[5]) );
  101. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[6]) );
  102. __dcbt( offsetLeaf, (void *)(worldbrush.leafs + pSrc[7]) );
  103. #endif
  104. worldbrush.leafs[pSrc[0]].visframe = visframe;
  105. worldbrush.leafs[pSrc[1]].visframe = visframe;
  106. worldbrush.leafs[pSrc[2]].visframe = visframe;
  107. worldbrush.leafs[pSrc[3]].visframe = visframe;
  108. worldbrush.leafs[pSrc[4]].visframe = visframe;
  109. worldbrush.leafs[pSrc[5]].visframe = visframe;
  110. worldbrush.leafs[pSrc[6]].visframe = visframe;
  111. worldbrush.leafs[pSrc[7]].visframe = visframe;
  112. pSrc += 8;
  113. count -= 8;
  114. }
  115. while ( count )
  116. {
  117. worldbrush.leafs[pSrc[0]].visframe = visframe;
  118. count--;
  119. pSrc++;
  120. }
  121. count = cache.nodelist.Count();
  122. pSrc = cache.nodelist.Base();
  123. while ( count >= 8 )
  124. {
  125. #if _X360
  126. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[0]) );
  127. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[1]) );
  128. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[2]) );
  129. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[3]) );
  130. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[4]) );
  131. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[5]) );
  132. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[6]) );
  133. __dcbt( offsetNode, (void *)(worldbrush.nodes + pSrc[7]) );
  134. #endif
  135. worldbrush.nodes[pSrc[0]].visframe = visframe;
  136. worldbrush.nodes[pSrc[1]].visframe = visframe;
  137. worldbrush.nodes[pSrc[2]].visframe = visframe;
  138. worldbrush.nodes[pSrc[3]].visframe = visframe;
  139. worldbrush.nodes[pSrc[4]].visframe = visframe;
  140. worldbrush.nodes[pSrc[5]].visframe = visframe;
  141. worldbrush.nodes[pSrc[6]].visframe = visframe;
  142. worldbrush.nodes[pSrc[7]].visframe = visframe;
  143. pSrc += 8;
  144. count -= 8;
  145. }
  146. while ( count )
  147. {
  148. worldbrush.nodes[pSrc[0]].visframe = visframe;
  149. count--;
  150. pSrc++;
  151. }
  152. }
  153. static void VisCache_Build( VisCacheEntry &cache, const worldbrushdata_t &worldbrush )
  154. {
  155. VPROF_INCREMENT_COUNTER( "VisCache misses", 1 );
  156. int i;
  157. mleaf_t *leaf;
  158. int cluster;
  159. cache.nClusters = vis.nClusters;
  160. for (i = 0; i < vis.nClusters; ++i)
  161. {
  162. cache.originclusters[i] = vis.rgVisClusters[i].viewcluster;
  163. }
  164. cache.leaflist.RemoveAll();
  165. cache.nodelist.RemoveAll();
  166. int visframe = r_visframecount;
  167. for ( i = 0, leaf = worldbrush.leafs ; i < worldbrush.numleafs ; i++, leaf++)
  168. {
  169. MEM_ALLOC_CREDIT();
  170. cluster = leaf->cluster;
  171. if ( cluster == -1 )
  172. continue;
  173. if (vis.rgCurrentVis[cluster>>3] & (1<<(cluster&7)))
  174. {
  175. leaf->visframe = visframe;
  176. cache.leaflist.AddToTail( i );
  177. mnode_t *node = leaf->parent;
  178. while (node && node->visframe != visframe)
  179. {
  180. cache.nodelist.AddToTail( node - worldbrush.nodes );
  181. node->visframe = visframe;
  182. node = node->parent;
  183. }
  184. }
  185. }
  186. }
  187. bool Map_AreAnyLeavesVisible( const worldbrushdata_t &worldbrush, int *leafList, int nLeaves )
  188. {
  189. for ( int i=0; i < nLeaves; i++ )
  190. {
  191. const mleaf_t *leaf = &worldbrush.leafs[leafList[i]];
  192. int cluster = leaf->cluster;
  193. if ( cluster == -1 )
  194. continue;
  195. if ( vis.rgCurrentVis[cluster>>3] & (1<<(cluster&7)) )
  196. return true;
  197. }
  198. return false;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose: Mark the leaves and nodes that are in the PVS for the current
  202. // cluster(s)
  203. // Input : *worldmodel -
  204. //-----------------------------------------------------------------------------
  205. void Map_VisMark( bool forcenovis, model_t *worldmodel )
  206. {
  207. VPROF( "Map_VisMark" );
  208. int i, c;
  209. // development aid to let you run around and see exactly where
  210. // the pvs ends
  211. if ( r_lockpvs.GetInt() )
  212. {
  213. return;
  214. }
  215. SortVisViewClusters();
  216. bool outsideWorld = false;
  217. for ( i = 0; i < vis.nClusters; i++ )
  218. {
  219. if ( vis.rgVisClusters[ i ].viewcluster != vis.rgVisClusters[ i ].oldviewcluster )
  220. {
  221. break;
  222. }
  223. }
  224. // No changes
  225. if ( i >= vis.nClusters && !forcenovis && ( vis.nClusters == vis.oldnClusters ) )
  226. {
  227. return;
  228. }
  229. // Update vis frame marker
  230. r_visframecount++;
  231. // Update cluster history
  232. vis.oldnClusters = vis.nClusters;
  233. for ( i = 0; i < vis.nClusters; i++ )
  234. {
  235. vis.rgVisClusters[ i ].oldviewcluster = vis.rgVisClusters[ i ].viewcluster;
  236. // Outside world?
  237. if ( vis.rgVisClusters[ i ].viewcluster == -1 )
  238. {
  239. outsideWorld = true;
  240. break;
  241. }
  242. }
  243. #ifdef USE_CONVARS
  244. if ( r_novis.GetInt() || forcenovis || outsideWorld )
  245. {
  246. // mark everything
  247. for (i=0 ; i<worldmodel->brush.pShared->numleafs ; i++)
  248. {
  249. worldmodel->brush.pShared->leafs[i].visframe = r_visframecount;
  250. }
  251. for (i=0 ; i<worldmodel->brush.pShared->numnodes ; i++)
  252. {
  253. worldmodel->brush.pShared->nodes[i].visframe = r_visframecount;
  254. }
  255. return;
  256. }
  257. #endif
  258. // There should always be at least one origin and that's the default render origin in most cases
  259. assert( vis.nClusters >= 1 );
  260. CM_Vis( vis.rgCurrentVis, sizeof( vis.rgCurrentVis ), vis.rgVisClusters[ 0 ].viewcluster, DVIS_PVS );
  261. // Get cluster count
  262. c = ( CM_NumClusters() + 31 ) / 32 ;
  263. // Merge in any extra clusters
  264. for ( i = 1; i < vis.nClusters; i++ )
  265. {
  266. byte mapVis[ MAX_MAP_CLUSTERS/8 ];
  267. CM_Vis( mapVis, sizeof( mapVis ), vis.rgVisClusters[ i ].viewcluster, DVIS_PVS );
  268. // Copy one dword at a time ( could use memcpy )
  269. for ( int j = 0 ; j < c ; j++ )
  270. {
  271. ((int *)vis.rgCurrentVis)[ j ] |= ((int *)mapVis)[ j ];
  272. }
  273. }
  274. // search the cache for a pre-built list of leaves and nodes that matches
  275. // the desired vis setup, and use that to mark the map if found
  276. for (i = viscache.Head(); i != viscache.InvalidIndex(); i = viscache.Next(i))
  277. {
  278. VisCacheEntry &cache = viscache[i];
  279. if (cache.nClusters != vis.nClusters) continue;
  280. for (c = 0; c < cache.nClusters; ++c)
  281. {
  282. if (cache.originclusters[c] != vis.rgVisClusters[c].viewcluster)
  283. {
  284. // NJS: This is a nasty goto, but avoids a nasty branch mispredict below
  285. // (if a break and if are used instead)
  286. goto next_cache_check;
  287. }
  288. }
  289. viscache.LinkToHead( i );
  290. VisMark_Cached( cache, *worldmodel->brush.pShared );
  291. return;
  292. next_cache_check:;
  293. }
  294. // if we get here, we need to update the cache with a new entry
  295. if (viscache.Count() < VISCACHE_SIZE)
  296. {
  297. viscache.AddToHead();
  298. }
  299. else
  300. {
  301. viscache.LinkToHead( viscache.Tail() );
  302. }
  303. // this also will mark the visleafs in order to build the cache data
  304. VisCache_Build( viscache[viscache.Head()], *worldmodel->brush.pShared );
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose: Purpose: Setup vis for the specified map
  308. // Input : *worldmodel - the map
  309. // visorigincount - how many origins to merge together ( usually 1, can be 0 if forcenovis is true )
  310. // origins[][3] - array of origins to merge together
  311. // forcenovis - if set to true, ignore all origins and just mark everything as visible ( SLOW rendering!!! )
  312. //-----------------------------------------------------------------------------
  313. void Map_VisSetup( model_t *worldmodel, int visorigincount, const Vector origins[], bool forcenovis /*=false*/, unsigned int &returnFlags )
  314. {
  315. assert( visorigincount <= MAX_VIS_LEAVES );
  316. // Don't crash if the client .dll tries to do something weird/dumb
  317. vis.nClusters = min( visorigincount, MAX_VIS_LEAVES );
  318. vis.bForceFullSky = false;
  319. vis.bSkyVisible = false;
  320. returnFlags = 0;
  321. for ( int i = 0; i < vis.nClusters; i++ )
  322. {
  323. int leafIndex = CM_PointLeafnum( origins[ i ] );
  324. int flags = CM_LeafFlags( leafIndex );
  325. if ( flags & ( LEAF_FLAGS_SKY | LEAF_FLAGS_SKY2D ) )
  326. {
  327. vis.bSkyVisible = true;
  328. }
  329. if ( flags & LEAF_FLAGS_RADIAL )
  330. {
  331. vis.bForceFullSky = true;
  332. returnFlags |= IVRenderView::VIEW_SETUP_VIS_EX_RETURN_FLAGS_USES_RADIAL_VIS;
  333. }
  334. vis.rgVisClusters[ i ].viewcluster = CM_LeafCluster( leafIndex );
  335. VectorCopy( origins[ i ], vis.rgVisClusters[ i ].origin );
  336. }
  337. if ( !vis.bSkyVisible )
  338. {
  339. vis.bForceFullSky = false;
  340. }
  341. Map_VisMark( forcenovis, worldmodel );
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Clear / reset vis data
  345. //-----------------------------------------------------------------------------
  346. void Map_VisClear( void )
  347. {
  348. vis.nClusters = 1;
  349. vis.oldnClusters = 1;
  350. for ( int i = 0; i < MAX_VIS_LEAVES; i++ )
  351. {
  352. vis.rgVisClusters[ i ].oldviewcluster = -2;
  353. VectorClear( vis.rgVisClusters[ i ].origin );
  354. vis.rgVisClusters[ i ].viewcluster = -2;
  355. }
  356. viscache.RemoveAll();
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Returns the current vis bitfield
  360. // Output : byte
  361. //-----------------------------------------------------------------------------
  362. byte *Map_VisCurrent( void )
  363. {
  364. return vis.rgCurrentVis;
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose: Returns the first viewcluster ( usually it's the only )
  368. // Output : int
  369. //-----------------------------------------------------------------------------
  370. int Map_VisCurrentCluster( void )
  371. {
  372. // BUGBUG: The client DLL can hit this assert during a level transition
  373. // because the temporary entities do visibility calculations during the
  374. // wrong part of the frame loop (i.e. before a view has been set up!)
  375. Assert( vis.rgVisClusters[ 0 ].viewcluster >= 0 );
  376. if ( vis.rgVisClusters[ 0 ].viewcluster < 0 )
  377. {
  378. static int visclusterwarningcount = 0;
  379. if ( ++visclusterwarningcount <= 5 )
  380. {
  381. ConDMsg( "Map_VisCurrentCluster() < 0!\n" );
  382. }
  383. }
  384. return vis.rgVisClusters[ 0 ].viewcluster;
  385. }
  386. bool Map_VisSkyVisible()
  387. {
  388. return vis.bSkyVisible;
  389. }
  390. bool Map_VisForceFullSky()
  391. {
  392. return vis.bForceFullSky;
  393. }