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.

3322 lines
133 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=====================================================================================//
  7. #include "cbase.h"
  8. #include "PortalSimulation.h"
  9. #include "vphysics_interface.h"
  10. #include "physics.h"
  11. #include "portal_shareddefs.h"
  12. #include "StaticCollisionPolyhedronCache.h"
  13. #include "model_types.h"
  14. #include "filesystem.h"
  15. #include "collisionutils.h"
  16. #include "tier1/callqueue.h"
  17. #ifndef CLIENT_DLL
  18. #include "world.h"
  19. #include "portal_player.h" //TODO: Move any portal mod specific code to callback functions or something
  20. #include "physicsshadowclone.h"
  21. #include "portal/weapon_physcannon.h"
  22. #include "player_pickup.h"
  23. #include "isaverestore.h"
  24. #include "hierarchy.h"
  25. #include "env_debughistory.h"
  26. #else
  27. #include "c_world.h"
  28. #endif
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. CCallQueue *GetPortalCallQueue();
  32. extern IPhysicsConstraintEvent *g_pConstraintEvents;
  33. static ConVar sv_portal_collision_sim_bounds_x( "sv_portal_collision_sim_bounds_x", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
  34. static ConVar sv_portal_collision_sim_bounds_y( "sv_portal_collision_sim_bounds_y", "200", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
  35. static ConVar sv_portal_collision_sim_bounds_z( "sv_portal_collision_sim_bounds_z", "252", FCVAR_REPLICATED, "Size of box used to grab collision geometry around placed portals. These should be at the default size or larger only!" );
  36. //#define DEBUG_PORTAL_SIMULATION_CREATION_TIMES //define to output creation timings to developer 2
  37. //#define DEBUG_PORTAL_COLLISION_ENVIRONMENTS //define this to allow for glview collision dumps of portal simulators
  38. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS ) || defined( DEBUG_PORTAL_SIMULATION_CREATION_TIMES )
  39. # if !defined( PORTAL_SIMULATORS_EMBED_GUID )
  40. # pragma message( __FILE__ "(" __LINE__AS_STRING ") : error custom: Portal simulators require a GUID to debug, enable the GUID in PortalSimulation.h ." )
  41. # endif
  42. #endif
  43. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS )
  44. void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char *szFileName ); //appends to the existing file if it exists
  45. #endif
  46. #define PORTAL_WALL_FARDIST 200.0f
  47. #define PORTAL_WALL_TUBE_DEPTH 1.0f
  48. #define PORTAL_WALL_TUBE_OFFSET 0.01f
  49. #define PORTAL_WALL_MIN_THICKNESS 0.1f
  50. #define PORTAL_POLYHEDRON_CUT_EPSILON (1.0f/1099511627776.0f) // 1 / (1<<40)
  51. #define PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT 0.1f //separating the world collision from wall collision by a small amount gets rid of extremely thin erroneous collision at the separating plane
  52. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  53. static ConVar sv_dump_portalsimulator_collision( "sv_dump_portalsimulator_collision", "0", FCVAR_REPLICATED | FCVAR_CHEAT ); //whether to actually dump out the data now that the possibility exists
  54. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename );
  55. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName );
  56. #endif
  57. #ifdef DEBUG_PORTAL_SIMULATION_CREATION_TIMES
  58. #define STARTDEBUGTIMER(x) { x.Start(); }
  59. #define STOPDEBUGTIMER(x) { x.End(); }
  60. #define DEBUGTIMERONLY(x) x
  61. #define CREATEDEBUGTIMER(x) CFastTimer x;
  62. static const char *s_szTabSpacing[] = { "", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", "\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t" };
  63. static int s_iTabSpacingIndex = 0;
  64. static int s_iPortalSimulatorGUID = 0; //used in standalone function that have no idea what a portal simulator is
  65. #define INCREMENTTABSPACING() ++s_iTabSpacingIndex;
  66. #define DECREMENTTABSPACING() --s_iTabSpacingIndex;
  67. #define TABSPACING (s_szTabSpacing[s_iTabSpacingIndex])
  68. #else
  69. #define STARTDEBUGTIMER(x)
  70. #define STOPDEBUGTIMER(x)
  71. #define DEBUGTIMERONLY(x)
  72. #define CREATEDEBUGTIMER(x)
  73. #define INCREMENTTABSPACING()
  74. #define DECREMENTTABSPACING()
  75. #define TABSPACING
  76. #endif
  77. #define PORTAL_HOLE_HALF_HEIGHT (PORTAL_HALF_HEIGHT + 0.1f)
  78. #define PORTAL_HOLE_HALF_WIDTH (PORTAL_HALF_WIDTH + 0.1f)
  79. static void ConvertBrushListToClippedPolyhedronList( const int *pBrushes, int iBrushCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList );
  80. static void ClipPolyhedrons( CPolyhedron * const *pExistingPolyhedrons, int iPolyhedronCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList );
  81. static inline CPolyhedron *TransformAndClipSinglePolyhedron( CPolyhedron *pExistingPolyhedron, const VMatrix &Transform, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fCutEpsilon, bool bUseTempMemory );
  82. static int GetEntityPhysicsObjects( IPhysicsEnvironment *pEnvironment, CBaseEntity *pEntity, IPhysicsObject **pRetList, int iRetListArraySize );
  83. static CPhysCollide *ConvertPolyhedronsToCollideable( CPolyhedron **pPolyhedrons, int iPolyhedronCount );
  84. #ifndef CLIENT_DLL
  85. static void UpdateShadowClonesPortalSimulationFlags( const CBaseEntity *pSourceEntity, unsigned int iFlags, int iSourceFlags );
  86. static bool g_bPlayerIsInSimulator = false;
  87. #endif
  88. static CUtlVector<CPortalSimulator *> s_PortalSimulators;
  89. CUtlVector<CPortalSimulator *> const &g_PortalSimulators = s_PortalSimulators;
  90. static CPortalSimulator *s_OwnedEntityMap[MAX_EDICTS] = { NULL };
  91. static CPortalSimulatorEventCallbacks s_DummyPortalSimulatorCallback;
  92. const char *PS_SD_Static_World_StaticProps_ClippedProp_t::szTraceSurfaceName = "**studio**";
  93. const int PS_SD_Static_World_StaticProps_ClippedProp_t::iTraceSurfaceFlags = 0;
  94. CBaseEntity *PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = NULL;
  95. CPortalSimulator::CPortalSimulator( void )
  96. : m_bLocalDataIsReady(false),
  97. m_bGenerateCollision(true),
  98. m_bSimulateVPhysics(true),
  99. m_bSharedCollisionConfiguration(false),
  100. m_pLinkedPortal(NULL),
  101. m_bInCrossLinkedFunction(false),
  102. m_pCallbacks(&s_DummyPortalSimulatorCallback),
  103. m_DataAccess(m_InternalData)
  104. {
  105. s_PortalSimulators.AddToTail( this );
  106. #ifdef CLIENT_DLL
  107. m_bGenerateCollision = (GameRules() && GameRules()->IsMultiplayer());
  108. #endif
  109. m_CreationChecklist.bPolyhedronsGenerated = false;
  110. m_CreationChecklist.bLocalCollisionGenerated = false;
  111. m_CreationChecklist.bLinkedCollisionGenerated = false;
  112. m_CreationChecklist.bLocalPhysicsGenerated = false;
  113. m_CreationChecklist.bLinkedPhysicsGenerated = false;
  114. #ifdef PORTAL_SIMULATORS_EMBED_GUID
  115. static int s_iPortalSimulatorGUIDAllocator = 0;
  116. m_iPortalSimulatorGUID = s_iPortalSimulatorGUIDAllocator++;
  117. #endif
  118. #ifndef CLIENT_DLL
  119. PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = GetWorldEntity(); //will overinitialize, but it's cheap
  120. m_InternalData.Simulation.pCollisionEntity = (CPSCollisionEntity *)CreateEntityByName( "portalsimulator_collisionentity" );
  121. Assert( m_InternalData.Simulation.pCollisionEntity != NULL );
  122. if( m_InternalData.Simulation.pCollisionEntity )
  123. {
  124. m_InternalData.Simulation.pCollisionEntity->m_pOwningSimulator = this;
  125. MarkAsOwned( m_InternalData.Simulation.pCollisionEntity );
  126. m_InternalData.Simulation.Dynamic.EntFlags[m_InternalData.Simulation.pCollisionEntity->entindex()] |= PSEF_OWNS_PHYSICS;
  127. DispatchSpawn( m_InternalData.Simulation.pCollisionEntity );
  128. }
  129. #else
  130. PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = GetClientWorldEntity();
  131. #endif
  132. }
  133. CPortalSimulator::~CPortalSimulator( void )
  134. {
  135. //go assert crazy here
  136. DetachFromLinked();
  137. ClearEverything();
  138. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  139. {
  140. if( s_PortalSimulators[i] == this )
  141. {
  142. s_PortalSimulators.FastRemove( i );
  143. break;
  144. }
  145. }
  146. if( m_InternalData.Placement.pHoleShapeCollideable )
  147. physcollision->DestroyCollide( m_InternalData.Placement.pHoleShapeCollideable );
  148. #ifndef CLIENT_DLL
  149. if( m_InternalData.Simulation.pCollisionEntity )
  150. {
  151. m_InternalData.Simulation.pCollisionEntity->m_pOwningSimulator = NULL;
  152. m_InternalData.Simulation.Dynamic.EntFlags[m_InternalData.Simulation.pCollisionEntity->entindex()] &= ~PSEF_OWNS_PHYSICS;
  153. MarkAsReleased( m_InternalData.Simulation.pCollisionEntity );
  154. UTIL_Remove( m_InternalData.Simulation.pCollisionEntity );
  155. m_InternalData.Simulation.pCollisionEntity = NULL;
  156. }
  157. #endif
  158. }
  159. void CPortalSimulator::MoveTo( const Vector &ptCenter, const QAngle &angles )
  160. {
  161. if( (m_InternalData.Placement.ptCenter == ptCenter) && (m_InternalData.Placement.qAngles == angles) ) //not actually moving at all
  162. return;
  163. CREATEDEBUGTIMER( functionTimer );
  164. STARTDEBUGTIMER( functionTimer );
  165. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::MoveTo() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  166. INCREMENTTABSPACING();
  167. #ifndef CLIENT_DLL
  168. //create a list of all entities that are actually within the portal hole, they will likely need to be moved out of solid space when the portal moves
  169. CBaseEntity **pFixEntities = (CBaseEntity **)stackalloc( sizeof( CBaseEntity * ) * m_InternalData.Simulation.Dynamic.OwnedEntities.Count() );
  170. int iFixEntityCount = 0;
  171. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  172. {
  173. CBaseEntity *pEntity = m_InternalData.Simulation.Dynamic.OwnedEntities[i];
  174. if( CPhysicsShadowClone::IsShadowClone( pEntity ) ||
  175. CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  176. continue;
  177. if( EntityIsInPortalHole( pEntity) )
  178. {
  179. pFixEntities[iFixEntityCount] = pEntity;
  180. ++iFixEntityCount;
  181. }
  182. }
  183. VPlane OldPlane = m_InternalData.Placement.PortalPlane; //used in fixing code
  184. #endif
  185. //update geometric data
  186. {
  187. m_InternalData.Placement.ptCenter = ptCenter;
  188. m_InternalData.Placement.qAngles = angles;
  189. AngleVectors( angles, &m_InternalData.Placement.vForward, &m_InternalData.Placement.vRight, &m_InternalData.Placement.vUp );
  190. m_InternalData.Placement.PortalPlane.Init( m_InternalData.Placement.vForward, m_InternalData.Placement.vForward.Dot( m_InternalData.Placement.ptCenter ) );
  191. }
  192. //Clear();
  193. #ifndef CLIENT_DLL
  194. ClearLinkedPhysics();
  195. ClearLocalPhysics();
  196. #endif
  197. ClearLinkedCollision();
  198. ClearLocalCollision();
  199. ClearPolyhedrons();
  200. m_bLocalDataIsReady = true;
  201. UpdateLinkMatrix();
  202. //update hole shape - used to detect if an entity is within the portal hole bounds
  203. {
  204. if( m_InternalData.Placement.pHoleShapeCollideable )
  205. physcollision->DestroyCollide( m_InternalData.Placement.pHoleShapeCollideable );
  206. float fHolePlanes[6*4];
  207. //first and second planes are always forward and backward planes
  208. fHolePlanes[(0*4) + 0] = m_InternalData.Placement.PortalPlane.m_Normal.x;
  209. fHolePlanes[(0*4) + 1] = m_InternalData.Placement.PortalPlane.m_Normal.y;
  210. fHolePlanes[(0*4) + 2] = m_InternalData.Placement.PortalPlane.m_Normal.z;
  211. fHolePlanes[(0*4) + 3] = m_InternalData.Placement.PortalPlane.m_Dist - 0.5f;
  212. fHolePlanes[(1*4) + 0] = -m_InternalData.Placement.PortalPlane.m_Normal.x;
  213. fHolePlanes[(1*4) + 1] = -m_InternalData.Placement.PortalPlane.m_Normal.y;
  214. fHolePlanes[(1*4) + 2] = -m_InternalData.Placement.PortalPlane.m_Normal.z;
  215. fHolePlanes[(1*4) + 3] = (-m_InternalData.Placement.PortalPlane.m_Dist) + 500.0f;
  216. //the remaining planes will always have the same ordering of normals, with different distances plugged in for each convex we're creating
  217. //normal order is up, down, left, right
  218. fHolePlanes[(2*4) + 0] = m_InternalData.Placement.vUp.x;
  219. fHolePlanes[(2*4) + 1] = m_InternalData.Placement.vUp.y;
  220. fHolePlanes[(2*4) + 2] = m_InternalData.Placement.vUp.z;
  221. fHolePlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (PORTAL_HALF_HEIGHT * 0.98f)) );
  222. fHolePlanes[(3*4) + 0] = -m_InternalData.Placement.vUp.x;
  223. fHolePlanes[(3*4) + 1] = -m_InternalData.Placement.vUp.y;
  224. fHolePlanes[(3*4) + 2] = -m_InternalData.Placement.vUp.z;
  225. fHolePlanes[(3*4) + 3] = -m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * (PORTAL_HALF_HEIGHT * 0.98f)) );
  226. fHolePlanes[(4*4) + 0] = -m_InternalData.Placement.vRight.x;
  227. fHolePlanes[(4*4) + 1] = -m_InternalData.Placement.vRight.y;
  228. fHolePlanes[(4*4) + 2] = -m_InternalData.Placement.vRight.z;
  229. fHolePlanes[(4*4) + 3] = -m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vRight * (PORTAL_HALF_WIDTH * 0.98f)) );
  230. fHolePlanes[(5*4) + 0] = m_InternalData.Placement.vRight.x;
  231. fHolePlanes[(5*4) + 1] = m_InternalData.Placement.vRight.y;
  232. fHolePlanes[(5*4) + 2] = m_InternalData.Placement.vRight.z;
  233. fHolePlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * (PORTAL_HALF_WIDTH * 0.98f)) );
  234. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON, true );
  235. Assert( pPolyhedron != NULL );
  236. CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  237. pPolyhedron->Release();
  238. Assert( pConvex != NULL );
  239. m_InternalData.Placement.pHoleShapeCollideable = physcollision->ConvertConvexToCollide( &pConvex, 1 );
  240. }
  241. #ifndef CLIENT_DLL
  242. for( int i = 0; i != iFixEntityCount; ++i )
  243. {
  244. if( !EntityIsInPortalHole( pFixEntities[i] ) )
  245. {
  246. //this entity is most definitely stuck in a solid wall right now
  247. //pFixEntities[i]->SetAbsOrigin( pFixEntities[i]->GetAbsOrigin() + (OldPlane.m_Normal * 50.0f) );
  248. FindClosestPassableSpace( pFixEntities[i], OldPlane.m_Normal );
  249. continue;
  250. }
  251. //entity is still in the hole, but it's possible the hole moved enough where they're in part of the wall
  252. {
  253. //TODO: figure out if that's the case and fix it
  254. }
  255. }
  256. #endif
  257. CreatePolyhedrons();
  258. CreateAllCollision();
  259. #ifndef CLIENT_DLL
  260. CreateAllPhysics();
  261. #endif
  262. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS ) && !defined( CLIENT_DLL )
  263. if( sv_dump_portalsimulator_collision.GetBool() )
  264. {
  265. const char *szFileName = "pscd.txt";
  266. filesystem->RemoveFile( szFileName );
  267. DumpActiveCollision( this, szFileName );
  268. if( m_pLinkedPortal )
  269. {
  270. szFileName = "pscd_linked.txt";
  271. filesystem->RemoveFile( szFileName );
  272. DumpActiveCollision( m_pLinkedPortal, szFileName );
  273. }
  274. }
  275. #endif
  276. #ifndef CLIENT_DLL
  277. Assert( (m_InternalData.Simulation.pCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.pCollisionEntity) );
  278. #endif
  279. STOPDEBUGTIMER( functionTimer );
  280. DECREMENTTABSPACING();
  281. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::MoveTo() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  282. }
  283. void CPortalSimulator::UpdateLinkMatrix( void )
  284. {
  285. if( m_pLinkedPortal && m_pLinkedPortal->m_bLocalDataIsReady )
  286. {
  287. Vector vLocalLeft = -m_InternalData.Placement.vRight;
  288. VMatrix matLocalToWorld( m_InternalData.Placement.vForward, vLocalLeft, m_InternalData.Placement.vUp );
  289. matLocalToWorld.SetTranslation( m_InternalData.Placement.ptCenter );
  290. VMatrix matLocalToWorldInverse;
  291. MatrixInverseTR( matLocalToWorld,matLocalToWorldInverse );
  292. //180 degree rotation about up
  293. VMatrix matRotation;
  294. matRotation.Identity();
  295. matRotation.m[0][0] = -1.0f;
  296. matRotation.m[1][1] = -1.0f;
  297. Vector vRemoteLeft = -m_pLinkedPortal->m_InternalData.Placement.vRight;
  298. VMatrix matRemoteToWorld( m_pLinkedPortal->m_InternalData.Placement.vForward, vRemoteLeft, m_pLinkedPortal->m_InternalData.Placement.vUp );
  299. matRemoteToWorld.SetTranslation( m_pLinkedPortal->m_InternalData.Placement.ptCenter );
  300. //final
  301. m_InternalData.Placement.matThisToLinked = matRemoteToWorld * matRotation * matLocalToWorldInverse;
  302. }
  303. else
  304. {
  305. m_InternalData.Placement.matThisToLinked.Identity();
  306. }
  307. m_InternalData.Placement.matThisToLinked.InverseTR( m_InternalData.Placement.matLinkedToThis );
  308. MatrixAngles( m_InternalData.Placement.matThisToLinked.As3x4(), m_InternalData.Placement.ptaap_ThisToLinked.qAngleTransform, m_InternalData.Placement.ptaap_ThisToLinked.ptOriginTransform );
  309. MatrixAngles( m_InternalData.Placement.matLinkedToThis.As3x4(), m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform );
  310. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  311. {
  312. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  313. m_bInCrossLinkedFunction = true;
  314. m_pLinkedPortal->UpdateLinkMatrix();
  315. m_bInCrossLinkedFunction = false;
  316. }
  317. }
  318. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  319. static ConVar sv_debug_dumpportalhole_nextcheck( "sv_debug_dumpportalhole_nextcheck", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  320. #endif
  321. bool CPortalSimulator::EntityIsInPortalHole( CBaseEntity *pEntity ) const
  322. {
  323. if( m_bLocalDataIsReady == false )
  324. return false;
  325. Assert( m_InternalData.Placement.pHoleShapeCollideable != NULL );
  326. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  327. const char *szDumpFileName = "ps_entholecheck.txt";
  328. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  329. {
  330. filesystem->RemoveFile( szDumpFileName );
  331. DumpActiveCollision( this, szDumpFileName );
  332. PortalSimulatorDumps_DumpCollideToGlView( m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, 1.0f, szDumpFileName );
  333. }
  334. #endif
  335. trace_t Trace;
  336. switch( pEntity->GetSolid() )
  337. {
  338. case SOLID_VPHYSICS:
  339. {
  340. ICollideable *pCollideable = pEntity->GetCollideable();
  341. vcollide_t *pVCollide = modelinfo->GetVCollide( pCollideable->GetCollisionModel() );
  342. //Assert( pVCollide != NULL ); //brush models?
  343. if( pVCollide != NULL )
  344. {
  345. Vector ptEntityPosition = pCollideable->GetCollisionOrigin();
  346. QAngle qEntityAngles = pCollideable->GetCollisionAngles();
  347. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  348. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  349. {
  350. for( int i = 0; i != pVCollide->solidCount; ++i )
  351. PortalSimulatorDumps_DumpCollideToGlView( m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, 0.4f, szDumpFileName );
  352. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  353. }
  354. #endif
  355. for( int i = 0; i != pVCollide->solidCount; ++i )
  356. {
  357. physcollision->TraceCollide( ptEntityPosition, ptEntityPosition, pVCollide->solids[i], qEntityAngles, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  358. if( Trace.startsolid )
  359. return true;
  360. }
  361. }
  362. else
  363. {
  364. //energy balls lack a vcollide
  365. Vector vMins, vMaxs, ptCenter;
  366. pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
  367. ptCenter = (vMins + vMaxs) * 0.5f;
  368. vMins -= ptCenter;
  369. vMaxs -= ptCenter;
  370. physcollision->TraceBox( ptCenter, ptCenter, vMins, vMaxs, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  371. return Trace.startsolid;
  372. }
  373. break;
  374. }
  375. case SOLID_BBOX:
  376. {
  377. Vector ptEntityPosition = pEntity->GetAbsOrigin();
  378. CCollisionProperty *pCollisionProp = pEntity->CollisionProp();
  379. physcollision->TraceBox( ptEntityPosition, ptEntityPosition, pCollisionProp->OBBMins(), pCollisionProp->OBBMaxs(), m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  380. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  381. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  382. {
  383. Vector vMins = ptEntityPosition + pCollisionProp->OBBMins();
  384. Vector vMaxs = ptEntityPosition + pCollisionProp->OBBMaxs();
  385. PortalSimulatorDumps_DumpBoxToGlView( vMins, vMaxs, 1.0f, 1.0f, 1.0f, szDumpFileName );
  386. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  387. }
  388. #endif
  389. if( Trace.startsolid )
  390. return true;
  391. break;
  392. }
  393. case SOLID_NONE:
  394. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  395. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  396. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  397. #endif
  398. return false;
  399. default:
  400. Assert( false ); //make a handler
  401. };
  402. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  403. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  404. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  405. #endif
  406. return false;
  407. }
  408. bool CPortalSimulator::EntityHitBoxExtentIsInPortalHole( CBaseAnimating *pBaseAnimating ) const
  409. {
  410. if( m_bLocalDataIsReady == false )
  411. return false;
  412. bool bFirstVert = true;
  413. Vector vMinExtent;
  414. Vector vMaxExtent;
  415. CStudioHdr *pStudioHdr = pBaseAnimating->GetModelPtr();
  416. if ( !pStudioHdr )
  417. return false;
  418. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pBaseAnimating->m_nHitboxSet );
  419. if ( !set )
  420. return false;
  421. Vector position;
  422. QAngle angles;
  423. for ( int i = 0; i < set->numhitboxes; i++ )
  424. {
  425. mstudiobbox_t *pbox = set->pHitbox( i );
  426. pBaseAnimating->GetBonePosition( pbox->bone, position, angles );
  427. // Build a rotation matrix from orientation
  428. matrix3x4_t fRotateMatrix;
  429. AngleMatrix( angles, fRotateMatrix );
  430. //Vector pVerts[8];
  431. Vector vecPos;
  432. for ( int i = 0; i < 8; ++i )
  433. {
  434. vecPos[0] = ( i & 0x1 ) ? pbox->bbmax[0] : pbox->bbmin[0];
  435. vecPos[1] = ( i & 0x2 ) ? pbox->bbmax[1] : pbox->bbmin[1];
  436. vecPos[2] = ( i & 0x4 ) ? pbox->bbmax[2] : pbox->bbmin[2];
  437. Vector vRotVec;
  438. VectorRotate( vecPos, fRotateMatrix, vRotVec );
  439. vRotVec += position;
  440. if ( bFirstVert )
  441. {
  442. vMinExtent = vRotVec;
  443. vMaxExtent = vRotVec;
  444. bFirstVert = false;
  445. }
  446. else
  447. {
  448. vMinExtent = vMinExtent.Min( vRotVec );
  449. vMaxExtent = vMaxExtent.Max( vRotVec );
  450. }
  451. }
  452. }
  453. Vector ptCenter = (vMinExtent + vMaxExtent) * 0.5f;
  454. vMinExtent -= ptCenter;
  455. vMaxExtent -= ptCenter;
  456. trace_t Trace;
  457. physcollision->TraceBox( ptCenter, ptCenter, vMinExtent, vMaxExtent, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  458. if( Trace.startsolid )
  459. return true;
  460. return false;
  461. }
  462. void CPortalSimulator::RemoveEntityFromPortalHole( CBaseEntity *pEntity )
  463. {
  464. if( EntityIsInPortalHole( pEntity ) )
  465. {
  466. FindClosestPassableSpace( pEntity, m_InternalData.Placement.PortalPlane.m_Normal );
  467. }
  468. }
  469. bool CPortalSimulator::RayIsInPortalHole( const Ray_t &ray ) const
  470. {
  471. trace_t Trace;
  472. physcollision->TraceBox( ray, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  473. return Trace.DidHit();
  474. }
  475. void CPortalSimulator::ClearEverything( void )
  476. {
  477. CREATEDEBUGTIMER( functionTimer );
  478. STARTDEBUGTIMER( functionTimer );
  479. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::Clear() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  480. INCREMENTTABSPACING();
  481. #ifndef CLIENT_DLL
  482. ClearAllPhysics();
  483. #endif
  484. ClearAllCollision();
  485. ClearPolyhedrons();
  486. #ifndef CLIENT_DLL
  487. ReleaseAllEntityOwnership();
  488. Assert( (m_InternalData.Simulation.pCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.pCollisionEntity) );
  489. #endif
  490. STOPDEBUGTIMER( functionTimer );
  491. DECREMENTTABSPACING();
  492. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::Clear() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  493. }
  494. void CPortalSimulator::AttachTo( CPortalSimulator *pLinkedPortalSimulator )
  495. {
  496. Assert( pLinkedPortalSimulator );
  497. if( pLinkedPortalSimulator == m_pLinkedPortal )
  498. return;
  499. CREATEDEBUGTIMER( functionTimer );
  500. STARTDEBUGTIMER( functionTimer );
  501. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::AttachTo() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  502. INCREMENTTABSPACING();
  503. DetachFromLinked();
  504. m_pLinkedPortal = pLinkedPortalSimulator;
  505. pLinkedPortalSimulator->m_pLinkedPortal = this;
  506. if( m_bLocalDataIsReady && m_pLinkedPortal->m_bLocalDataIsReady )
  507. {
  508. UpdateLinkMatrix();
  509. CreateLinkedCollision();
  510. #ifndef CLIENT_DLL
  511. CreateLinkedPhysics();
  512. #endif
  513. }
  514. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS ) && !defined( CLIENT_DLL )
  515. if( sv_dump_portalsimulator_collision.GetBool() )
  516. {
  517. const char *szFileName = "pscd.txt";
  518. filesystem->RemoveFile( szFileName );
  519. DumpActiveCollision( this, szFileName );
  520. if( m_pLinkedPortal )
  521. {
  522. szFileName = "pscd_linked.txt";
  523. filesystem->RemoveFile( szFileName );
  524. DumpActiveCollision( m_pLinkedPortal, szFileName );
  525. }
  526. }
  527. #endif
  528. STOPDEBUGTIMER( functionTimer );
  529. DECREMENTTABSPACING();
  530. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::AttachTo() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  531. }
  532. #ifndef CLIENT_DLL
  533. void CPortalSimulator::TakeOwnershipOfEntity( CBaseEntity *pEntity )
  534. {
  535. AssertMsg( m_bLocalDataIsReady, "Tell the portal simulator where it is with MoveTo() before using it in any other way." );
  536. Assert( pEntity != NULL );
  537. if( pEntity == NULL )
  538. return;
  539. if( pEntity->IsWorld() )
  540. return;
  541. if( CPhysicsShadowClone::IsShadowClone( pEntity ) )
  542. return;
  543. if( pEntity->GetServerVehicle() != NULL ) //we don't take kindly to vehicles in these here parts. Their physics controllers currently don't migrate properly and cause a crash
  544. return;
  545. if( OwnsEntity( pEntity ) )
  546. return;
  547. Assert( GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  548. MarkAsOwned( pEntity );
  549. Assert( GetSimulatorThatOwnsEntity( pEntity ) == this );
  550. if( EntityIsInPortalHole( pEntity ) )
  551. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] |= PSEF_IS_IN_PORTAL_HOLE;
  552. else
  553. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_IS_IN_PORTAL_HOLE;
  554. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] );
  555. m_pCallbacks->PortalSimulator_TookOwnershipOfEntity( pEntity );
  556. if( IsSimulatingVPhysics() )
  557. TakePhysicsOwnership( pEntity );
  558. pEntity->CollisionRulesChanged(); //absolutely necessary in single-environment mode, possibly expendable in multi-environment moder
  559. //pEntity->SetGroundEntity( NULL );
  560. IPhysicsObject *pObject = pEntity->VPhysicsGetObject();
  561. if( pObject )
  562. {
  563. pObject->Wake();
  564. pObject->RecheckContactPoints();
  565. }
  566. CUtlVector<CBaseEntity *> childrenList;
  567. GetAllChildren( pEntity, childrenList );
  568. for ( int i = childrenList.Count(); --i >= 0; )
  569. {
  570. CBaseEntity *pEnt = childrenList[i];
  571. CPortalSimulator *pOwningSimulator = GetSimulatorThatOwnsEntity( pEnt );
  572. if( pOwningSimulator != this )
  573. {
  574. if( pOwningSimulator != NULL )
  575. pOwningSimulator->ReleaseOwnershipOfEntity( pEnt, (pOwningSimulator == m_pLinkedPortal) );
  576. TakeOwnershipOfEntity( childrenList[i] );
  577. }
  578. }
  579. }
  580. void CPortalSimulator::TakePhysicsOwnership( CBaseEntity *pEntity )
  581. {
  582. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  583. return;
  584. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  585. return;
  586. Assert( CPhysicsShadowClone::IsShadowClone( pEntity ) == false );
  587. Assert( OwnsEntity( pEntity ) ); //taking physics ownership happens AFTER general ownership
  588. if( OwnsPhysicsForEntity( pEntity ) )
  589. return;
  590. int iEntIndex = pEntity->entindex();
  591. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_OWNS_PHYSICS;
  592. //physics cloning
  593. {
  594. #ifdef _DEBUG
  595. {
  596. int iDebugIndex;
  597. for( iDebugIndex = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  598. {
  599. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  600. break;
  601. }
  602. AssertMsg( iDebugIndex < 0, "Trying to own an entity, when a clone from the linked portal already exists" );
  603. if( m_pLinkedPortal )
  604. {
  605. for( iDebugIndex = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  606. {
  607. if( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  608. break;
  609. }
  610. AssertMsg( iDebugIndex < 0, "Trying to own an entity, when we're already exporting a clone to the linked portal" );
  611. }
  612. //Don't require a copy from main to already exist
  613. }
  614. #endif
  615. EHANDLE hEnt = pEntity;
  616. //To linked portal
  617. if( m_pLinkedPortal && m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment )
  618. {
  619. DBG_CODE(
  620. for( int i = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  621. AssertMsg( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i]->GetClonedEntity() != pEntity, "Already cloning to linked portal." );
  622. );
  623. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::TakePhysicsOwnership(): To Linked Portal", &m_InternalData.Placement.matThisToLinked.As3x4() );
  624. if( pClone )
  625. {
  626. //bool bHeldByPhyscannon = false;
  627. CBaseEntity *pHeldEntity = NULL;
  628. CPortal_Player *pPlayer = (CPortal_Player *)GetPlayerHoldingEntity( pEntity );
  629. if ( !pPlayer && pEntity->IsPlayer() )
  630. {
  631. pPlayer = (CPortal_Player *)pEntity;
  632. }
  633. if ( pPlayer )
  634. {
  635. pHeldEntity = GetPlayerHeldEntity( pPlayer );
  636. /*if ( !pHeldEntity )
  637. {
  638. pHeldEntity = PhysCannonGetHeldEntity( pPlayer->GetActiveWeapon() );
  639. bHeldByPhyscannon = true;
  640. }*/
  641. }
  642. if( pHeldEntity )
  643. {
  644. //player is holding the entity, force them to pick it back up again
  645. bool bIsHeldObjectOnOppositeSideOfPortal = pPlayer->IsHeldObjectOnOppositeSideOfPortal();
  646. pPlayer->m_bSilentDropAndPickup = true;
  647. pPlayer->ForceDropOfCarriedPhysObjects( pHeldEntity );
  648. pPlayer->SetHeldObjectOnOppositeSideOfPortal( bIsHeldObjectOnOppositeSideOfPortal );
  649. }
  650. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  651. m_pLinkedPortal->MarkAsOwned( pClone );
  652. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS;
  653. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_IS_IN_PORTAL_HOLE;
  654. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  655. if( pHeldEntity )
  656. {
  657. /*if ( bHeldByPhyscannon )
  658. {
  659. PhysCannonPickupObject( pPlayer, pHeldEntity );
  660. }
  661. else*/
  662. {
  663. PlayerPickupObject( pPlayer, pHeldEntity );
  664. }
  665. pPlayer->m_bSilentDropAndPickup = false;
  666. }
  667. }
  668. }
  669. }
  670. m_pCallbacks->PortalSimulator_TookPhysicsOwnershipOfEntity( pEntity );
  671. }
  672. void RecheckEntityCollision( CBaseEntity *pEntity )
  673. {
  674. CCallQueue *pCallQueue;
  675. if ( (pCallQueue = GetPortalCallQueue()) != NULL )
  676. {
  677. pCallQueue->QueueCall( RecheckEntityCollision, pEntity );
  678. return;
  679. }
  680. pEntity->CollisionRulesChanged(); //absolutely necessary in single-environment mode, possibly expendable in multi-environment mode
  681. //pEntity->SetGroundEntity( NULL );
  682. IPhysicsObject *pObject = pEntity->VPhysicsGetObject();
  683. if( pObject )
  684. {
  685. pObject->Wake();
  686. pObject->RecheckContactPoints();
  687. }
  688. }
  689. void CPortalSimulator::ReleaseOwnershipOfEntity( CBaseEntity *pEntity, bool bMovingToLinkedSimulator /*= false*/ )
  690. {
  691. if( pEntity == NULL )
  692. return;
  693. if( pEntity->IsWorld() )
  694. return;
  695. if( !OwnsEntity( pEntity ) )
  696. return;
  697. if( m_InternalData.Simulation.pPhysicsEnvironment )
  698. ReleasePhysicsOwnership( pEntity, true, bMovingToLinkedSimulator );
  699. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_IS_IN_PORTAL_HOLE;
  700. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] );
  701. Assert( GetSimulatorThatOwnsEntity( pEntity ) == this );
  702. MarkAsReleased( pEntity );
  703. Assert( GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  704. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  705. {
  706. if( m_InternalData.Simulation.Dynamic.OwnedEntities[i] == pEntity )
  707. {
  708. m_InternalData.Simulation.Dynamic.OwnedEntities.FastRemove(i);
  709. break;
  710. }
  711. }
  712. if( bMovingToLinkedSimulator == false )
  713. {
  714. RecheckEntityCollision( pEntity );
  715. }
  716. m_pCallbacks->PortalSimulator_ReleasedOwnershipOfEntity( pEntity );
  717. CUtlVector<CBaseEntity *> childrenList;
  718. GetAllChildren( pEntity, childrenList );
  719. for ( int i = childrenList.Count(); --i >= 0; )
  720. ReleaseOwnershipOfEntity( childrenList[i] );
  721. }
  722. void CPortalSimulator::ReleaseAllEntityOwnership( void )
  723. {
  724. //Assert( m_bLocalDataIsReady || (m_InternalData.Simulation.Dynamic.OwnedEntities.Count() == 0) );
  725. int iSkippedObjects = 0;
  726. while( m_InternalData.Simulation.Dynamic.OwnedEntities.Count() != iSkippedObjects ) //the release function changes OwnedEntities
  727. {
  728. CBaseEntity *pEntity = m_InternalData.Simulation.Dynamic.OwnedEntities[iSkippedObjects];
  729. if( CPhysicsShadowClone::IsShadowClone( pEntity ) ||
  730. CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  731. {
  732. ++iSkippedObjects;
  733. continue;
  734. }
  735. RemoveEntityFromPortalHole( pEntity ); //assume that whenever someone wants to release all entities, it's because the portal is going away
  736. ReleaseOwnershipOfEntity( pEntity );
  737. }
  738. Assert( (m_InternalData.Simulation.pCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.pCollisionEntity) );
  739. }
  740. void CPortalSimulator::ReleasePhysicsOwnership( CBaseEntity *pEntity, bool bContinuePhysicsCloning /*= true*/, bool bMovingToLinkedSimulator /*= false*/ )
  741. {
  742. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  743. return;
  744. Assert( OwnsEntity( pEntity ) ); //releasing physics ownership happens BEFORE releasing general ownership
  745. Assert( CPhysicsShadowClone::IsShadowClone( pEntity ) == false );
  746. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  747. return;
  748. if( !OwnsPhysicsForEntity( pEntity ) )
  749. return;
  750. if( IsSimulatingVPhysics() == false )
  751. bContinuePhysicsCloning = false;
  752. int iEntIndex = pEntity->entindex();
  753. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_OWNS_PHYSICS;
  754. //physics cloning
  755. {
  756. #ifdef _DEBUG
  757. {
  758. int iDebugIndex;
  759. for( iDebugIndex = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  760. {
  761. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  762. break;
  763. }
  764. AssertMsg( iDebugIndex < 0, "Trying to release an entity, when a clone from the linked portal already exists." );
  765. }
  766. #endif
  767. //clear exported clones
  768. {
  769. DBG_CODE_NOSCOPE( bool bFoundAlready = false; );
  770. DBG_CODE_NOSCOPE( const char *szLastFoundMarker = NULL; );
  771. //to linked portal
  772. if( m_pLinkedPortal )
  773. {
  774. DBG_CODE_NOSCOPE( bFoundAlready = false; );
  775. for( int i = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  776. {
  777. if( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i]->GetClonedEntity() == pEntity )
  778. {
  779. CPhysicsShadowClone *pClone = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  780. AssertMsg( bFoundAlready == false, "Multiple clones to linked portal found." );
  781. DBG_CODE_NOSCOPE( bFoundAlready = true; );
  782. DBG_CODE_NOSCOPE( szLastFoundMarker = pClone->m_szDebugMarker );
  783. //bool bHeldByPhyscannon = false;
  784. CBaseEntity *pHeldEntity = NULL;
  785. CPortal_Player *pPlayer = (CPortal_Player *)GetPlayerHoldingEntity( pEntity );
  786. if ( !pPlayer && pEntity->IsPlayer() )
  787. {
  788. pPlayer = (CPortal_Player *)pEntity;
  789. }
  790. if ( pPlayer )
  791. {
  792. pHeldEntity = GetPlayerHeldEntity( pPlayer );
  793. /*if ( !pHeldEntity )
  794. {
  795. pHeldEntity = PhysCannonGetHeldEntity( pPlayer->GetActiveWeapon() );
  796. bHeldByPhyscannon = true;
  797. }*/
  798. }
  799. if( pHeldEntity )
  800. {
  801. //player is holding the entity, force them to pick it back up again
  802. bool bIsHeldObjectOnOppositeSideOfPortal = pPlayer->IsHeldObjectOnOppositeSideOfPortal();
  803. pPlayer->m_bSilentDropAndPickup = true;
  804. pPlayer->ForceDropOfCarriedPhysObjects( pHeldEntity );
  805. pPlayer->SetHeldObjectOnOppositeSideOfPortal( bIsHeldObjectOnOppositeSideOfPortal );
  806. }
  807. else
  808. {
  809. pHeldEntity = NULL;
  810. }
  811. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  812. m_pLinkedPortal->MarkAsReleased( pClone );
  813. pClone->Free();
  814. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.FastRemove(i);
  815. if( pHeldEntity )
  816. {
  817. /*if ( bHeldByPhyscannon )
  818. {
  819. PhysCannonPickupObject( pPlayer, pHeldEntity );
  820. }
  821. else*/
  822. {
  823. PlayerPickupObject( pPlayer, pHeldEntity );
  824. }
  825. pPlayer->m_bSilentDropAndPickup = false;
  826. }
  827. DBG_CODE_NOSCOPE( continue; );
  828. break;
  829. }
  830. }
  831. }
  832. }
  833. }
  834. m_pCallbacks->PortalSimulator_ReleasedPhysicsOwnershipOfEntity( pEntity );
  835. }
  836. void CPortalSimulator::StartCloningEntity( CBaseEntity *pEntity )
  837. {
  838. if( CPhysicsShadowClone::IsShadowClone( pEntity ) || CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  839. return;
  840. if( (m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_FROM_MAIN) != 0 )
  841. return; //already cloned, no work to do
  842. #ifdef _DEBUG
  843. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Count(); --i >= 0; )
  844. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain[i] != pEntity );
  845. #endif
  846. //NDebugOverlay::EntityBounds( pEntity, 0, 255, 0, 50, 5.0f );
  847. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.AddToTail( pEntity );
  848. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] |= PSEF_CLONES_ENTITY_FROM_MAIN;
  849. }
  850. void CPortalSimulator::StopCloningEntity( CBaseEntity *pEntity )
  851. {
  852. if( (m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_FROM_MAIN) == 0 )
  853. {
  854. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Find( pEntity ) == -1 );
  855. return; //not cloned, no work to do
  856. }
  857. //NDebugOverlay::EntityBounds( pEntity, 255, 0, 0, 50, 5.0f );
  858. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.FastRemove(m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Find( pEntity ));
  859. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_CLONES_ENTITY_FROM_MAIN;
  860. }
  861. /*void CPortalSimulator::TeleportEntityToLinkedPortal( CBaseEntity *pEntity )
  862. {
  863. //TODO: migrate teleportation code from CProp_Portal::Touch to here
  864. }*/
  865. void CPortalSimulator::MarkAsOwned( CBaseEntity *pEntity )
  866. {
  867. Assert( pEntity != NULL );
  868. int iEntIndex = pEntity->entindex();
  869. Assert( s_OwnedEntityMap[iEntIndex] == NULL );
  870. #ifdef _DEBUG
  871. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  872. Assert( m_InternalData.Simulation.Dynamic.OwnedEntities[i] != pEntity );
  873. #endif
  874. Assert( (m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY) == 0 );
  875. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_OWNS_ENTITY;
  876. s_OwnedEntityMap[iEntIndex] = this;
  877. m_InternalData.Simulation.Dynamic.OwnedEntities.AddToTail( pEntity );
  878. if ( pEntity->IsPlayer() )
  879. {
  880. g_bPlayerIsInSimulator = true;
  881. }
  882. }
  883. void CPortalSimulator::MarkAsReleased( CBaseEntity *pEntity )
  884. {
  885. Assert( pEntity != NULL );
  886. int iEntIndex = pEntity->entindex();
  887. Assert( s_OwnedEntityMap[iEntIndex] == this );
  888. Assert( ((m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY) != 0) || CPSCollisionEntity::IsPortalSimulatorCollisionEntity(pEntity) );
  889. s_OwnedEntityMap[iEntIndex] = NULL;
  890. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_OWNS_ENTITY;
  891. int i;
  892. for( i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  893. {
  894. if( m_InternalData.Simulation.Dynamic.OwnedEntities[i] == pEntity )
  895. {
  896. m_InternalData.Simulation.Dynamic.OwnedEntities.FastRemove(i);
  897. break;
  898. }
  899. }
  900. Assert( i >= 0 );
  901. if ( pEntity->IsPlayer() )
  902. {
  903. g_bPlayerIsInSimulator = false;
  904. }
  905. }
  906. void CPortalSimulator::CreateAllPhysics( void )
  907. {
  908. if( IsSimulatingVPhysics() == false )
  909. return;
  910. CREATEDEBUGTIMER( functionTimer );
  911. STARTDEBUGTIMER( functionTimer );
  912. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  913. INCREMENTTABSPACING();
  914. CreateMinimumPhysics();
  915. CreateLocalPhysics();
  916. CreateLinkedPhysics();
  917. STOPDEBUGTIMER( functionTimer );
  918. DECREMENTTABSPACING();
  919. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  920. }
  921. void CPortalSimulator::CreateMinimumPhysics( void )
  922. {
  923. if( IsSimulatingVPhysics() == false )
  924. return;
  925. if( m_InternalData.Simulation.pPhysicsEnvironment != NULL )
  926. return;
  927. CREATEDEBUGTIMER( functionTimer );
  928. STARTDEBUGTIMER( functionTimer );
  929. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateMinimumPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  930. INCREMENTTABSPACING();
  931. m_InternalData.Simulation.pPhysicsEnvironment = physenv_main;
  932. STOPDEBUGTIMER( functionTimer );
  933. DECREMENTTABSPACING();
  934. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateMinimumPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  935. }
  936. void CPortalSimulator::CreateLocalPhysics( void )
  937. {
  938. if( IsSimulatingVPhysics() == false )
  939. return;
  940. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create local physics before being placed." );
  941. if( m_CreationChecklist.bLocalPhysicsGenerated )
  942. return;
  943. CREATEDEBUGTIMER( functionTimer );
  944. STARTDEBUGTIMER( functionTimer );
  945. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  946. INCREMENTTABSPACING();
  947. CreateMinimumPhysics();
  948. //int iDefaultSurfaceIndex = physprops->GetSurfaceIndex( "default" );
  949. objectparams_t params = g_PhysDefaultObjectParams;
  950. // Any non-moving object can point to world safely-- Make sure we dont use 'params' for something other than that beyond this point.
  951. if( m_InternalData.Simulation.pCollisionEntity )
  952. params.pGameData = m_InternalData.Simulation.pCollisionEntity;
  953. else
  954. GetWorldEntity();
  955. //World
  956. {
  957. Assert( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  958. if( m_InternalData.Simulation.Static.World.Brushes.pCollideable != NULL )
  959. {
  960. m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.World.Brushes.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  961. if( (m_InternalData.Simulation.pCollisionEntity != NULL) && (m_InternalData.Simulation.pCollisionEntity->VPhysicsGetObject() == NULL) )
  962. m_InternalData.Simulation.pCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject);
  963. m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  964. }
  965. //Assert( m_InternalData.Simulation.Static.World.StaticProps.PhysicsObjects.Count() == 0 ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  966. #ifdef _DEBUG
  967. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  968. {
  969. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  970. }
  971. #endif
  972. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0 )
  973. {
  974. Assert( m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists );
  975. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  976. {
  977. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  978. Assert( Representation.pCollide != NULL );
  979. Assert( Representation.pPhysicsObject == NULL );
  980. Representation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( Representation.pCollide, Representation.iTraceSurfaceProps, vec3_origin, vec3_angle, &params );
  981. Assert( Representation.pPhysicsObject != NULL );
  982. Representation.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  983. }
  984. }
  985. m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists = true;
  986. }
  987. //Wall
  988. {
  989. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  990. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable != NULL )
  991. {
  992. m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  993. if( (m_InternalData.Simulation.pCollisionEntity != NULL) && (m_InternalData.Simulation.pCollisionEntity->VPhysicsGetObject() == NULL) )
  994. m_InternalData.Simulation.pCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject);
  995. m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  996. }
  997. Assert( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  998. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable != NULL )
  999. {
  1000. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  1001. if( (m_InternalData.Simulation.pCollisionEntity != NULL) && (m_InternalData.Simulation.pCollisionEntity->VPhysicsGetObject() == NULL) )
  1002. m_InternalData.Simulation.pCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject);
  1003. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1004. }
  1005. }
  1006. //re-acquire environment physics for owned entities
  1007. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1008. TakePhysicsOwnership( m_InternalData.Simulation.Dynamic.OwnedEntities[i] );
  1009. if( m_InternalData.Simulation.pCollisionEntity )
  1010. m_InternalData.Simulation.pCollisionEntity->CollisionRulesChanged();
  1011. STOPDEBUGTIMER( functionTimer );
  1012. DECREMENTTABSPACING();
  1013. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1014. m_CreationChecklist.bLocalPhysicsGenerated = true;
  1015. }
  1016. void CPortalSimulator::CreateLinkedPhysics( void )
  1017. {
  1018. if( IsSimulatingVPhysics() == false )
  1019. return;
  1020. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create linked physics before being placed itself." );
  1021. if( (m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_bLocalDataIsReady == false) )
  1022. return;
  1023. if( m_CreationChecklist.bLinkedPhysicsGenerated )
  1024. return;
  1025. CREATEDEBUGTIMER( functionTimer );
  1026. STARTDEBUGTIMER( functionTimer );
  1027. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLinkedPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1028. INCREMENTTABSPACING();
  1029. CreateMinimumPhysics();
  1030. //int iDefaultSurfaceIndex = physprops->GetSurfaceIndex( "default" );
  1031. objectparams_t params = g_PhysDefaultObjectParams;
  1032. if( m_InternalData.Simulation.pCollisionEntity )
  1033. params.pGameData = m_InternalData.Simulation.pCollisionEntity;
  1034. else
  1035. params.pGameData = GetWorldEntity();
  1036. //everything in our linked collision should be based on the linked portal's world collision
  1037. PS_SD_Static_World_t &RemoteSimulationStaticWorld = m_pLinkedPortal->m_InternalData.Simulation.Static.World;
  1038. Assert( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1039. if( RemoteSimulationStaticWorld.Brushes.pCollideable != NULL )
  1040. {
  1041. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( RemoteSimulationStaticWorld.Brushes.pCollideable, m_pLinkedPortal->m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform, m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, &params );
  1042. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1043. }
  1044. Assert( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count() == 0 ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1045. if( RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations.Count() != 0 )
  1046. {
  1047. for( int i = RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1048. {
  1049. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations[i];
  1050. IPhysicsObject *pPhysObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( Representation.pCollide, Representation.iTraceSurfaceProps, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform, m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, &params );
  1051. if( pPhysObject )
  1052. {
  1053. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.AddToTail( pPhysObject );
  1054. pPhysObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1055. }
  1056. }
  1057. }
  1058. //re-clone physicsshadowclones from the remote environment
  1059. CUtlVector<CBaseEntity *> &RemoteOwnedEntities = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.OwnedEntities;
  1060. for( int i = RemoteOwnedEntities.Count(); --i >= 0; )
  1061. {
  1062. if( CPhysicsShadowClone::IsShadowClone( RemoteOwnedEntities[i] ) ||
  1063. CPSCollisionEntity::IsPortalSimulatorCollisionEntity( RemoteOwnedEntities[i] ) )
  1064. continue;
  1065. int j;
  1066. for( j = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --j >= 0; )
  1067. {
  1068. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[j]->GetClonedEntity() == RemoteOwnedEntities[i] )
  1069. break;
  1070. }
  1071. if( j >= 0 ) //already cloning
  1072. continue;
  1073. EHANDLE hEnt = RemoteOwnedEntities[i];
  1074. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::CreateLinkedPhysics(): From Linked Portal", &m_InternalData.Placement.matLinkedToThis.As3x4() );
  1075. if( pClone )
  1076. {
  1077. MarkAsOwned( pClone );
  1078. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS;
  1079. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  1080. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  1081. }
  1082. }
  1083. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  1084. {
  1085. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  1086. m_bInCrossLinkedFunction = true;
  1087. m_pLinkedPortal->CreateLinkedPhysics();
  1088. m_bInCrossLinkedFunction = false;
  1089. }
  1090. if( m_InternalData.Simulation.pCollisionEntity )
  1091. m_InternalData.Simulation.pCollisionEntity->CollisionRulesChanged();
  1092. STOPDEBUGTIMER( functionTimer );
  1093. DECREMENTTABSPACING();
  1094. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLinkedPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1095. m_CreationChecklist.bLinkedPhysicsGenerated = true;
  1096. }
  1097. void CPortalSimulator::ClearAllPhysics( void )
  1098. {
  1099. CREATEDEBUGTIMER( functionTimer );
  1100. STARTDEBUGTIMER( functionTimer );
  1101. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1102. INCREMENTTABSPACING();
  1103. ClearLinkedPhysics();
  1104. ClearLocalPhysics();
  1105. ClearMinimumPhysics();
  1106. STOPDEBUGTIMER( functionTimer );
  1107. DECREMENTTABSPACING();
  1108. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1109. }
  1110. void CPortalSimulator::ClearMinimumPhysics( void )
  1111. {
  1112. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  1113. return;
  1114. CREATEDEBUGTIMER( functionTimer );
  1115. STARTDEBUGTIMER( functionTimer );
  1116. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearMinimumPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1117. INCREMENTTABSPACING();
  1118. m_InternalData.Simulation.pPhysicsEnvironment = NULL;
  1119. STOPDEBUGTIMER( functionTimer );
  1120. DECREMENTTABSPACING();
  1121. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearMinimumPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1122. }
  1123. void CPortalSimulator::ClearLocalPhysics( void )
  1124. {
  1125. if( m_CreationChecklist.bLocalPhysicsGenerated == false )
  1126. return;
  1127. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  1128. return;
  1129. CREATEDEBUGTIMER( functionTimer );
  1130. STARTDEBUGTIMER( functionTimer );
  1131. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1132. INCREMENTTABSPACING();
  1133. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  1134. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( true ); //if we don't do this, things crash the next time we cleanup the delete list while checking mindists
  1135. if( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject )
  1136. {
  1137. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject );
  1138. m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject = NULL;
  1139. }
  1140. if( m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists &&
  1141. (m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) )
  1142. {
  1143. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1144. {
  1145. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  1146. if( Representation.pPhysicsObject )
  1147. {
  1148. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( Representation.pPhysicsObject );
  1149. Representation.pPhysicsObject = NULL;
  1150. }
  1151. }
  1152. }
  1153. m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists = false;
  1154. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject )
  1155. {
  1156. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject );
  1157. m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject = NULL;
  1158. }
  1159. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject )
  1160. {
  1161. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject );
  1162. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject = NULL;
  1163. }
  1164. //all physics clones
  1165. {
  1166. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1167. {
  1168. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  1169. Assert( GetSimulatorThatOwnsEntity( pClone ) == this );
  1170. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  1171. MarkAsReleased( pClone );
  1172. Assert( GetSimulatorThatOwnsEntity( pClone ) == NULL );
  1173. pClone->Free();
  1174. }
  1175. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  1176. }
  1177. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0 );
  1178. //release physics ownership of owned entities
  1179. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1180. ReleasePhysicsOwnership( m_InternalData.Simulation.Dynamic.OwnedEntities[i], false );
  1181. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0 );
  1182. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  1183. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( false );
  1184. if( m_InternalData.Simulation.pCollisionEntity )
  1185. m_InternalData.Simulation.pCollisionEntity->CollisionRulesChanged();
  1186. STOPDEBUGTIMER( functionTimer );
  1187. DECREMENTTABSPACING();
  1188. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1189. m_CreationChecklist.bLocalPhysicsGenerated = false;
  1190. }
  1191. void CPortalSimulator::ClearLinkedPhysics( void )
  1192. {
  1193. if( m_CreationChecklist.bLinkedPhysicsGenerated == false )
  1194. return;
  1195. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  1196. return;
  1197. CREATEDEBUGTIMER( functionTimer );
  1198. STARTDEBUGTIMER( functionTimer );
  1199. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLinkedPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1200. INCREMENTTABSPACING();
  1201. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  1202. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( true ); //if we don't do this, things crash the next time we cleanup the delete list while checking mindists
  1203. //static collideables
  1204. {
  1205. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject )
  1206. {
  1207. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject );
  1208. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject = NULL;
  1209. }
  1210. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count() )
  1211. {
  1212. for( int i = m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count(); --i >= 0; )
  1213. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects[i] );
  1214. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.RemoveAll();
  1215. }
  1216. }
  1217. //clones from the linked portal
  1218. {
  1219. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1220. {
  1221. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  1222. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  1223. MarkAsReleased( pClone );
  1224. pClone->Free();
  1225. }
  1226. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  1227. }
  1228. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  1229. {
  1230. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  1231. m_bInCrossLinkedFunction = true;
  1232. m_pLinkedPortal->ClearLinkedPhysics();
  1233. m_bInCrossLinkedFunction = false;
  1234. }
  1235. Assert( (m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0) &&
  1236. ((m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0)) );
  1237. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  1238. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( false );
  1239. if( m_InternalData.Simulation.pCollisionEntity )
  1240. m_InternalData.Simulation.pCollisionEntity->CollisionRulesChanged();
  1241. STOPDEBUGTIMER( functionTimer );
  1242. DECREMENTTABSPACING();
  1243. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLinkedPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1244. m_CreationChecklist.bLinkedPhysicsGenerated = false;
  1245. }
  1246. void CPortalSimulator::ClearLinkedEntities( void )
  1247. {
  1248. //clones from the linked portal
  1249. {
  1250. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1251. {
  1252. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  1253. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  1254. MarkAsReleased( pClone );
  1255. pClone->Free();
  1256. }
  1257. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  1258. }
  1259. }
  1260. #endif //#ifndef CLIENT_DLL
  1261. void CPortalSimulator::CreateAllCollision( void )
  1262. {
  1263. CREATEDEBUGTIMER( functionTimer );
  1264. STARTDEBUGTIMER( functionTimer );
  1265. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1266. INCREMENTTABSPACING();
  1267. CreateLocalCollision();
  1268. CreateLinkedCollision();
  1269. STOPDEBUGTIMER( functionTimer );
  1270. DECREMENTTABSPACING();
  1271. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1272. }
  1273. void CPortalSimulator::CreateLocalCollision( void )
  1274. {
  1275. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create local collision before being placed." );
  1276. if( m_CreationChecklist.bLocalCollisionGenerated )
  1277. return;
  1278. if( IsCollisionGenerationEnabled() == false )
  1279. return;
  1280. DEBUGTIMERONLY( s_iPortalSimulatorGUID = GetPortalSimulatorGUID() );
  1281. CREATEDEBUGTIMER( functionTimer );
  1282. STARTDEBUGTIMER( functionTimer );
  1283. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1284. INCREMENTTABSPACING();
  1285. CREATEDEBUGTIMER( worldBrushTimer );
  1286. STARTDEBUGTIMER( worldBrushTimer );
  1287. Assert( m_InternalData.Simulation.Static.World.Brushes.pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1288. if( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() != 0 )
  1289. m_InternalData.Simulation.Static.World.Brushes.pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Base(), m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() );
  1290. STOPDEBUGTIMER( worldBrushTimer );
  1291. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldBrushTimer.GetDuration().GetMillisecondsF() ); );
  1292. CREATEDEBUGTIMER( worldPropTimer );
  1293. STARTDEBUGTIMER( worldPropTimer );
  1294. #ifdef _DEBUG
  1295. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1296. {
  1297. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide == NULL );
  1298. }
  1299. #endif
  1300. Assert( m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists == false ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1301. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0 )
  1302. {
  1303. Assert( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() != 0 );
  1304. CPolyhedron **pPolyhedronsBase = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Base();
  1305. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1306. {
  1307. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  1308. Assert( Representation.pCollide == NULL );
  1309. Representation.pCollide = ConvertPolyhedronsToCollideable( &pPolyhedronsBase[Representation.PolyhedronGroup.iStartIndex], Representation.PolyhedronGroup.iNumPolyhedrons );
  1310. Assert( Representation.pCollide != NULL );
  1311. }
  1312. }
  1313. m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists = true;
  1314. STOPDEBUGTIMER( worldPropTimer );
  1315. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Props=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldPropTimer.GetDuration().GetMillisecondsF() ); );
  1316. if( IsSimulatingVPhysics() )
  1317. {
  1318. //only need the tube when simulating player movement
  1319. //TODO: replace the complete wall with the wall shell
  1320. CREATEDEBUGTIMER( wallBrushTimer );
  1321. STARTDEBUGTIMER( wallBrushTimer );
  1322. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1323. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Count() != 0 )
  1324. m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Base(), m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Count() );
  1325. STOPDEBUGTIMER( wallBrushTimer );
  1326. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWall Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, wallBrushTimer.GetDuration().GetMillisecondsF() ); );
  1327. }
  1328. CREATEDEBUGTIMER( wallTubeTimer );
  1329. STARTDEBUGTIMER( wallTubeTimer );
  1330. Assert( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1331. if( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() != 0 )
  1332. m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Base(), m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() );
  1333. STOPDEBUGTIMER( wallTubeTimer );
  1334. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWall Tube=%fms\n", GetPortalSimulatorGUID(), TABSPACING, wallTubeTimer.GetDuration().GetMillisecondsF() ); );
  1335. //grab surface properties to use for the portal environment
  1336. {
  1337. CTraceFilterWorldAndPropsOnly filter;
  1338. trace_t Trace;
  1339. UTIL_TraceLine( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vForward, m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vForward * 500.0f), MASK_SOLID_BRUSHONLY, &filter, &Trace );
  1340. if( Trace.fraction != 1.0f )
  1341. {
  1342. m_InternalData.Simulation.Static.SurfaceProperties.contents = Trace.contents;
  1343. m_InternalData.Simulation.Static.SurfaceProperties.surface = Trace.surface;
  1344. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = Trace.m_pEnt;
  1345. }
  1346. else
  1347. {
  1348. m_InternalData.Simulation.Static.SurfaceProperties.contents = CONTENTS_SOLID;
  1349. m_InternalData.Simulation.Static.SurfaceProperties.surface.name = "**empty**";
  1350. m_InternalData.Simulation.Static.SurfaceProperties.surface.flags = 0;
  1351. m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps = 0;
  1352. #ifndef CLIENT_DLL
  1353. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = GetWorldEntity();
  1354. #else
  1355. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = GetClientWorldEntity();
  1356. #endif
  1357. }
  1358. #ifndef CLIENT_DLL
  1359. if( m_InternalData.Simulation.pCollisionEntity )
  1360. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = m_InternalData.Simulation.pCollisionEntity;
  1361. #endif
  1362. }
  1363. STOPDEBUGTIMER( functionTimer );
  1364. DECREMENTTABSPACING();
  1365. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1366. m_CreationChecklist.bLocalCollisionGenerated = true;
  1367. }
  1368. void CPortalSimulator::CreateLinkedCollision( void )
  1369. {
  1370. if( m_CreationChecklist.bLinkedCollisionGenerated )
  1371. return;
  1372. if( IsCollisionGenerationEnabled() == false )
  1373. return;
  1374. //nothing to do for now, the current set of collision is just transformed from the linked simulator when needed. It's really cheap to transform in traces and physics generation.
  1375. m_CreationChecklist.bLinkedCollisionGenerated = true;
  1376. }
  1377. void CPortalSimulator::ClearAllCollision( void )
  1378. {
  1379. CREATEDEBUGTIMER( functionTimer );
  1380. STARTDEBUGTIMER( functionTimer );
  1381. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1382. INCREMENTTABSPACING();
  1383. ClearLinkedCollision();
  1384. ClearLocalCollision();
  1385. STOPDEBUGTIMER( functionTimer );
  1386. DECREMENTTABSPACING();
  1387. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1388. }
  1389. void CPortalSimulator::ClearLinkedCollision( void )
  1390. {
  1391. if( m_CreationChecklist.bLinkedCollisionGenerated == false )
  1392. return;
  1393. //nothing to do for now, the current set of collision is just transformed from the linked simulator when needed. It's really cheap to transform in traces and physics generation.
  1394. m_CreationChecklist.bLinkedCollisionGenerated = false;
  1395. }
  1396. void CPortalSimulator::ClearLocalCollision( void )
  1397. {
  1398. if( m_CreationChecklist.bLocalCollisionGenerated == false )
  1399. return;
  1400. CREATEDEBUGTIMER( functionTimer );
  1401. STARTDEBUGTIMER( functionTimer );
  1402. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1403. INCREMENTTABSPACING();
  1404. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable )
  1405. {
  1406. physcollision->DestroyCollide( m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable );
  1407. m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable = NULL;
  1408. }
  1409. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable )
  1410. {
  1411. physcollision->DestroyCollide( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable );
  1412. m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable = NULL;
  1413. }
  1414. if( m_InternalData.Simulation.Static.World.Brushes.pCollideable )
  1415. {
  1416. physcollision->DestroyCollide( m_InternalData.Simulation.Static.World.Brushes.pCollideable );
  1417. m_InternalData.Simulation.Static.World.Brushes.pCollideable = NULL;
  1418. }
  1419. if( m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists &&
  1420. (m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) )
  1421. {
  1422. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1423. {
  1424. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  1425. if( Representation.pCollide )
  1426. {
  1427. physcollision->DestroyCollide( Representation.pCollide );
  1428. Representation.pCollide = NULL;
  1429. }
  1430. }
  1431. }
  1432. m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists = false;
  1433. STOPDEBUGTIMER( functionTimer );
  1434. DECREMENTTABSPACING();
  1435. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1436. m_CreationChecklist.bLocalCollisionGenerated = false;
  1437. }
  1438. void CPortalSimulator::CreatePolyhedrons( void )
  1439. {
  1440. if( m_CreationChecklist.bPolyhedronsGenerated )
  1441. return;
  1442. if( IsCollisionGenerationEnabled() == false )
  1443. return;
  1444. CREATEDEBUGTIMER( functionTimer );
  1445. STARTDEBUGTIMER( functionTimer );
  1446. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreatePolyhedrons() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1447. INCREMENTTABSPACING();
  1448. //forward reverse conventions signify whether the normal is the same direction as m_InternalData.Placement.PortalPlane.m_Normal
  1449. //World and wall conventions signify whether it's been shifted in front of the portal plane or behind it
  1450. float fWorldClipPlane_Forward[4] = { m_InternalData.Placement.PortalPlane.m_Normal.x,
  1451. m_InternalData.Placement.PortalPlane.m_Normal.y,
  1452. m_InternalData.Placement.PortalPlane.m_Normal.z,
  1453. m_InternalData.Placement.PortalPlane.m_Dist + PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT };
  1454. float fWorldClipPlane_Reverse[4] = { -fWorldClipPlane_Forward[0],
  1455. -fWorldClipPlane_Forward[1],
  1456. -fWorldClipPlane_Forward[2],
  1457. -fWorldClipPlane_Forward[3] };
  1458. float fWallClipPlane_Forward[4] = { m_InternalData.Placement.PortalPlane.m_Normal.x,
  1459. m_InternalData.Placement.PortalPlane.m_Normal.y,
  1460. m_InternalData.Placement.PortalPlane.m_Normal.z,
  1461. m_InternalData.Placement.PortalPlane.m_Dist }; // - PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT
  1462. //float fWallClipPlane_Reverse[4] = { -fWallClipPlane_Forward[0],
  1463. // -fWallClipPlane_Forward[1],
  1464. // -fWallClipPlane_Forward[2],
  1465. // -fWallClipPlane_Forward[3] };
  1466. //World
  1467. {
  1468. Vector vOBBForward = m_InternalData.Placement.vForward;
  1469. Vector vOBBRight = m_InternalData.Placement.vRight;
  1470. Vector vOBBUp = m_InternalData.Placement.vUp;
  1471. //scale the extents to usable sizes
  1472. float flScaleX = sv_portal_collision_sim_bounds_x.GetFloat();
  1473. if ( flScaleX < 200.0f )
  1474. flScaleX = 200.0f;
  1475. float flScaleY = sv_portal_collision_sim_bounds_y.GetFloat();
  1476. if ( flScaleY < 200.0f )
  1477. flScaleY = 200.0f;
  1478. float flScaleZ = sv_portal_collision_sim_bounds_z.GetFloat();
  1479. if ( flScaleZ < 252.0f )
  1480. flScaleZ = 252.0f;
  1481. vOBBForward *= flScaleX;
  1482. vOBBRight *= flScaleY;
  1483. vOBBUp *= flScaleZ; // default size for scale z (252) is player (height + portal half height) * 2. Any smaller than this will allow for players to
  1484. // reach unsimulated geometry before an end touch with teh portal.
  1485. Vector ptOBBOrigin = m_InternalData.Placement.ptCenter;
  1486. ptOBBOrigin -= vOBBRight / 2.0f;
  1487. ptOBBOrigin -= vOBBUp / 2.0f;
  1488. Vector vAABBMins, vAABBMaxs;
  1489. vAABBMins = vAABBMaxs = ptOBBOrigin;
  1490. for( int i = 1; i != 8; ++i )
  1491. {
  1492. Vector ptTest = ptOBBOrigin;
  1493. if( i & (1 << 0) ) ptTest += vOBBForward;
  1494. if( i & (1 << 1) ) ptTest += vOBBRight;
  1495. if( i & (1 << 2) ) ptTest += vOBBUp;
  1496. if( ptTest.x < vAABBMins.x ) vAABBMins.x = ptTest.x;
  1497. if( ptTest.y < vAABBMins.y ) vAABBMins.y = ptTest.y;
  1498. if( ptTest.z < vAABBMins.z ) vAABBMins.z = ptTest.z;
  1499. if( ptTest.x > vAABBMaxs.x ) vAABBMaxs.x = ptTest.x;
  1500. if( ptTest.y > vAABBMaxs.y ) vAABBMaxs.y = ptTest.y;
  1501. if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z;
  1502. }
  1503. //Brushes
  1504. {
  1505. Assert( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() == 0 );
  1506. CUtlVector<int> WorldBrushes;
  1507. enginetrace->GetBrushesInAABB( vAABBMins, vAABBMaxs, &WorldBrushes, MASK_SOLID_BRUSHONLY|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP );
  1508. //create locally clipped polyhedrons for the world
  1509. {
  1510. int *pBrushList = WorldBrushes.Base();
  1511. int iBrushCount = WorldBrushes.Count();
  1512. ConvertBrushListToClippedPolyhedronList( pBrushList, iBrushCount, fWorldClipPlane_Reverse, 1, PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.World.Brushes.Polyhedrons );
  1513. }
  1514. }
  1515. //static props
  1516. {
  1517. Assert( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() == 0 );
  1518. CUtlVector<ICollideable *> StaticProps;
  1519. staticpropmgr->GetAllStaticPropsInAABB( vAABBMins, vAABBMaxs, &StaticProps );
  1520. for( int i = StaticProps.Count(); --i >= 0; )
  1521. {
  1522. ICollideable *pProp = StaticProps[i];
  1523. CPolyhedron *PolyhedronArray[1024];
  1524. int iPolyhedronCount = g_StaticCollisionPolyhedronCache.GetStaticPropPolyhedrons( pProp, PolyhedronArray, 1024 );
  1525. StaticPropPolyhedronGroups_t indices;
  1526. indices.iStartIndex = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count();
  1527. for( int j = 0; j != iPolyhedronCount; ++j )
  1528. {
  1529. CPolyhedron *pPropPolyhedronPiece = PolyhedronArray[j];
  1530. if( pPropPolyhedronPiece )
  1531. {
  1532. CPolyhedron *pClippedPropPolyhedron = ClipPolyhedron( pPropPolyhedronPiece, fWorldClipPlane_Reverse, 1, 0.01f, false );
  1533. if( pClippedPropPolyhedron )
  1534. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.AddToTail( pClippedPropPolyhedron );
  1535. }
  1536. }
  1537. indices.iNumPolyhedrons = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() - indices.iStartIndex;
  1538. if( indices.iNumPolyhedrons != 0 )
  1539. {
  1540. int index = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.AddToTail();
  1541. PS_SD_Static_World_StaticProps_ClippedProp_t &NewEntry = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[index];
  1542. NewEntry.PolyhedronGroup = indices;
  1543. NewEntry.pCollide = NULL;
  1544. #ifndef CLIENT_DLL
  1545. NewEntry.pPhysicsObject = NULL;
  1546. #endif
  1547. NewEntry.pSourceProp = pProp->GetEntityHandle();
  1548. const model_t *pModel = pProp->GetCollisionModel();
  1549. bool bIsStudioModel = pModel && (modelinfo->GetModelType( pModel ) == mod_studio);
  1550. AssertOnce( bIsStudioModel );
  1551. if( bIsStudioModel )
  1552. {
  1553. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pModel );
  1554. Assert( pStudioHdr != NULL );
  1555. NewEntry.iTraceContents = pStudioHdr->contents;
  1556. NewEntry.iTraceSurfaceProps = physprops->GetSurfaceIndex( pStudioHdr->pszSurfaceProp() );
  1557. }
  1558. else
  1559. {
  1560. NewEntry.iTraceContents = m_InternalData.Simulation.Static.SurfaceProperties.contents;
  1561. NewEntry.iTraceSurfaceProps = m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps;
  1562. }
  1563. }
  1564. }
  1565. }
  1566. }
  1567. //(Holy) Wall
  1568. {
  1569. Assert( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() == 0 );
  1570. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Count() == 0 );
  1571. Vector vBackward = -m_InternalData.Placement.vForward;
  1572. Vector vLeft = -m_InternalData.Placement.vRight;
  1573. Vector vDown = -m_InternalData.Placement.vUp;
  1574. Vector vOBBForward = -m_InternalData.Placement.vForward;
  1575. Vector vOBBRight = -m_InternalData.Placement.vRight;
  1576. Vector vOBBUp = m_InternalData.Placement.vUp;
  1577. //scale the extents to usable sizes
  1578. vOBBForward *= PORTAL_WALL_FARDIST / 2.0f;
  1579. vOBBRight *= PORTAL_WALL_FARDIST * 2.0f;
  1580. vOBBUp *= PORTAL_WALL_FARDIST * 2.0f;
  1581. Vector ptOBBOrigin = m_InternalData.Placement.ptCenter;
  1582. ptOBBOrigin -= vOBBRight / 2.0f;
  1583. ptOBBOrigin -= vOBBUp / 2.0f;
  1584. Vector vAABBMins, vAABBMaxs;
  1585. vAABBMins = vAABBMaxs = ptOBBOrigin;
  1586. for( int i = 1; i != 8; ++i )
  1587. {
  1588. Vector ptTest = ptOBBOrigin;
  1589. if( i & (1 << 0) ) ptTest += vOBBForward;
  1590. if( i & (1 << 1) ) ptTest += vOBBRight;
  1591. if( i & (1 << 2) ) ptTest += vOBBUp;
  1592. if( ptTest.x < vAABBMins.x ) vAABBMins.x = ptTest.x;
  1593. if( ptTest.y < vAABBMins.y ) vAABBMins.y = ptTest.y;
  1594. if( ptTest.z < vAABBMins.z ) vAABBMins.z = ptTest.z;
  1595. if( ptTest.x > vAABBMaxs.x ) vAABBMaxs.x = ptTest.x;
  1596. if( ptTest.y > vAABBMaxs.y ) vAABBMaxs.y = ptTest.y;
  1597. if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z;
  1598. }
  1599. float fPlanes[6 * 4];
  1600. //first and second planes are always forward and backward planes
  1601. fPlanes[(0*4) + 0] = fWallClipPlane_Forward[0];
  1602. fPlanes[(0*4) + 1] = fWallClipPlane_Forward[1];
  1603. fPlanes[(0*4) + 2] = fWallClipPlane_Forward[2];
  1604. fPlanes[(0*4) + 3] = fWallClipPlane_Forward[3] - PORTAL_WALL_TUBE_OFFSET;
  1605. fPlanes[(1*4) + 0] = vBackward.x;
  1606. fPlanes[(1*4) + 1] = vBackward.y;
  1607. fPlanes[(1*4) + 2] = vBackward.z;
  1608. float fTubeDepthDist = vBackward.Dot( m_InternalData.Placement.ptCenter + (vBackward * (PORTAL_WALL_TUBE_DEPTH + PORTAL_WALL_TUBE_OFFSET)) );
  1609. fPlanes[(1*4) + 3] = fTubeDepthDist;
  1610. //the remaining planes will always have the same ordering of normals, with different distances plugged in for each convex we're creating
  1611. //normal order is up, down, left, right
  1612. fPlanes[(2*4) + 0] = m_InternalData.Placement.vUp.x;
  1613. fPlanes[(2*4) + 1] = m_InternalData.Placement.vUp.y;
  1614. fPlanes[(2*4) + 2] = m_InternalData.Placement.vUp.z;
  1615. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * PORTAL_HOLE_HALF_HEIGHT) );
  1616. fPlanes[(3*4) + 0] = vDown.x;
  1617. fPlanes[(3*4) + 1] = vDown.y;
  1618. fPlanes[(3*4) + 2] = vDown.z;
  1619. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + (vDown * PORTAL_HOLE_HALF_HEIGHT) );
  1620. fPlanes[(4*4) + 0] = vLeft.x;
  1621. fPlanes[(4*4) + 1] = vLeft.y;
  1622. fPlanes[(4*4) + 2] = vLeft.z;
  1623. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + (vLeft * PORTAL_HOLE_HALF_WIDTH) );
  1624. fPlanes[(5*4) + 0] = m_InternalData.Placement.vRight.x;
  1625. fPlanes[(5*4) + 1] = m_InternalData.Placement.vRight.y;
  1626. fPlanes[(5*4) + 2] = m_InternalData.Placement.vRight.z;
  1627. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * PORTAL_HOLE_HALF_WIDTH) );
  1628. float *fSidePlanesOnly = &fPlanes[(2*4)];
  1629. //these 2 get re-used a bit
  1630. float fFarRightPlaneDistance = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (PORTAL_WALL_FARDIST * 10.0f) );
  1631. float fFarLeftPlaneDistance = vLeft.Dot( m_InternalData.Placement.ptCenter + vLeft * (PORTAL_WALL_FARDIST * 10.0f) );
  1632. CUtlVector<int> WallBrushes;
  1633. CUtlVector<CPolyhedron *> WallBrushPolyhedrons_ClippedToWall;
  1634. CPolyhedron **pWallClippedPolyhedrons = NULL;
  1635. int iWallClippedPolyhedronCount = 0;
  1636. if( IsSimulatingVPhysics() ) //if not simulating vphysics, we skip making the entire wall, and just create the minimal tube instead
  1637. {
  1638. enginetrace->GetBrushesInAABB( vAABBMins, vAABBMaxs, &WallBrushes, MASK_SOLID_BRUSHONLY );
  1639. if( WallBrushes.Count() != 0 )
  1640. ConvertBrushListToClippedPolyhedronList( WallBrushes.Base(), WallBrushes.Count(), fPlanes, 1, PORTAL_POLYHEDRON_CUT_EPSILON, &WallBrushPolyhedrons_ClippedToWall );
  1641. if( WallBrushPolyhedrons_ClippedToWall.Count() != 0 )
  1642. {
  1643. for( int i = WallBrushPolyhedrons_ClippedToWall.Count(); --i >= 0; )
  1644. {
  1645. CPolyhedron *pPolyhedron = ClipPolyhedron( WallBrushPolyhedrons_ClippedToWall[i], fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, true );
  1646. if( pPolyhedron )
  1647. {
  1648. //a chunk of this brush passes through the hole, not eligible to be removed from cutting
  1649. pPolyhedron->Release();
  1650. }
  1651. else
  1652. {
  1653. //no part of this brush interacts with the hole, no point in cutting the brush any later
  1654. m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.AddToTail( WallBrushPolyhedrons_ClippedToWall[i] );
  1655. WallBrushPolyhedrons_ClippedToWall.FastRemove( i );
  1656. }
  1657. }
  1658. if( WallBrushPolyhedrons_ClippedToWall.Count() != 0 ) //might have become 0 while removing uncut brushes
  1659. {
  1660. pWallClippedPolyhedrons = WallBrushPolyhedrons_ClippedToWall.Base();
  1661. iWallClippedPolyhedronCount = WallBrushPolyhedrons_ClippedToWall.Count();
  1662. }
  1663. }
  1664. }
  1665. //upper wall
  1666. {
  1667. //minimal portion that extends into the hole space
  1668. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  1669. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS) );
  1670. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vUp * PORTAL_HOLE_HALF_HEIGHT );
  1671. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + vLeft * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1672. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1673. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  1674. if( pTubePolyhedron )
  1675. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  1676. //general hole cut
  1677. //fPlanes[(1*4) + 3] += 2000.0f;
  1678. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vUp * (PORTAL_WALL_FARDIST * 10.0f) );
  1679. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS) );
  1680. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  1681. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  1682. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons );
  1683. }
  1684. //lower wall
  1685. {
  1686. //minimal portion that extends into the hole space
  1687. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  1688. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (vDown * PORTAL_HOLE_HALF_HEIGHT) );
  1689. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + vDown * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS) );
  1690. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + vLeft * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1691. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1692. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  1693. if( pTubePolyhedron )
  1694. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  1695. //general hole cut
  1696. //fPlanes[(1*4) + 3] += 2000.0f;
  1697. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (vDown * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS)) );
  1698. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + (vDown * (PORTAL_WALL_FARDIST * 10.0f)) );
  1699. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  1700. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  1701. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons );
  1702. }
  1703. //left wall
  1704. {
  1705. //minimal portion that extends into the hole space
  1706. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  1707. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * PORTAL_HOLE_HALF_HEIGHT) );
  1708. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + (vDown * PORTAL_HOLE_HALF_HEIGHT) );
  1709. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + (vLeft * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS)) );
  1710. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (vLeft * PORTAL_HOLE_HALF_WIDTH) );
  1711. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  1712. if( pTubePolyhedron )
  1713. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  1714. //general hole cut
  1715. //fPlanes[(1*4) + 3] += 2000.0f;
  1716. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS)) );
  1717. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS)) );
  1718. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  1719. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (vLeft * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS)) );
  1720. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons );
  1721. }
  1722. //right wall
  1723. {
  1724. //minimal portion that extends into the hole space
  1725. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  1726. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT)) );
  1727. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + (vDown * (PORTAL_HOLE_HALF_HEIGHT)) );
  1728. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * PORTAL_HOLE_HALF_WIDTH );
  1729. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1730. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  1731. if( pTubePolyhedron )
  1732. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  1733. //general hole cut
  1734. //fPlanes[(1*4) + 3] += 2000.0f;
  1735. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS)) );
  1736. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter + (vDown * (PORTAL_HOLE_HALF_HEIGHT + PORTAL_WALL_MIN_THICKNESS)) );
  1737. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (PORTAL_HOLE_HALF_WIDTH + PORTAL_WALL_MIN_THICKNESS) );
  1738. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  1739. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons );
  1740. }
  1741. for( int i = WallBrushPolyhedrons_ClippedToWall.Count(); --i >= 0; )
  1742. WallBrushPolyhedrons_ClippedToWall[i]->Release();
  1743. WallBrushPolyhedrons_ClippedToWall.RemoveAll();
  1744. }
  1745. STOPDEBUGTIMER( functionTimer );
  1746. DECREMENTTABSPACING();
  1747. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreatePolyhedrons() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1748. m_CreationChecklist.bPolyhedronsGenerated = true;
  1749. }
  1750. void CPortalSimulator::ClearPolyhedrons( void )
  1751. {
  1752. if( m_CreationChecklist.bPolyhedronsGenerated == false )
  1753. return;
  1754. CREATEDEBUGTIMER( functionTimer );
  1755. STARTDEBUGTIMER( functionTimer );
  1756. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearPolyhedrons() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1757. INCREMENTTABSPACING();
  1758. if( m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count() != 0 )
  1759. {
  1760. for( int i = m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.Count(); --i >= 0; )
  1761. m_InternalData.Simulation.Static.World.Brushes.Polyhedrons[i]->Release();
  1762. m_InternalData.Simulation.Static.World.Brushes.Polyhedrons.RemoveAll();
  1763. }
  1764. if( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() != 0 )
  1765. {
  1766. for( int i = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count(); --i >= 0; )
  1767. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons[i]->Release();
  1768. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.RemoveAll();
  1769. }
  1770. #ifdef _DEBUG
  1771. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1772. {
  1773. #ifndef CLIENT_DLL
  1774. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pPhysicsObject == NULL );
  1775. #endif
  1776. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide == NULL );
  1777. }
  1778. #endif
  1779. m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.RemoveAll();
  1780. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Count() != 0 )
  1781. {
  1782. for( int i = m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.Count(); --i >= 0; )
  1783. m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons[i]->Release();
  1784. m_InternalData.Simulation.Static.Wall.Local.Brushes.Polyhedrons.RemoveAll();
  1785. }
  1786. if( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() != 0 )
  1787. {
  1788. for( int i = m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count(); --i >= 0; )
  1789. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons[i]->Release();
  1790. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.RemoveAll();
  1791. }
  1792. STOPDEBUGTIMER( functionTimer );
  1793. DECREMENTTABSPACING();
  1794. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearPolyhedrons() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1795. m_CreationChecklist.bPolyhedronsGenerated = false;
  1796. }
  1797. void CPortalSimulator::DetachFromLinked( void )
  1798. {
  1799. if( m_pLinkedPortal == NULL )
  1800. return;
  1801. CREATEDEBUGTIMER( functionTimer );
  1802. STARTDEBUGTIMER( functionTimer );
  1803. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DetachFromLinked() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1804. INCREMENTTABSPACING();
  1805. //IMPORTANT: Physics objects must be destroyed before their associated collision data or a fairly cryptic crash will ensue
  1806. #ifndef CLIENT_DLL
  1807. ClearLinkedEntities();
  1808. ClearLinkedPhysics();
  1809. #endif
  1810. ClearLinkedCollision();
  1811. if( m_pLinkedPortal->m_bInCrossLinkedFunction == false )
  1812. {
  1813. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  1814. m_bInCrossLinkedFunction = true;
  1815. m_pLinkedPortal->DetachFromLinked();
  1816. m_bInCrossLinkedFunction = false;
  1817. }
  1818. m_pLinkedPortal = NULL;
  1819. STOPDEBUGTIMER( functionTimer );
  1820. DECREMENTTABSPACING();
  1821. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DetachFromLinked() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1822. }
  1823. void CPortalSimulator::SetPortalSimulatorCallbacks( CPortalSimulatorEventCallbacks *pCallbacks )
  1824. {
  1825. if( pCallbacks )
  1826. m_pCallbacks = pCallbacks;
  1827. else
  1828. m_pCallbacks = &s_DummyPortalSimulatorCallback; //always keep the pointer valid
  1829. }
  1830. void CPortalSimulator::SetVPhysicsSimulationEnabled( bool bEnabled )
  1831. {
  1832. AssertMsg( (m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_bSimulateVPhysics == m_bSimulateVPhysics), "Linked portals are in disagreement as to whether they would simulate VPhysics." );
  1833. if( bEnabled == m_bSimulateVPhysics )
  1834. return;
  1835. CREATEDEBUGTIMER( functionTimer );
  1836. STARTDEBUGTIMER( functionTimer );
  1837. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetVPhysicsSimulationEnabled() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1838. INCREMENTTABSPACING();
  1839. m_bSimulateVPhysics = bEnabled;
  1840. if( bEnabled )
  1841. {
  1842. //we took some local collision shortcuts when generating while physics simulation is off, regenerate
  1843. ClearLocalCollision();
  1844. ClearPolyhedrons();
  1845. CreatePolyhedrons();
  1846. CreateLocalCollision();
  1847. #ifndef CLIENT_DLL
  1848. CreateAllPhysics();
  1849. #endif
  1850. }
  1851. #ifndef CLIENT_DLL
  1852. else
  1853. {
  1854. ClearAllPhysics();
  1855. }
  1856. #endif
  1857. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  1858. {
  1859. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  1860. m_bInCrossLinkedFunction = true;
  1861. m_pLinkedPortal->SetVPhysicsSimulationEnabled( bEnabled );
  1862. m_bInCrossLinkedFunction = false;
  1863. }
  1864. STOPDEBUGTIMER( functionTimer );
  1865. DECREMENTTABSPACING();
  1866. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetVPhysicsSimulationEnabled() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1867. }
  1868. #ifndef CLIENT_DLL
  1869. void CPortalSimulator::PrePhysFrame( void )
  1870. {
  1871. int iPortalSimulators = s_PortalSimulators.Count();
  1872. if( iPortalSimulators != 0 )
  1873. {
  1874. CPortalSimulator **pAllSimulators = s_PortalSimulators.Base();
  1875. for( int i = 0; i != iPortalSimulators; ++i )
  1876. {
  1877. CPortalSimulator *pSimulator = pAllSimulators[i];
  1878. if( !pSimulator->IsReadyToSimulate() )
  1879. continue;
  1880. int iOwnedEntities = pSimulator->m_InternalData.Simulation.Dynamic.OwnedEntities.Count();
  1881. if( iOwnedEntities != 0 )
  1882. {
  1883. CBaseEntity **pOwnedEntities = pSimulator->m_InternalData.Simulation.Dynamic.OwnedEntities.Base();
  1884. for( int j = 0; j != iOwnedEntities; ++j )
  1885. {
  1886. CBaseEntity *pEntity = pOwnedEntities[j];
  1887. if( CPhysicsShadowClone::IsShadowClone( pEntity ) )
  1888. continue;
  1889. Assert( (pEntity != NULL) && (pEntity->IsMarkedForDeletion() == false) );
  1890. IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
  1891. if( (pPhysObject == NULL) || pPhysObject->IsAsleep() )
  1892. continue;
  1893. int iEntIndex = pEntity->entindex();
  1894. int iExistingFlags = pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex];
  1895. if( pSimulator->EntityIsInPortalHole( pEntity ) )
  1896. pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_IS_IN_PORTAL_HOLE;
  1897. else
  1898. pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_IS_IN_PORTAL_HOLE;
  1899. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] );
  1900. if( ((iExistingFlags ^ pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex]) & PSEF_IS_IN_PORTAL_HOLE) != 0 ) //value changed
  1901. {
  1902. pEntity->CollisionRulesChanged(); //entity moved into or out of the portal hole, need to either add or remove collision with transformed geometry
  1903. CPhysicsShadowCloneLL *pClones = CPhysicsShadowClone::GetClonesOfEntity( pEntity );
  1904. while( pClones )
  1905. {
  1906. pClones->pClone->CollisionRulesChanged();
  1907. pClones = pClones->pNext;
  1908. }
  1909. }
  1910. }
  1911. }
  1912. }
  1913. }
  1914. }
  1915. void CPortalSimulator::PostPhysFrame( void )
  1916. {
  1917. if ( g_bPlayerIsInSimulator )
  1918. {
  1919. CPortal_Player* pPlayer = dynamic_cast<CPortal_Player*>( UTIL_GetLocalPlayer() );
  1920. CProp_Portal* pTouchedPortal = pPlayer->m_hPortalEnvironment.Get();
  1921. CPortalSimulator* pSim = GetSimulatorThatOwnsEntity( pPlayer );
  1922. if ( pTouchedPortal && pSim && (pTouchedPortal->m_PortalSimulator.GetPortalSimulatorGUID() != pSim->GetPortalSimulatorGUID()) )
  1923. {
  1924. Warning ( "Player is simulated in a physics environment but isn't touching a portal! Can't teleport, but can fall through portal hole. Returning player to main environment.\n" );
  1925. ADD_DEBUG_HISTORY( HISTORY_PLAYER_DAMAGE, UTIL_VarArgs( "Player in PortalSimulator but not touching a portal, removing from sim at : %f\n", gpGlobals->curtime ) );
  1926. if ( pSim )
  1927. {
  1928. pSim->ReleaseOwnershipOfEntity( pPlayer, false );
  1929. }
  1930. }
  1931. }
  1932. }
  1933. #endif //#ifndef CLIENT_DLL
  1934. #ifndef CLIENT_DLL
  1935. int CPortalSimulator::GetMoveableOwnedEntities( CBaseEntity **pEntsOut, int iEntOutLimit )
  1936. {
  1937. int iOwnedEntCount = m_InternalData.Simulation.Dynamic.OwnedEntities.Count();
  1938. int iOutputCount = 0;
  1939. for( int i = 0; i != iOwnedEntCount; ++i )
  1940. {
  1941. CBaseEntity *pEnt = m_InternalData.Simulation.Dynamic.OwnedEntities[i];
  1942. Assert( pEnt != NULL );
  1943. if( CPhysicsShadowClone::IsShadowClone( pEnt ) )
  1944. continue;
  1945. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEnt ) )
  1946. continue;
  1947. if( pEnt->GetMoveType() == MOVETYPE_NONE )
  1948. continue;
  1949. pEntsOut[iOutputCount] = pEnt;
  1950. ++iOutputCount;
  1951. if( iOutputCount == iEntOutLimit )
  1952. break;
  1953. }
  1954. return iOutputCount;
  1955. }
  1956. CPortalSimulator *CPortalSimulator::GetSimulatorThatOwnsEntity( const CBaseEntity *pEntity )
  1957. {
  1958. #ifdef _DEBUG
  1959. int iEntIndex = pEntity->entindex();
  1960. CPortalSimulator *pOwningSimulatorCheck = NULL;
  1961. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  1962. {
  1963. if( s_PortalSimulators[i]->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY )
  1964. {
  1965. AssertMsg( pOwningSimulatorCheck == NULL, "More than one portal simulator found owning the same entity." );
  1966. pOwningSimulatorCheck = s_PortalSimulators[i];
  1967. }
  1968. }
  1969. AssertMsg( pOwningSimulatorCheck == s_OwnedEntityMap[iEntIndex], "Owned entity mapping out of sync with individual simulator ownership flags." );
  1970. #endif
  1971. return s_OwnedEntityMap[pEntity->entindex()];
  1972. }
  1973. CPortalSimulator *CPortalSimulator::GetSimulatorThatCreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType )
  1974. {
  1975. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  1976. {
  1977. if( s_PortalSimulators[i]->CreatedPhysicsObject( pObject, pOut_SourceType ) )
  1978. return s_PortalSimulators[i];
  1979. }
  1980. return NULL;
  1981. }
  1982. bool CPortalSimulator::CreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType ) const
  1983. {
  1984. if( (pObject == m_InternalData.Simulation.Static.World.Brushes.pPhysicsObject) || (pObject == m_InternalData.Simulation.Static.Wall.Local.Brushes.pPhysicsObject) )
  1985. {
  1986. if( pOut_SourceType )
  1987. *pOut_SourceType = PSPOST_LOCAL_BRUSHES;
  1988. return true;
  1989. }
  1990. if( pObject == m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject )
  1991. {
  1992. if( pOut_SourceType )
  1993. *pOut_SourceType = PSPOST_REMOTE_BRUSHES;
  1994. return true;
  1995. }
  1996. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1997. {
  1998. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pPhysicsObject == pObject )
  1999. {
  2000. if( pOut_SourceType )
  2001. *pOut_SourceType = PSPOST_LOCAL_STATICPROPS;
  2002. return true;
  2003. }
  2004. }
  2005. for( int i = m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count(); --i >= 0; )
  2006. {
  2007. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects[i] == pObject )
  2008. {
  2009. if( pOut_SourceType )
  2010. *pOut_SourceType = PSPOST_REMOTE_STATICPROPS;
  2011. return true;
  2012. }
  2013. }
  2014. if( pObject == m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject )
  2015. {
  2016. if( pOut_SourceType )
  2017. *pOut_SourceType = PSPOST_HOLYWALL_TUBE;
  2018. return true;
  2019. }
  2020. return false;
  2021. }
  2022. #endif //#ifndef CLIENT_DLL
  2023. static void ConvertBrushListToClippedPolyhedronList( const int *pBrushes, int iBrushCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList )
  2024. {
  2025. if( pPolyhedronList == NULL )
  2026. return;
  2027. if( (pBrushes == NULL) || (iBrushCount == 0) )
  2028. return;
  2029. for( int i = 0; i != iBrushCount; ++i )
  2030. {
  2031. CPolyhedron *pPolyhedron = ClipPolyhedron( g_StaticCollisionPolyhedronCache.GetBrushPolyhedron( pBrushes[i] ), pOutwardFacingClipPlanes, iClipPlaneCount, fClipEpsilon );
  2032. if( pPolyhedron )
  2033. pPolyhedronList->AddToTail( pPolyhedron );
  2034. }
  2035. }
  2036. static void ClipPolyhedrons( CPolyhedron * const *pExistingPolyhedrons, int iPolyhedronCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList )
  2037. {
  2038. if( pPolyhedronList == NULL )
  2039. return;
  2040. if( (pExistingPolyhedrons == NULL) || (iPolyhedronCount == 0) )
  2041. return;
  2042. for( int i = 0; i != iPolyhedronCount; ++i )
  2043. {
  2044. CPolyhedron *pPolyhedron = ClipPolyhedron( pExistingPolyhedrons[i], pOutwardFacingClipPlanes, iClipPlaneCount, fClipEpsilon );
  2045. if( pPolyhedron )
  2046. pPolyhedronList->AddToTail( pPolyhedron );
  2047. }
  2048. }
  2049. static CPhysCollide *ConvertPolyhedronsToCollideable( CPolyhedron **pPolyhedrons, int iPolyhedronCount )
  2050. {
  2051. if( (pPolyhedrons == NULL) || (iPolyhedronCount == 0 ) )
  2052. return NULL;
  2053. CREATEDEBUGTIMER( functionTimer );
  2054. STARTDEBUGTIMER( functionTimer );
  2055. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvertPolyhedronsToCollideable() START\n", s_iPortalSimulatorGUID, TABSPACING ); );
  2056. INCREMENTTABSPACING();
  2057. CPhysConvex **pConvexes = (CPhysConvex **)stackalloc( iPolyhedronCount * sizeof( CPhysConvex * ) );
  2058. int iConvexCount = 0;
  2059. CREATEDEBUGTIMER( convexTimer );
  2060. STARTDEBUGTIMER( convexTimer );
  2061. for( int i = 0; i != iPolyhedronCount; ++i )
  2062. {
  2063. pConvexes[iConvexCount] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedrons[i] );
  2064. Assert( pConvexes[iConvexCount] != NULL );
  2065. if( pConvexes[iConvexCount] )
  2066. ++iConvexCount;
  2067. }
  2068. STOPDEBUGTIMER( convexTimer );
  2069. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvex Generation:%fms\n", s_iPortalSimulatorGUID, TABSPACING, convexTimer.GetDuration().GetMillisecondsF() ); );
  2070. CPhysCollide *pReturn;
  2071. if( iConvexCount != 0 )
  2072. {
  2073. CREATEDEBUGTIMER( collideTimer );
  2074. STARTDEBUGTIMER( collideTimer );
  2075. pReturn = physcollision->ConvertConvexToCollide( pConvexes, iConvexCount );
  2076. STOPDEBUGTIMER( collideTimer );
  2077. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCollideable Generation:%fms\n", s_iPortalSimulatorGUID, TABSPACING, collideTimer.GetDuration().GetMillisecondsF() ); );
  2078. }
  2079. else
  2080. {
  2081. pReturn = NULL;
  2082. }
  2083. STOPDEBUGTIMER( functionTimer );
  2084. DECREMENTTABSPACING();
  2085. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvertPolyhedronsToCollideable() FINISH: %fms\n", s_iPortalSimulatorGUID, TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2086. return pReturn;
  2087. }
  2088. static inline CPolyhedron *TransformAndClipSinglePolyhedron( CPolyhedron *pExistingPolyhedron, const VMatrix &Transform, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fCutEpsilon, bool bUseTempMemory )
  2089. {
  2090. Vector *pTempPointArray = (Vector *)stackalloc( sizeof( Vector ) * pExistingPolyhedron->iVertexCount );
  2091. Polyhedron_IndexedPolygon_t *pTempPolygonArray = (Polyhedron_IndexedPolygon_t *)stackalloc( sizeof( Polyhedron_IndexedPolygon_t ) * pExistingPolyhedron->iPolygonCount );
  2092. Polyhedron_IndexedPolygon_t *pOriginalPolygons = pExistingPolyhedron->pPolygons;
  2093. pExistingPolyhedron->pPolygons = pTempPolygonArray;
  2094. Vector *pOriginalPoints = pExistingPolyhedron->pVertices;
  2095. pExistingPolyhedron->pVertices = pTempPointArray;
  2096. for( int j = 0; j != pExistingPolyhedron->iPolygonCount; ++j )
  2097. {
  2098. pTempPolygonArray[j].iFirstIndex = pOriginalPolygons[j].iFirstIndex;
  2099. pTempPolygonArray[j].iIndexCount = pOriginalPolygons[j].iIndexCount;
  2100. pTempPolygonArray[j].polyNormal = Transform.ApplyRotation( pOriginalPolygons[j].polyNormal );
  2101. }
  2102. for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j )
  2103. {
  2104. pTempPointArray[j] = Transform * pOriginalPoints[j];
  2105. }
  2106. CPolyhedron *pNewPolyhedron = ClipPolyhedron( pExistingPolyhedron, pOutwardFacingClipPlanes, iClipPlaneCount, fCutEpsilon, bUseTempMemory ); //copy the polyhedron
  2107. //restore the original polyhedron to its former self
  2108. pExistingPolyhedron->pVertices = pOriginalPoints;
  2109. pExistingPolyhedron->pPolygons = pOriginalPolygons;
  2110. return pNewPolyhedron;
  2111. }
  2112. static int GetEntityPhysicsObjects( IPhysicsEnvironment *pEnvironment, CBaseEntity *pEntity, IPhysicsObject **pRetList, int iRetListArraySize )
  2113. {
  2114. int iCount, iRetCount = 0;
  2115. const IPhysicsObject **pList = pEnvironment->GetObjectList( &iCount );
  2116. if( iCount > iRetListArraySize )
  2117. iCount = iRetListArraySize;
  2118. for ( int i = 0; i < iCount; ++i )
  2119. {
  2120. CBaseEntity *pEnvEntity = reinterpret_cast<CBaseEntity *>(pList[i]->GetGameData());
  2121. if ( pEntity == pEnvEntity )
  2122. {
  2123. pRetList[iRetCount] = (IPhysicsObject *)(pList[i]);
  2124. ++iRetCount;
  2125. }
  2126. }
  2127. return iRetCount;
  2128. }
  2129. #ifndef CLIENT_DLL
  2130. //Move all entities back to the main environment for removal, and make sure the main environment is in control during the UTIL_Remove process
  2131. struct UTIL_Remove_PhysicsStack_t
  2132. {
  2133. IPhysicsEnvironment *pPhysicsEnvironment;
  2134. CEntityList *pShadowList;
  2135. };
  2136. static CUtlVector<UTIL_Remove_PhysicsStack_t> s_UTIL_Remove_PhysicsStack;
  2137. void CPortalSimulator::Pre_UTIL_Remove( CBaseEntity *pEntity )
  2138. {
  2139. int index = s_UTIL_Remove_PhysicsStack.AddToTail();
  2140. s_UTIL_Remove_PhysicsStack[index].pPhysicsEnvironment = physenv;
  2141. s_UTIL_Remove_PhysicsStack[index].pShadowList = g_pShadowEntities;
  2142. int iEntIndex = pEntity->entindex();
  2143. //NDebugOverlay::EntityBounds( pEntity, 0, 0, 0, 50, 5.0f );
  2144. if( (CPhysicsShadowClone::IsShadowClone( pEntity ) == false) &&
  2145. (CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) == false) )
  2146. {
  2147. CPortalSimulator *pOwningSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity );
  2148. if( pOwningSimulator )
  2149. {
  2150. pOwningSimulator->ReleasePhysicsOwnership( pEntity, false );
  2151. pOwningSimulator->ReleaseOwnershipOfEntity( pEntity );
  2152. }
  2153. //might be cloned from main to a few environments
  2154. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  2155. s_PortalSimulators[i]->StopCloningEntity( pEntity );
  2156. }
  2157. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  2158. {
  2159. s_PortalSimulators[i]->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] = 0;
  2160. }
  2161. physenv = physenv_main;
  2162. g_pShadowEntities = g_pShadowEntities_Main;
  2163. }
  2164. void CPortalSimulator::Post_UTIL_Remove( CBaseEntity *pEntity )
  2165. {
  2166. int index = s_UTIL_Remove_PhysicsStack.Count() - 1;
  2167. Assert( index >= 0 );
  2168. UTIL_Remove_PhysicsStack_t &PhysicsStackEntry = s_UTIL_Remove_PhysicsStack[index];
  2169. physenv = PhysicsStackEntry.pPhysicsEnvironment;
  2170. g_pShadowEntities = PhysicsStackEntry.pShadowList;
  2171. s_UTIL_Remove_PhysicsStack.FastRemove(index);
  2172. #ifdef _DEBUG
  2173. for( int i = CPhysicsShadowClone::g_ShadowCloneList.Count(); --i >= 0; )
  2174. {
  2175. Assert( CPhysicsShadowClone::g_ShadowCloneList[i]->GetClonedEntity() != pEntity ); //shouldn't be any clones of this object anymore
  2176. }
  2177. #endif
  2178. }
  2179. void UpdateShadowClonesPortalSimulationFlags( const CBaseEntity *pSourceEntity, unsigned int iFlags, int iSourceFlags )
  2180. {
  2181. unsigned int iOrFlags = iSourceFlags & iFlags;
  2182. CPhysicsShadowCloneLL *pClones = CPhysicsShadowClone::GetClonesOfEntity( pSourceEntity );
  2183. while( pClones )
  2184. {
  2185. CPhysicsShadowClone *pClone = pClones->pClone;
  2186. CPortalSimulator *pCloneSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pClone );
  2187. unsigned int *pFlags = (unsigned int *)&pCloneSimulator->m_DataAccess.Simulation.Dynamic.EntFlags[pClone->entindex()];
  2188. *pFlags &= ~iFlags;
  2189. *pFlags |= iOrFlags;
  2190. Assert( ((iSourceFlags ^ *pFlags) & iFlags) == 0 );
  2191. pClones = pClones->pNext;
  2192. }
  2193. }
  2194. #endif
  2195. #ifndef CLIENT_DLL
  2196. class CPS_AutoGameSys_EntityListener : public CAutoGameSystem, public IEntityListener
  2197. #else
  2198. class CPS_AutoGameSys_EntityListener : public CAutoGameSystem
  2199. #endif
  2200. {
  2201. public:
  2202. virtual void LevelInitPreEntity( void )
  2203. {
  2204. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  2205. s_PortalSimulators[i]->ClearEverything();
  2206. }
  2207. virtual void LevelShutdownPreEntity( void )
  2208. {
  2209. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  2210. s_PortalSimulators[i]->ClearEverything();
  2211. }
  2212. #ifndef CLIENT_DLL
  2213. virtual bool Init( void )
  2214. {
  2215. gEntList.AddListenerEntity( this );
  2216. return true;
  2217. }
  2218. //virtual void OnEntityCreated( CBaseEntity *pEntity ) {}
  2219. virtual void OnEntitySpawned( CBaseEntity *pEntity )
  2220. {
  2221. }
  2222. virtual void OnEntityDeleted( CBaseEntity *pEntity )
  2223. {
  2224. CPortalSimulator *pSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity );
  2225. if( pSimulator )
  2226. {
  2227. pSimulator->ReleasePhysicsOwnership( pEntity, false );
  2228. pSimulator->ReleaseOwnershipOfEntity( pEntity );
  2229. }
  2230. Assert( CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  2231. }
  2232. #endif //#ifndef CLIENT_DLL
  2233. };
  2234. static CPS_AutoGameSys_EntityListener s_CPS_AGS_EL_Singleton;
  2235. #ifndef CLIENT_DLL
  2236. LINK_ENTITY_TO_CLASS( portalsimulator_collisionentity, CPSCollisionEntity );
  2237. static bool s_PortalSimulatorCollisionEntities[MAX_EDICTS] = { false };
  2238. CPSCollisionEntity::CPSCollisionEntity( void )
  2239. {
  2240. m_pOwningSimulator = NULL;
  2241. }
  2242. CPSCollisionEntity::~CPSCollisionEntity( void )
  2243. {
  2244. if( m_pOwningSimulator )
  2245. {
  2246. m_pOwningSimulator->m_InternalData.Simulation.Dynamic.EntFlags[entindex()] &= ~PSEF_OWNS_PHYSICS;
  2247. m_pOwningSimulator->MarkAsReleased( this );
  2248. m_pOwningSimulator->m_InternalData.Simulation.pCollisionEntity = NULL;
  2249. m_pOwningSimulator = NULL;
  2250. }
  2251. s_PortalSimulatorCollisionEntities[entindex()] = false;
  2252. }
  2253. void CPSCollisionEntity::UpdateOnRemove( void )
  2254. {
  2255. VPhysicsSetObject( NULL );
  2256. if( m_pOwningSimulator )
  2257. {
  2258. m_pOwningSimulator->m_InternalData.Simulation.Dynamic.EntFlags[entindex()] &= ~PSEF_OWNS_PHYSICS;
  2259. m_pOwningSimulator->MarkAsReleased( this );
  2260. m_pOwningSimulator->m_InternalData.Simulation.pCollisionEntity = NULL;
  2261. m_pOwningSimulator = NULL;
  2262. }
  2263. s_PortalSimulatorCollisionEntities[entindex()] = false;
  2264. BaseClass::UpdateOnRemove();
  2265. }
  2266. void CPSCollisionEntity::Spawn( void )
  2267. {
  2268. BaseClass::Spawn();
  2269. SetSolid( SOLID_CUSTOM );
  2270. SetMoveType( MOVETYPE_NONE );
  2271. SetCollisionGroup( COLLISION_GROUP_NONE );
  2272. s_PortalSimulatorCollisionEntities[entindex()] = true;
  2273. VPhysicsSetObject( NULL );
  2274. AddFlag( FL_WORLDBRUSH );
  2275. AddEffects( EF_NODRAW | EF_NOSHADOW | EF_NORECEIVESHADOW );
  2276. IncrementInterpolationFrame();
  2277. }
  2278. void CPSCollisionEntity::Activate( void )
  2279. {
  2280. BaseClass::Activate();
  2281. CollisionRulesChanged();
  2282. }
  2283. int CPSCollisionEntity::ObjectCaps( void )
  2284. {
  2285. return ((BaseClass::ObjectCaps() | FCAP_DONT_SAVE) & ~(FCAP_FORCE_TRANSITION | FCAP_ACROSS_TRANSITION | FCAP_MUST_SPAWN | FCAP_SAVE_NON_NETWORKABLE));
  2286. }
  2287. bool CPSCollisionEntity::ShouldCollide( int collisionGroup, int contentsMask ) const
  2288. {
  2289. return GetWorldEntity()->ShouldCollide( collisionGroup, contentsMask );
  2290. }
  2291. IPhysicsObject *CPSCollisionEntity::VPhysicsGetObject( void )
  2292. {
  2293. if( m_pOwningSimulator == NULL )
  2294. return NULL;
  2295. if( m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Brushes.pPhysicsObject != NULL )
  2296. return m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Brushes.pPhysicsObject;
  2297. else if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pPhysicsObject != NULL )
  2298. return m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pPhysicsObject;
  2299. else if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Tube.pPhysicsObject != NULL )
  2300. return m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pPhysicsObject;
  2301. else if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject != NULL )
  2302. return m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject;
  2303. else
  2304. return NULL;
  2305. }
  2306. int CPSCollisionEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  2307. {
  2308. if( m_pOwningSimulator == NULL )
  2309. return 0;
  2310. if( (pList == NULL) || (listMax == 0) )
  2311. return 0;
  2312. int iRetVal = 0;
  2313. if( m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Brushes.pPhysicsObject != NULL )
  2314. {
  2315. pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.World.Brushes.pPhysicsObject;
  2316. ++iRetVal;
  2317. if( iRetVal == listMax )
  2318. return iRetVal;
  2319. }
  2320. if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pPhysicsObject != NULL )
  2321. {
  2322. pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pPhysicsObject;
  2323. ++iRetVal;
  2324. if( iRetVal == listMax )
  2325. return iRetVal;
  2326. }
  2327. if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Tube.pPhysicsObject != NULL )
  2328. {
  2329. pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.Local.Tube.pPhysicsObject;
  2330. ++iRetVal;
  2331. if( iRetVal == listMax )
  2332. return iRetVal;
  2333. }
  2334. if( m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject != NULL )
  2335. {
  2336. pList[iRetVal] = m_pOwningSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObject;
  2337. ++iRetVal;
  2338. if( iRetVal == listMax )
  2339. return iRetVal;
  2340. }
  2341. return iRetVal;
  2342. }
  2343. bool CPSCollisionEntity::IsPortalSimulatorCollisionEntity( const CBaseEntity *pEntity )
  2344. {
  2345. return s_PortalSimulatorCollisionEntities[pEntity->entindex()];
  2346. }
  2347. #endif //#ifndef CLIENT_DLL
  2348. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  2349. #include "filesystem.h"
  2350. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename );
  2351. static void PortalSimulatorDumps_DumpPlanesToGlView( float *pPlanes, int iPlaneCount, const char *pszFileName );
  2352. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName );
  2353. static void PortalSimulatorDumps_DumpOBBoxToGlView( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, float fRed, float fGreen, float fBlue, const char *pszFileName );
  2354. void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char *szFileName )
  2355. {
  2356. CREATEDEBUGTIMER( collisionDumpTimer );
  2357. STARTDEBUGTIMER( collisionDumpTimer );
  2358. //color coding scheme, static prop collision is brighter than brush collision. Remote world stuff transformed to the local wall is darker than completely local stuff
  2359. #define PSDAC_INTENSITY_LOCALBRUSH 0.25f
  2360. #define PSDAC_INTENSITY_LOCALPROP 1.0f
  2361. #define PSDAC_INTENSITY_REMOTEBRUSH 0.125f
  2362. #define PSDAC_INTENSITY_REMOTEPROP 0.5f
  2363. if( pPortalSimulator->m_DataAccess.Simulation.Static.World.Brushes.pCollideable )
  2364. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.World.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  2365. if( pPortalSimulator->m_DataAccess.Simulation.Static.World.StaticProps.bCollisionExists )
  2366. {
  2367. for( int i = pPortalSimulator->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2368. {
  2369. Assert( pPortalSimulator->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide );
  2370. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALPROP, szFileName );
  2371. }
  2372. }
  2373. if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable )
  2374. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  2375. if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Tube.pCollideable )
  2376. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.Local.Tube.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  2377. //if( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable )
  2378. // PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_REMOTEBRUSH, szFileName );
  2379. CPortalSimulator *pLinkedPortal = pPortalSimulator->GetLinkedPortalSimulator();
  2380. if( pLinkedPortal )
  2381. {
  2382. if( pLinkedPortal->m_DataAccess.Simulation.Static.World.Brushes.pCollideable )
  2383. PortalSimulatorDumps_DumpCollideToGlView( pLinkedPortal->m_DataAccess.Simulation.Static.World.Brushes.pCollideable, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.ptOriginTransform, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.qAngleTransform, PSDAC_INTENSITY_REMOTEBRUSH, szFileName );
  2384. //for( int i = pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.Collideables.Count(); --i >= 0; )
  2385. // PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->m_DataAccess.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.Collideables[i], vec3_origin, vec3_angle, PSDAC_INTENSITY_REMOTEPROP, szFileName );
  2386. if( pLinkedPortal->m_DataAccess.Simulation.Static.World.StaticProps.bCollisionExists )
  2387. {
  2388. for( int i = pLinkedPortal->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2389. {
  2390. Assert( pLinkedPortal->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide );
  2391. PortalSimulatorDumps_DumpCollideToGlView( pLinkedPortal->m_DataAccess.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.ptOriginTransform, pPortalSimulator->m_DataAccess.Placement.ptaap_LinkedToThis.qAngleTransform, PSDAC_INTENSITY_REMOTEPROP, szFileName );
  2392. }
  2393. }
  2394. }
  2395. STOPDEBUGTIMER( collisionDumpTimer );
  2396. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DumpActiveCollision() Spent %fms generating a collision dump\n", pPortalSimulator->GetPortalSimulatorGUID(), TABSPACING, collisionDumpTimer.GetDuration().GetMillisecondsF() ); );
  2397. }
  2398. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename )
  2399. {
  2400. if ( !pCollide )
  2401. return;
  2402. printf("Writing %s...\n", pFilename );
  2403. Vector *outVerts;
  2404. int vertCount = physcollision->CreateDebugMesh( pCollide, &outVerts );
  2405. FileHandle_t fp = filesystem->Open( pFilename, "ab" );
  2406. int triCount = vertCount / 3;
  2407. int vert = 0;
  2408. VMatrix tmp = SetupMatrixOrgAngles( origin, angles );
  2409. int i;
  2410. for ( i = 0; i < vertCount; i++ )
  2411. {
  2412. outVerts[i] = tmp.VMul4x3( outVerts[i] );
  2413. }
  2414. for ( i = 0; i < triCount; i++ )
  2415. {
  2416. filesystem->FPrintf( fp, "3\n" );
  2417. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f 0 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  2418. vert++;
  2419. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f 0 %.2f 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  2420. vert++;
  2421. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f 0 0 %.2f\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  2422. vert++;
  2423. }
  2424. filesystem->Close( fp );
  2425. physcollision->DestroyDebugMesh( vertCount, outVerts );
  2426. }
  2427. static void PortalSimulatorDumps_DumpPlanesToGlView( float *pPlanes, int iPlaneCount, const char *pszFileName )
  2428. {
  2429. FileHandle_t fp = filesystem->Open( pszFileName, "wb" );
  2430. for( int i = 0; i < iPlaneCount; ++i )
  2431. {
  2432. Vector vPlaneVerts[4];
  2433. float fRed, fGreen, fBlue;
  2434. fRed = rand()/32768.0f;
  2435. fGreen = rand()/32768.0f;
  2436. fBlue = rand()/32768.0f;
  2437. PolyFromPlane( vPlaneVerts, *(Vector *)(pPlanes + (i*4)), pPlanes[(i*4) + 3], 1000.0f );
  2438. filesystem->FPrintf( fp, "4\n" );
  2439. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fRed, fGreen, fBlue );
  2440. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fRed, fGreen, fBlue );
  2441. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fRed, fGreen, fBlue );
  2442. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fRed, fGreen, fBlue );
  2443. }
  2444. filesystem->Close( fp );
  2445. }
  2446. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName )
  2447. {
  2448. FileHandle_t fp = filesystem->Open( pszFileName, "ab" );
  2449. //x min side
  2450. filesystem->FPrintf( fp, "4\n" );
  2451. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2452. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2453. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2454. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2455. filesystem->FPrintf( fp, "4\n" );
  2456. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2457. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2458. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2459. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2460. //x max side
  2461. filesystem->FPrintf( fp, "4\n" );
  2462. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2463. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2464. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2465. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2466. filesystem->FPrintf( fp, "4\n" );
  2467. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2468. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2469. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2470. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2471. //y min side
  2472. filesystem->FPrintf( fp, "4\n" );
  2473. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2474. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2475. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2476. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2477. filesystem->FPrintf( fp, "4\n" );
  2478. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2479. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2480. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2481. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2482. //y max side
  2483. filesystem->FPrintf( fp, "4\n" );
  2484. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2485. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2486. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2487. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2488. filesystem->FPrintf( fp, "4\n" );
  2489. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2490. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2491. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2492. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2493. //z min side
  2494. filesystem->FPrintf( fp, "4\n" );
  2495. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2496. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2497. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2498. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2499. filesystem->FPrintf( fp, "4\n" );
  2500. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2501. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2502. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  2503. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  2504. //z max side
  2505. filesystem->FPrintf( fp, "4\n" );
  2506. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2507. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2508. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2509. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2510. filesystem->FPrintf( fp, "4\n" );
  2511. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2512. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2513. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  2514. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  2515. filesystem->Close( fp );
  2516. }
  2517. static void PortalSimulatorDumps_DumpOBBoxToGlView( const Vector &ptOrigin, const Vector &vExtent1, const Vector &vExtent2, const Vector &vExtent3, float fRed, float fGreen, float fBlue, const char *pszFileName )
  2518. {
  2519. FileHandle_t fp = filesystem->Open( pszFileName, "ab" );
  2520. Vector ptExtents[8];
  2521. int counter;
  2522. for( counter = 0; counter != 8; ++counter )
  2523. {
  2524. ptExtents[counter] = ptOrigin;
  2525. if( counter & (1<<0) ) ptExtents[counter] += vExtent1;
  2526. if( counter & (1<<1) ) ptExtents[counter] += vExtent2;
  2527. if( counter & (1<<2) ) ptExtents[counter] += vExtent3;
  2528. }
  2529. //x min side
  2530. filesystem->FPrintf( fp, "4\n" );
  2531. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2532. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2533. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2534. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2535. filesystem->FPrintf( fp, "4\n" );
  2536. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2537. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2538. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2539. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2540. //x max side
  2541. filesystem->FPrintf( fp, "4\n" );
  2542. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2543. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2544. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2545. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2546. filesystem->FPrintf( fp, "4\n" );
  2547. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2548. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2549. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2550. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2551. //y min side
  2552. filesystem->FPrintf( fp, "4\n" );
  2553. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2554. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2555. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2556. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2557. filesystem->FPrintf( fp, "4\n" );
  2558. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2559. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2560. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2561. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2562. //y max side
  2563. filesystem->FPrintf( fp, "4\n" );
  2564. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2565. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2566. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2567. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2568. filesystem->FPrintf( fp, "4\n" );
  2569. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2570. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2571. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2572. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2573. //z min side
  2574. filesystem->FPrintf( fp, "4\n" );
  2575. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2576. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2577. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2578. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2579. filesystem->FPrintf( fp, "4\n" );
  2580. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[1].x, ptExtents[1].y, ptExtents[1].z, fRed, fGreen, fBlue );
  2581. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[3].x, ptExtents[3].y, ptExtents[3].z, fRed, fGreen, fBlue );
  2582. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[2].x, ptExtents[2].y, ptExtents[2].z, fRed, fGreen, fBlue );
  2583. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[0].x, ptExtents[0].y, ptExtents[0].z, fRed, fGreen, fBlue );
  2584. //z max side
  2585. filesystem->FPrintf( fp, "4\n" );
  2586. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2587. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2588. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2589. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2590. filesystem->FPrintf( fp, "4\n" );
  2591. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[5].x, ptExtents[5].y, ptExtents[5].z, fRed, fGreen, fBlue );
  2592. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[7].x, ptExtents[7].y, ptExtents[7].z, fRed, fGreen, fBlue );
  2593. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[6].x, ptExtents[6].y, ptExtents[6].z, fRed, fGreen, fBlue );
  2594. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", ptExtents[4].x, ptExtents[4].y, ptExtents[4].z, fRed, fGreen, fBlue );
  2595. filesystem->Close( fp );
  2596. }
  2597. #endif