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

5298 lines
224 KiB

  1. //========= Copyright (c) 1996-2006, 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. #include "vphysics/virtualmesh.h"
  18. #ifndef CLIENT_DLL
  19. #include "world.h"
  20. #include "portal_player.h" //TODO: Move any portal mod specific code to callback functions or something
  21. #include "physicsshadowclone.h"
  22. #include "portal/weapon_physcannon.h"
  23. #include "player_pickup.h"
  24. #include "isaverestore.h"
  25. #include "hierarchy.h"
  26. #include "env_debughistory.h"
  27. #else
  28. #include "c_world.h"
  29. #endif
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. #if defined( CLIENT_DLL )
  33. #define s_szDLLName "client"
  34. #else
  35. #define s_szDLLName "server"
  36. #endif
  37. CCallQueue *GetPortalCallQueue();
  38. extern IPhysicsConstraintEvent *g_pConstraintEvents;
  39. //#define DEBUG_PORTAL_SIMULATION_CREATION_TIMES //define to output creation timings to developer 2
  40. #define DEBUG_PORTAL_COLLISION_ENVIRONMENTS //define this to allow for glview collision dumps of portal simulators
  41. #define VPHYSICS_SHRINK (0.5f) //HACK: assume VBSP uses this number until we have time to encode it in the map per model
  42. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS ) || defined( DEBUG_PORTAL_SIMULATION_CREATION_TIMES )
  43. # if !defined( PORTAL_SIMULATORS_EMBED_GUID )
  44. # pragma message( __FILE__ "(" __LINE__AS_STRING ") : error custom: Portal simulators require a GUID to debug, enable the GUID in PortalSimulation.h ." )
  45. # endif
  46. #endif
  47. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS )
  48. void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char *szFileName ); //appends to the existing file if it exists
  49. #endif
  50. #define PORTAL_WALL_TUBE_DEPTH (1.0f) //(1.0f/128.0f)
  51. #define PORTAL_WALL_TUBE_OFFSET (0.01f) //(1.0f/128.0f)
  52. #define PORTAL_WALL_MIN_THICKNESS (0.1f) //(1.0f/16.0f)
  53. #define PORTAL_POLYHEDRON_CUT_EPSILON (1.0f/1024.0f) //(1.0f/128.0f)
  54. #define PORTAL_WORLDCLIP_EPSILON (1.0f/1024.0f) //(1.0f/256.0f)
  55. #define PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT (1.0f/16.0f) //separating the world collision from wall collision by a small amount gets rid of extremely thin erroneous collision at the separating plane
  56. #define PORTAL_HOLE_HALF_HEIGHT_MOD (0.1f)
  57. #define PORTAL_HOLE_HALF_WIDTH_MOD (0.1f)
  58. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  59. 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
  60. static ConVar sv_dump_portalsimulator_holeshapes( "sv_dump_portalsimulator_holeshapes", "0", FCVAR_REPLICATED );
  61. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename );
  62. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName );
  63. #endif
  64. #ifdef DEBUG_PORTAL_SIMULATION_CREATION_TIMES
  65. #define STARTDEBUGTIMER(x) { x.Start(); }
  66. #define STOPDEBUGTIMER(x) { x.End(); }
  67. #define DEBUGTIMERONLY(x) x
  68. #define CREATEDEBUGTIMER(x) CFastTimer x;
  69. 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" };
  70. static int s_iTabSpacingIndex = 0;
  71. static int s_iPortalSimulatorGUID = 0; //used in standalone function that have no idea what a portal simulator is
  72. #define INCREMENTTABSPACING() ++s_iTabSpacingIndex;
  73. #define DECREMENTTABSPACING() --s_iTabSpacingIndex;
  74. #define TABSPACING (s_szTabSpacing[s_iTabSpacingIndex])
  75. #else
  76. #define STARTDEBUGTIMER(x)
  77. #define STOPDEBUGTIMER(x)
  78. #define DEBUGTIMERONLY(x)
  79. #define CREATEDEBUGTIMER(x)
  80. #define INCREMENTTABSPACING()
  81. #define DECREMENTTABSPACING()
  82. #define TABSPACING
  83. #endif
  84. static void ConvertBrushListToClippedPolyhedronList( const uint32 *pBrushes, int iBrushCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList );
  85. static void ClipPolyhedrons( CPolyhedron * const *pExistingPolyhedrons, int iPolyhedronCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList );
  86. static inline CPolyhedron *TransformAndClipSinglePolyhedron( CPolyhedron *pExistingPolyhedron, const VMatrix &Transform, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fCutEpsilon, bool bUseTempMemory );
  87. static int GetEntityPhysicsObjects( IPhysicsEnvironment *pEnvironment, CBaseEntity *pEntity, IPhysicsObject **pRetList, int iRetListArraySize );
  88. static CPhysCollide *ConvertPolyhedronsToCollideable( CPolyhedron **pPolyhedrons, int iPolyhedronCount );
  89. static void CarveWallBrushes_Sub( float *fPlanes, CUtlVector<CPolyhedron *> &WallBrushPolyhedrons_ClippedToWall, PS_InternalData_t &InternalData, CUtlVector<CPolyhedron *> &OutputPolyhedrons, float fFarRightPlaneDistance, float fFarLeftPlaneDistance, const Vector &vLeft, const Vector &vDown );
  90. #ifndef CLIENT_DLL
  91. static void UpdateShadowClonesPortalSimulationFlags( const CBaseEntity *pSourceEntity, unsigned int iFlags, int iSourceFlags );
  92. #endif
  93. static CUtlVector<CPortalSimulator *> s_PortalSimulators;
  94. CUtlVector<CPortalSimulator *> const &g_PortalSimulators = s_PortalSimulators;
  95. static CPortalSimulator *s_OwnedEntityMap[MAX_EDICTS] = { NULL };
  96. static CPortalSimulatorEventCallbacks s_DummyPortalSimulatorCallback;
  97. const char *PS_SD_Static_World_StaticProps_ClippedProp_t::szTraceSurfaceName = "**studio**";
  98. const int PS_SD_Static_World_StaticProps_ClippedProp_t::iTraceSurfaceFlags = 0;
  99. CBaseEntity *PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = NULL;
  100. ConVar portal_clone_displacements ( "portal_clone_displacements", "0", FCVAR_REPLICATED | FCVAR_CHEAT );
  101. ConVar portal_environment_radius( "portal_environment_radius", "75", FCVAR_REPLICATED | FCVAR_CHEAT );
  102. ConVar portal_ghosts_scale( "portal_ghosts_scale", "1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Scale the bounds of objects ghosted in portal environments for the purposes of hit testing." );
  103. ConVar portal_ghost_force_hitbox("portal_ghost_force_hitbox", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "(1 = Legacy behavior) Force potentially ghosted renderables to use their hitboxes to test against portal holes instead of collision AABBs" );
  104. ConVar portal_ghost_show_bbox("portal_ghost_show_bbox", "0", FCVAR_REPLICATED | FCVAR_CHEAT, "Render AABBs around the bounding box used for ghost renderable bounds checking (either hitbox or collision AABB)" );
  105. #if defined( GAME_DLL )
  106. ConVar portal_carve_vphysics_clips( "portal_carve_vphysics_clips", "1" );
  107. class CFunc_VPhysics_Clip_Watcher : public CAutoGameSystem
  108. {
  109. public:
  110. CFunc_VPhysics_Clip_Watcher( void )
  111. {
  112. m_bHaveCached = false;
  113. }
  114. virtual void LevelInitPostEntity()
  115. {
  116. Cache();
  117. }
  118. virtual void LevelShutdownPostEntity()
  119. {
  120. m_VPhysicsClipEntities.RemoveAll();
  121. m_bHaveCached = false;
  122. }
  123. void Cache( void )
  124. {
  125. if( m_bHaveCached )
  126. return;
  127. CBaseEntity *pIterateEntities = NULL;
  128. while( (pIterateEntities = gEntList.FindEntityByClassname( pIterateEntities, "func_clip_vphysics" )) != NULL )
  129. {
  130. CCollisionProperty *pProp = pIterateEntities->CollisionProp();
  131. VPhysicsClipEntry_t tempEntry;
  132. tempEntry.hEnt = pIterateEntities;
  133. pProp->WorldSpaceAABB( &tempEntry.vAABBMins, &tempEntry.vAABBMaxs );
  134. m_VPhysicsClipEntities.AddToTail( tempEntry );
  135. }
  136. m_bHaveCached = true;
  137. }
  138. CUtlVector<VPhysicsClipEntry_t> m_VPhysicsClipEntities;
  139. bool m_bHaveCached;
  140. };
  141. static CFunc_VPhysics_Clip_Watcher s_VPhysicsClipWatcher;
  142. CUtlVector<VPhysicsClipEntry_t>& GetVPhysicsClipList ( void )
  143. {
  144. return s_VPhysicsClipWatcher.m_VPhysicsClipEntities;
  145. }
  146. #endif
  147. #if defined( DBGFLAG_ASSERT ) && 0 //only enable this if mathlib.lib is built with DBGFLAG_ASSERT and ENABLE_DEBUG_POLYHEDRON_DUMPS is defined in polyhedron.cpp
  148. extern void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform, const char *szfileOpenOptions = "ab" ); //need to make sure mathlib creates this by building it debug or with DBGFLAG_ASSERT
  149. typedef bool (*PFN_PolyhedronCarvingDebugStepCallback)( CPolyhedron *pPolyhedron ); //function that receives a polyhedron conversion after each cut. For the slowest, surest debugging possible. Returns true if the polyhedron passes mustard, false to dump the current work state
  150. extern PFN_PolyhedronCarvingDebugStepCallback g_pPolyhedronCarvingDebugStepCallback;
  151. #define DEBUG_POLYHEDRON_CONVERSION 1
  152. bool TestPolyhedronConversion( CPolyhedron *pPolyhedron )
  153. {
  154. if( pPolyhedron == NULL )
  155. return false;
  156. //dump each test case
  157. if( false )
  158. {
  159. VMatrix matScaleNearOrigin;
  160. matScaleNearOrigin.Identity();
  161. const float cScale = 10.0f;
  162. matScaleNearOrigin = matScaleNearOrigin.Scale( Vector( cScale, cScale, cScale ) );
  163. matScaleNearOrigin.SetTranslation( -pPolyhedron->Center() * cScale );
  164. #ifndef CLIENT_DLL
  165. const char *szDumpFile = "TestPolyhedronConversionServer.txt";
  166. #else
  167. const char *szDumpFile = "TestPolyhedronConversionClient.txt";
  168. #endif
  169. DumpPolyhedronToGLView( pPolyhedron, szDumpFile, &matScaleNearOrigin, "wb" );
  170. }
  171. CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  172. if( pConvex == NULL )
  173. return false;
  174. //TODO: is there an easier way to destroy the convex directly without converting it to a collide first? Debug only code, do we care to make something new?
  175. CPhysCollide *pCollide = physcollision->ConvertConvexToCollide( &pConvex, 1 );
  176. physcollision->DestroyCollide( pCollide );
  177. return true;
  178. }
  179. #endif
  180. #if defined( CLIENT_DLL )
  181. //copy/paste from game/server/hierarchy.cpp
  182. static void GetAllChildren_r( CBaseEntity *pEntity, CUtlVector<CBaseEntity *> &list )
  183. {
  184. for ( ; pEntity != NULL; pEntity = pEntity->NextMovePeer() )
  185. {
  186. list.AddToTail( pEntity );
  187. GetAllChildren_r( pEntity->FirstMoveChild(), list );
  188. }
  189. }
  190. int GetAllChildren( CBaseEntity *pParent, CUtlVector<CBaseEntity *> &list )
  191. {
  192. if ( !pParent )
  193. return 0;
  194. GetAllChildren_r( pParent->FirstMoveChild(), list );
  195. return list.Count();
  196. }
  197. #endif
  198. #ifdef GAME_DLL
  199. BEGIN_SEND_TABLE_NOBASE( PS_SimulationData_t, DT_PS_SimulationData_t )
  200. SendPropEHandle( SENDINFO( hCollisionEntity ) )
  201. END_SEND_TABLE()
  202. #else
  203. BEGIN_RECV_TABLE_NOBASE( PS_SimulationData_t, DT_PS_SimulationData_t )
  204. RecvPropEHandle( RECVINFO( hCollisionEntity ) )
  205. END_RECV_TABLE()
  206. #endif // ifdef GAME_DLL
  207. #ifdef GAME_DLL
  208. BEGIN_SEND_TABLE_NOBASE( PS_InternalData_t, DT_PS_InternalData_t )
  209. SendPropDataTable( SENDINFO_DT(Simulation), &REFERENCE_SEND_TABLE(DT_PS_SimulationData_t) )
  210. END_SEND_TABLE()
  211. #else
  212. BEGIN_RECV_TABLE_NOBASE( PS_InternalData_t, DT_PS_InternalData_t )
  213. RecvPropDataTable( RECVINFO_DT(Simulation), 0, &REFERENCE_RECV_TABLE(DT_PS_SimulationData_t) )
  214. END_RECV_TABLE()
  215. #endif // ifdef GAME_DLL
  216. #ifdef GAME_DLL
  217. BEGIN_SEND_TABLE_NOBASE( CPortalSimulator, DT_PortalSimulator )
  218. SendPropDataTable( SENDINFO_DT(m_InternalData), &REFERENCE_SEND_TABLE(DT_PS_InternalData_t) )
  219. END_SEND_TABLE()
  220. #else
  221. BEGIN_RECV_TABLE_NOBASE( CPortalSimulator, DT_PortalSimulator )
  222. RecvPropDataTable( RECVINFO_DT(m_InternalData), 0, &REFERENCE_RECV_TABLE(DT_PS_InternalData_t) )
  223. END_RECV_TABLE()
  224. #endif // ifdef GAME_DLL
  225. CPortalSimulator::CPortalSimulator( void )
  226. : m_bLocalDataIsReady(false),
  227. m_bGenerateCollision(true),
  228. m_bSimulateVPhysics(true),
  229. m_bSharedCollisionConfiguration(false),
  230. m_pLinkedPortal(NULL),
  231. m_bInCrossLinkedFunction(false),
  232. m_pCallbacks(&s_DummyPortalSimulatorCallback)
  233. {
  234. s_PortalSimulators.AddToTail( this );
  235. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  236. g_pPolyhedronCarvingDebugStepCallback = TestPolyhedronConversion;
  237. #endif
  238. #ifdef CLIENT_DLL
  239. m_bGenerateCollision = (GameRules() && GameRules()->IsMultiplayer());
  240. #endif
  241. m_CreationChecklist.bPolyhedronsGenerated = false;
  242. m_CreationChecklist.bLocalCollisionGenerated = false;
  243. m_CreationChecklist.bLinkedCollisionGenerated = false;
  244. m_CreationChecklist.bLocalPhysicsGenerated = false;
  245. m_CreationChecklist.bLinkedPhysicsGenerated = false;
  246. #ifdef PORTAL_SIMULATORS_EMBED_GUID
  247. static int s_iPortalSimulatorGUIDAllocator = 0;
  248. m_iPortalSimulatorGUID = s_iPortalSimulatorGUIDAllocator++;
  249. #endif
  250. #ifndef CLIENT_DLL
  251. PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = GetWorldEntity(); //will overinitialize, but it's cheap
  252. m_InternalData.Simulation.hCollisionEntity = (CPSCollisionEntity *)CreateEntityByName( "portalsimulator_collisionentity" );
  253. Assert( m_InternalData.Simulation.hCollisionEntity != NULL );
  254. if( m_InternalData.Simulation.hCollisionEntity )
  255. {
  256. m_InternalData.Simulation.hCollisionEntity->m_pOwningSimulator = this;
  257. MarkAsOwned( m_InternalData.Simulation.hCollisionEntity );
  258. m_InternalData.Simulation.Dynamic.EntFlags[m_InternalData.Simulation.hCollisionEntity->entindex()] |= PSEF_OWNS_PHYSICS;
  259. DispatchSpawn( m_InternalData.Simulation.hCollisionEntity );
  260. }
  261. #else
  262. PS_SD_Static_World_StaticProps_ClippedProp_t::pTraceEntity = GetClientWorldEntity();
  263. #endif
  264. }
  265. CPortalSimulator::~CPortalSimulator( void )
  266. {
  267. //go assert crazy here
  268. DetachFromLinked();
  269. ClearEverything();
  270. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  271. {
  272. if( s_PortalSimulators[i] == this )
  273. {
  274. s_PortalSimulators.FastRemove( i );
  275. break;
  276. }
  277. }
  278. if( m_InternalData.Placement.pHoleShapeCollideable )
  279. physcollision->DestroyCollide( m_InternalData.Placement.pHoleShapeCollideable );
  280. if( m_InternalData.Placement.pInvHoleShapeCollideable )
  281. physcollision->DestroyCollide( m_InternalData.Placement.pInvHoleShapeCollideable );
  282. if( m_InternalData.Placement.pAABBAngleTransformCollideable )
  283. physcollision->DestroyCollide( m_InternalData.Placement.pAABBAngleTransformCollideable );
  284. #ifndef CLIENT_DLL
  285. if( m_InternalData.Simulation.hCollisionEntity )
  286. {
  287. m_InternalData.Simulation.hCollisionEntity->m_pOwningSimulator = NULL;
  288. m_InternalData.Simulation.Dynamic.EntFlags[m_InternalData.Simulation.hCollisionEntity->entindex()] &= ~PSEF_OWNS_PHYSICS;
  289. MarkAsReleased( m_InternalData.Simulation.hCollisionEntity );
  290. UTIL_Remove( m_InternalData.Simulation.hCollisionEntity );
  291. m_InternalData.Simulation.hCollisionEntity = NULL;
  292. }
  293. #endif
  294. }
  295. void CPortalSimulator::SetSize( float fHalfWidth, float fHalfHeight )
  296. {
  297. if( (m_InternalData.Placement.fHalfWidth == fHalfWidth) && (m_InternalData.Placement.fHalfHeight == fHalfHeight) ) //not actually resizing at all
  298. return;
  299. CREATEDEBUGTIMER( functionTimer );
  300. STARTDEBUGTIMER( functionTimer );
  301. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetSize() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  302. INCREMENTTABSPACING();
  303. MovedOrResized( m_InternalData.Placement.ptCenter, m_InternalData.Placement.qAngles, fHalfWidth, fHalfHeight );
  304. STOPDEBUGTIMER( functionTimer );
  305. DECREMENTTABSPACING();
  306. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetSize() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  307. }
  308. void CPortalSimulator::MoveTo( const Vector &ptCenter, const QAngle &angles )
  309. {
  310. if( (m_InternalData.Placement.ptCenter == ptCenter) && (m_InternalData.Placement.qAngles == angles) ) //not actually moving at all
  311. return;
  312. CREATEDEBUGTIMER( functionTimer );
  313. STARTDEBUGTIMER( functionTimer );
  314. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::MoveTo() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  315. INCREMENTTABSPACING();
  316. MovedOrResized( ptCenter, angles, m_InternalData.Placement.fHalfWidth, m_InternalData.Placement.fHalfHeight );
  317. STOPDEBUGTIMER( functionTimer );
  318. DECREMENTTABSPACING();
  319. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::MoveTo() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  320. }
  321. extern ConVar sv_portal_new_player_trace;
  322. CEG_NOINLINE void CPortalSimulator::MovedOrResized( const Vector &ptCenter, const QAngle &qAngles, float fHalfWidth, float fHalfHeight )
  323. {
  324. if( (fHalfWidth == 0.0f) || (fHalfHeight == 0.0f) || !ptCenter.IsValid() )
  325. {
  326. m_InternalData.Placement.fHalfWidth = fHalfWidth;
  327. m_InternalData.Placement.fHalfHeight = fHalfHeight;
  328. ClearEverything();
  329. return;
  330. }
  331. #ifndef CLIENT_DLL
  332. //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
  333. CBaseEntity **pFixEntities = (CBaseEntity **)stackalloc( sizeof( CBaseEntity * ) * m_InternalData.Simulation.Dynamic.OwnedEntities.Count() );
  334. int iFixEntityCount = 0;
  335. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  336. {
  337. CBaseEntity *pEntity = m_InternalData.Simulation.Dynamic.OwnedEntities[i];
  338. if( CPhysicsShadowClone::IsShadowClone( pEntity ) ||
  339. CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  340. continue;
  341. if( EntityIsInPortalHole( pEntity ) )
  342. {
  343. pFixEntities[iFixEntityCount] = pEntity;
  344. ++iFixEntityCount;
  345. }
  346. }
  347. VPlane OldPlane = m_InternalData.Placement.PortalPlane; //used in fixing code
  348. #endif
  349. //update placement data
  350. {
  351. m_InternalData.Placement.ptCenter = ptCenter;
  352. m_InternalData.Placement.qAngles = qAngles;
  353. AngleVectors( qAngles, &m_InternalData.Placement.vForward, &m_InternalData.Placement.vRight, &m_InternalData.Placement.vUp );
  354. m_InternalData.Placement.PortalPlane.Init( m_InternalData.Placement.vForward, m_InternalData.Placement.vForward.Dot( m_InternalData.Placement.ptCenter ) );
  355. m_InternalData.Placement.fHalfWidth = fHalfWidth;
  356. m_InternalData.Placement.fHalfHeight = fHalfHeight;
  357. m_InternalData.Placement.vCollisionCloneExtents.x = MAX( fHalfWidth, fHalfHeight ) + portal_environment_radius.GetFloat();
  358. m_InternalData.Placement.vCollisionCloneExtents.y = fHalfWidth + portal_environment_radius.GetFloat();
  359. m_InternalData.Placement.vCollisionCloneExtents.z = fHalfHeight + portal_environment_radius.GetFloat();
  360. }
  361. //Clear();
  362. #ifndef CLIENT_DLL
  363. ClearLinkedPhysics();
  364. ClearLocalPhysics();
  365. #endif
  366. ClearLinkedCollision();
  367. ClearLocalCollision();
  368. ClearPolyhedrons();
  369. m_bLocalDataIsReady = true;
  370. UpdateLinkMatrix();
  371. //update hole shape - used to detect if an entity is within the portal hole bounds
  372. {
  373. float fHolePlanes[6*4];
  374. //first and second planes are always forward and backward planes
  375. fHolePlanes[(0*4) + 0] = m_InternalData.Placement.PortalPlane.m_Normal.x;
  376. fHolePlanes[(0*4) + 1] = m_InternalData.Placement.PortalPlane.m_Normal.y;
  377. fHolePlanes[(0*4) + 2] = m_InternalData.Placement.PortalPlane.m_Normal.z;
  378. fHolePlanes[(0*4) + 3] = m_InternalData.Placement.PortalPlane.m_Dist - 0.5f;
  379. fHolePlanes[(1*4) + 0] = -m_InternalData.Placement.PortalPlane.m_Normal.x;
  380. fHolePlanes[(1*4) + 1] = -m_InternalData.Placement.PortalPlane.m_Normal.y;
  381. fHolePlanes[(1*4) + 2] = -m_InternalData.Placement.PortalPlane.m_Normal.z;
  382. fHolePlanes[(1*4) + 3] = (-m_InternalData.Placement.PortalPlane.m_Dist) + 500.0f;
  383. //the remaining planes will always have the same ordering of normals, with different distances plugged in for each convex we're creating
  384. //normal order is up, down, left, right
  385. fHolePlanes[(2*4) + 0] = m_InternalData.Placement.vUp.x;
  386. fHolePlanes[(2*4) + 1] = m_InternalData.Placement.vUp.y;
  387. fHolePlanes[(2*4) + 2] = m_InternalData.Placement.vUp.z;
  388. fHolePlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight * 0.98f)) );
  389. fHolePlanes[(3*4) + 0] = -m_InternalData.Placement.vUp.x;
  390. fHolePlanes[(3*4) + 1] = -m_InternalData.Placement.vUp.y;
  391. fHolePlanes[(3*4) + 2] = -m_InternalData.Placement.vUp.z;
  392. fHolePlanes[(3*4) + 3] = -m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight * 0.98f)) );
  393. fHolePlanes[(4*4) + 0] = -m_InternalData.Placement.vRight.x;
  394. fHolePlanes[(4*4) + 1] = -m_InternalData.Placement.vRight.y;
  395. fHolePlanes[(4*4) + 2] = -m_InternalData.Placement.vRight.z;
  396. fHolePlanes[(4*4) + 3] = -m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth * 0.98f)) );
  397. fHolePlanes[(5*4) + 0] = m_InternalData.Placement.vRight.x;
  398. fHolePlanes[(5*4) + 1] = m_InternalData.Placement.vRight.y;
  399. fHolePlanes[(5*4) + 2] = m_InternalData.Placement.vRight.z;
  400. fHolePlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth * 0.98f)) );
  401. //create hole collideable
  402. {
  403. if( m_InternalData.Placement.pHoleShapeCollideable )
  404. physcollision->DestroyCollide( m_InternalData.Placement.pHoleShapeCollideable );
  405. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON, true );
  406. Assert( pPolyhedron != NULL );
  407. CPhysConvex *pConvex = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  408. pPolyhedron->Release();
  409. Assert( pConvex != NULL );
  410. convertconvexparams_t params;
  411. params.Defaults();
  412. params.buildOptimizedTraceTables = true;
  413. params.bUseFastApproximateInertiaTensor = true;
  414. m_InternalData.Placement.pHoleShapeCollideable = physcollision->ConvertConvexToCollideParams( &pConvex, 1, params );
  415. }
  416. //create inverse hole collideable
  417. {
  418. if( m_InternalData.Placement.pInvHoleShapeCollideable )
  419. physcollision->DestroyCollide( m_InternalData.Placement.pInvHoleShapeCollideable );
  420. if( m_InternalData.Placement.pAABBAngleTransformCollideable )
  421. physcollision->DestroyCollide( m_InternalData.Placement.pAABBAngleTransformCollideable );
  422. const float kCarveEpsilon = (1.0f / 512.0f);
  423. //make thickness extra thin
  424. fHolePlanes[(0*4) + 3] = m_InternalData.Placement.PortalPlane.m_Dist;
  425. fHolePlanes[(1*4) + 3] = (-m_InternalData.Placement.PortalPlane.m_Dist) + 1.0f;
  426. float fAABBTransformPlanes[6*4];
  427. memcpy( fAABBTransformPlanes, fHolePlanes, sizeof( float ) * 6 * 4 );
  428. fAABBTransformPlanes[(0*4) + 3] = m_InternalData.Placement.PortalPlane.m_Dist - (PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT / 2.0f);
  429. fAABBTransformPlanes[(1*4) + 3] = (-m_InternalData.Placement.PortalPlane.m_Dist) + (64.0f);
  430. //set initial outer bounds super far away (supposed to represent an infinite plane with a finite solid)
  431. const float kReallyFar = 1024.0f;
  432. float fFarDists[4]; //mapping is meant to be (fFarDists[i] <-> fHolePlanes[((i+2)*4) + 3])
  433. fFarDists[0] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * kReallyFar) );
  434. fFarDists[1] = -m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * kReallyFar) );
  435. fFarDists[2] = -m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vRight * kReallyFar) );
  436. fFarDists[3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * kReallyFar) );
  437. #ifdef CLIENT_DLL
  438. CEG_PROTECT_MEMBER_FUNCTION( CPortalSimulator_MovedOrResized );
  439. #endif
  440. const float kInnerCarve = 0.1f;
  441. float fInvHoleNearDists[4]; //mapping is meant to be (fInvHoleNearDists[i] <-> fHolePlanes[((i+2)*4) + 3])
  442. fInvHoleNearDists[0] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight + kInnerCarve)) );
  443. fInvHoleNearDists[1] = -m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight + kInnerCarve)) );
  444. fInvHoleNearDists[2] = -m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth + kInnerCarve)) );
  445. fInvHoleNearDists[3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth + kInnerCarve)) );
  446. const float kAABBInnerCarve = (PORTAL_HOLE_HALF_WIDTH_MOD + (1.0f/16.0f)) * 4.0f;//(-1.0f/1024.0f);
  447. float fAABBTransformNearDists[4]; //mapping is meant to be (fAABBTransformNearDists[i] <-> fAABBTransformPlanes[((i+2)*4) + 3])
  448. fAABBTransformNearDists[0] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight + kAABBInnerCarve)) );
  449. fAABBTransformNearDists[1] = -m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vUp * (m_InternalData.Placement.fHalfHeight + kAABBInnerCarve)) );
  450. fAABBTransformNearDists[2] = -m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth + kAABBInnerCarve)) );
  451. fAABBTransformNearDists[3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter - (m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth + kAABBInnerCarve)) );
  452. //left and right sections will be the sliver segments, top and bottom are roughly half the surface area of the entire collideable each
  453. CPhysConvex *pInvHoleConvexes[4];
  454. CPhysConvex *pAABBTransformConvexes[4];
  455. //top section
  456. {
  457. fHolePlanes[(2*4) + 3] = fFarDists[0];
  458. fHolePlanes[(3*4) + 3] = fInvHoleNearDists[1];
  459. fHolePlanes[(4*4) + 3] = fFarDists[2];
  460. fHolePlanes[(5*4) + 3] = fFarDists[3];
  461. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, kCarveEpsilon, true );
  462. Assert( pPolyhedron != NULL );
  463. pInvHoleConvexes[0] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  464. pPolyhedron->Release();
  465. Assert( pInvHoleConvexes[0] != NULL );
  466. fAABBTransformPlanes[(2*4) + 3] = fFarDists[0];
  467. fAABBTransformPlanes[(3*4) + 3] = fAABBTransformNearDists[1];
  468. fAABBTransformPlanes[(4*4) + 3] = fFarDists[2];
  469. fAABBTransformPlanes[(5*4) + 3] = fFarDists[3];
  470. /*pPolyhedron = GeneratePolyhedronFromPlanes( fAABBTransformPlanes, 6, kCarveEpsilon, true );
  471. Assert( pPolyhedron != NULL );
  472. pAABBTransformConvexes[0] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  473. pPolyhedron->Release();
  474. Assert( pAABBTransformConvexes[0] != NULL );*/
  475. }
  476. //bottom section
  477. {
  478. fHolePlanes[(2*4) + 3] = fInvHoleNearDists[0];
  479. fHolePlanes[(3*4) + 3] = fFarDists[1];
  480. //fHolePlanes[(4*4) + 3] = fFarDists[2]; //no change since top section
  481. //fHolePlanes[(5*4) + 3] = fFarDists[3];
  482. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, kCarveEpsilon, true );
  483. Assert( pPolyhedron != NULL );
  484. pInvHoleConvexes[1] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  485. pPolyhedron->Release();
  486. Assert( pInvHoleConvexes[1] != NULL );
  487. fAABBTransformPlanes[(2*4) + 3] = fAABBTransformNearDists[0];
  488. fAABBTransformPlanes[(3*4) + 3] = fFarDists[1];
  489. //fAABBTransformPlanes[(4*4) + 3] = fFarDists[2]; //no change since top section
  490. //fAABBTransformPlanes[(5*4) + 3] = fFarDists[3];
  491. pPolyhedron = GeneratePolyhedronFromPlanes( fAABBTransformPlanes, 6, kCarveEpsilon, true );
  492. Assert( pPolyhedron != NULL );
  493. pAABBTransformConvexes[1] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  494. pPolyhedron->Release();
  495. Assert( pAABBTransformConvexes[1] != NULL );
  496. }
  497. //left section
  498. {
  499. fHolePlanes[(2*4) + 3] = -fInvHoleNearDists[1]; //remap inward facing top/bottom near distances to outward facing ones
  500. fHolePlanes[(3*4) + 3] = -fInvHoleNearDists[0];
  501. //fHolePlanes[(4*4) + 3] = fFarDists[2]; //no change since bottom section
  502. fHolePlanes[(5*4) + 3] = fInvHoleNearDists[3];
  503. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, kCarveEpsilon, true );
  504. Assert( pPolyhedron != NULL );
  505. pInvHoleConvexes[2] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  506. pPolyhedron->Release();
  507. Assert( pInvHoleConvexes[2] != NULL );
  508. fAABBTransformPlanes[(2*4) + 3] = -fAABBTransformNearDists[1]; //remap inward facing top/bottom near distances to outward facing ones
  509. fAABBTransformPlanes[(3*4) + 3] = -fAABBTransformNearDists[0];
  510. //fAABBTransformPlanes[(4*4) + 3] = fFarDists[2]; //no change since bottom section
  511. fAABBTransformPlanes[(5*4) + 3] = fAABBTransformNearDists[3];
  512. /*pPolyhedron = GeneratePolyhedronFromPlanes( fAABBTransformPlanes, 6, kCarveEpsilon, true );
  513. Assert( pPolyhedron != NULL );
  514. pAABBTransformConvexes[2] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  515. pPolyhedron->Release();
  516. Assert( pAABBTransformConvexes[2] != NULL );*/
  517. }
  518. //right section
  519. {
  520. //fHolePlanes[(2*4) + 3] = -fInvHoleNearDists[1]; //no change since left section
  521. //fHolePlanes[(3*4) + 3] = -fInvHoleNearDists[0];
  522. fHolePlanes[(4*4) + 3] = fInvHoleNearDists[2];
  523. fHolePlanes[(5*4) + 3] = fFarDists[3];
  524. CPolyhedron *pPolyhedron = GeneratePolyhedronFromPlanes( fHolePlanes, 6, kCarveEpsilon, true );
  525. Assert( pPolyhedron != NULL );
  526. pInvHoleConvexes[3] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  527. pPolyhedron->Release();
  528. Assert( pInvHoleConvexes[3] != NULL );
  529. //fAABBTransformPlanes[(2*4) + 3] = -fAABBTransformNearDists[1]; //no change since left section
  530. //fAABBTransformPlanes[(3*4) + 3] = -fAABBTransformNearDists[0];
  531. fAABBTransformPlanes[(4*4) + 3] = fAABBTransformNearDists[2];
  532. fAABBTransformPlanes[(5*4) + 3] = fFarDists[3];
  533. /*pPolyhedron = GeneratePolyhedronFromPlanes( fAABBTransformPlanes, 6, kCarveEpsilon, true );
  534. Assert( pPolyhedron != NULL );
  535. pAABBTransformConvexes[3] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedron );
  536. pPolyhedron->Release();
  537. Assert( pAABBTransformConvexes[3] != NULL );*/
  538. }
  539. convertconvexparams_t params;
  540. params.Defaults();
  541. params.buildOptimizedTraceTables = true;
  542. params.bUseFastApproximateInertiaTensor = true;
  543. m_InternalData.Placement.pInvHoleShapeCollideable = physcollision->ConvertConvexToCollideParams( pInvHoleConvexes, 4, params );
  544. //m_InternalData.Placement.pAABBAngleTransformCollideable = physcollision->ConvertConvexToCollide( pAABBTransformConvexes, 4 );
  545. m_InternalData.Placement.pAABBAngleTransformCollideable = physcollision->ConvertConvexToCollideParams( &pAABBTransformConvexes[1], 1, params );
  546. }
  547. }
  548. #ifndef CLIENT_DLL
  549. for( int i = 0; i != iFixEntityCount; ++i )
  550. {
  551. if( !EntityIsInPortalHole( pFixEntities[i] ) )
  552. {
  553. //this entity is most definitely stuck in a solid wall right now
  554. //pFixEntities[i]->SetAbsOrigin( pFixEntities[i]->GetAbsOrigin() + (OldPlane.m_Normal * 50.0f) );
  555. FindClosestPassableSpace( pFixEntities[i], OldPlane.m_Normal );
  556. continue;
  557. }
  558. //entity is still in the hole, but it's possible the hole moved enough where they're in part of the wall
  559. {
  560. //TODO: figure out if that's the case and fix it
  561. }
  562. }
  563. #endif
  564. CreatePolyhedrons();
  565. CreateAllCollision();
  566. #ifndef CLIENT_DLL
  567. CreateAllPhysics();
  568. #endif
  569. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS )
  570. if( sv_dump_portalsimulator_collision.GetBool() )
  571. {
  572. const char *szFileName = "pscd_" s_szDLLName ".txt";
  573. filesystem->RemoveFile( szFileName );
  574. DumpActiveCollision( this, szFileName );
  575. if( m_pLinkedPortal )
  576. {
  577. szFileName = "pscd_" s_szDLLName "_linked.txt";
  578. filesystem->RemoveFile( szFileName );
  579. DumpActiveCollision( m_pLinkedPortal, szFileName );
  580. }
  581. }
  582. #endif
  583. #ifndef CLIENT_DLL
  584. Assert( (m_InternalData.Simulation.hCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.hCollisionEntity) );
  585. #endif
  586. }
  587. void CPortalSimulator::UpdateLinkMatrix( void )
  588. {
  589. if( m_pLinkedPortal && m_pLinkedPortal->m_bLocalDataIsReady )
  590. {
  591. Vector vLocalLeft = -m_InternalData.Placement.vRight;
  592. VMatrix matLocalToWorld( m_InternalData.Placement.vForward, vLocalLeft, m_InternalData.Placement.vUp );
  593. matLocalToWorld.SetTranslation( m_InternalData.Placement.ptCenter );
  594. VMatrix matLocalToWorldInverse;
  595. MatrixInverseTR( matLocalToWorld,matLocalToWorldInverse );
  596. //180 degree rotation about up
  597. VMatrix matRotation;
  598. matRotation.Identity();
  599. matRotation.m[0][0] = -1.0f;
  600. matRotation.m[1][1] = -1.0f;
  601. Vector vRemoteLeft = -m_pLinkedPortal->m_InternalData.Placement.vRight;
  602. VMatrix matRemoteToWorld( m_pLinkedPortal->m_InternalData.Placement.vForward, vRemoteLeft, m_pLinkedPortal->m_InternalData.Placement.vUp );
  603. matRemoteToWorld.SetTranslation( m_pLinkedPortal->m_InternalData.Placement.ptCenter );
  604. //final
  605. m_InternalData.Placement.matThisToLinked = matRemoteToWorld * matRotation * matLocalToWorldInverse;
  606. }
  607. else
  608. {
  609. m_InternalData.Placement.matThisToLinked.Identity();
  610. }
  611. m_InternalData.Placement.matThisToLinked.InverseTR( m_InternalData.Placement.matLinkedToThis );
  612. MatrixAngles( m_InternalData.Placement.matThisToLinked.As3x4(), m_InternalData.Placement.ptaap_ThisToLinked.qAngleTransform, m_InternalData.Placement.ptaap_ThisToLinked.ptOriginTransform );
  613. MatrixAngles( m_InternalData.Placement.matLinkedToThis.As3x4(), m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform );
  614. m_InternalData.Placement.ptaap_ThisToLinked.ptShrinkAlignedOrigin = m_InternalData.Placement.ptaap_ThisToLinked.ptOriginTransform;
  615. m_InternalData.Placement.ptaap_LinkedToThis.ptShrinkAlignedOrigin = m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform;
  616. if( m_InternalData.Placement.bParentIsVPhysicsSolidBrush )
  617. {
  618. if( m_pLinkedPortal )
  619. {
  620. m_InternalData.Placement.ptaap_ThisToLinked.ptShrinkAlignedOrigin += m_pLinkedPortal->m_InternalData.Placement.vForward * VPHYSICS_SHRINK;
  621. }
  622. m_InternalData.Placement.ptaap_LinkedToThis.ptShrinkAlignedOrigin -= m_InternalData.Placement.vForward * VPHYSICS_SHRINK;
  623. }
  624. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  625. {
  626. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  627. m_bInCrossLinkedFunction = true;
  628. m_pLinkedPortal->UpdateLinkMatrix();
  629. m_bInCrossLinkedFunction = false;
  630. }
  631. }
  632. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  633. static ConVar sv_debug_dumpportalhole_nextcheck( "sv_debug_dumpportalhole_nextcheck", "0", FCVAR_CHEAT | FCVAR_REPLICATED );
  634. #endif
  635. bool CPortalSimulator::EntityIsInPortalHole( CBaseEntity *pEntity ) const
  636. {
  637. if( m_bLocalDataIsReady == false )
  638. return false;
  639. Assert( m_InternalData.Placement.pHoleShapeCollideable != NULL );
  640. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  641. const char *szDumpFileName = "ps_entholecheck.txt";
  642. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  643. {
  644. filesystem->RemoveFile( szDumpFileName );
  645. DumpActiveCollision( this, szDumpFileName );
  646. PortalSimulatorDumps_DumpCollideToGlView( m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, 1.0f, szDumpFileName );
  647. }
  648. #endif
  649. trace_t Trace;
  650. switch( pEntity->GetSolid() )
  651. {
  652. case SOLID_VPHYSICS:
  653. {
  654. ICollideable *pCollideable = pEntity->GetCollideable();
  655. vcollide_t *pVCollide = modelinfo->GetVCollide( pCollideable->GetCollisionModel() );
  656. //Assert( pVCollide != NULL ); //brush models?
  657. if( pVCollide != NULL )
  658. {
  659. Vector ptEntityPosition = pCollideable->GetCollisionOrigin();
  660. QAngle qEntityAngles = pCollideable->GetCollisionAngles();
  661. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  662. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  663. {
  664. for( int i = 0; i != pVCollide->solidCount; ++i )
  665. PortalSimulatorDumps_DumpCollideToGlView( m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, 0.4f, szDumpFileName );
  666. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  667. }
  668. #endif
  669. for( int i = 0; i != pVCollide->solidCount; ++i )
  670. {
  671. physcollision->TraceCollide( ptEntityPosition, ptEntityPosition, pVCollide->solids[i], qEntityAngles, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  672. if( Trace.startsolid )
  673. return true;
  674. }
  675. }
  676. else
  677. {
  678. //energy balls lack a vcollide
  679. Vector vMins, vMaxs, ptCenter;
  680. pCollideable->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
  681. ptCenter = (vMins + vMaxs) * 0.5f;
  682. vMins -= ptCenter;
  683. vMaxs -= ptCenter;
  684. physcollision->TraceBox( ptCenter, ptCenter, vMins, vMaxs, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  685. return Trace.startsolid;
  686. }
  687. break;
  688. }
  689. case SOLID_BBOX:
  690. case SOLID_OBB:
  691. case SOLID_OBB_YAW:
  692. {
  693. #if defined( CLIENT_DLL )
  694. if( !C_BaseEntity::IsAbsQueriesValid() )
  695. {
  696. return ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_IS_IN_PORTAL_HOLE) != 0); //return existing value if we can't test it right now
  697. }
  698. #endif
  699. Vector ptEntityPosition = pEntity->GetAbsOrigin();
  700. CCollisionProperty *pCollisionProp = pEntity->CollisionProp();
  701. physcollision->TraceBox( ptEntityPosition, ptEntityPosition, pCollisionProp->OBBMins(), pCollisionProp->OBBMaxs(), m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  702. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  703. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  704. {
  705. Vector vMins = ptEntityPosition + pCollisionProp->OBBMins();
  706. Vector vMaxs = ptEntityPosition + pCollisionProp->OBBMaxs();
  707. PortalSimulatorDumps_DumpBoxToGlView( vMins, vMaxs, 1.0f, 1.0f, 1.0f, szDumpFileName );
  708. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  709. }
  710. #endif
  711. if( Trace.startsolid )
  712. return true;
  713. break;
  714. }
  715. case SOLID_NONE:
  716. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  717. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  718. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  719. #endif
  720. return false;
  721. case SOLID_CUSTOM:
  722. {
  723. Vector vMins, vMaxs;
  724. Vector ptCenter = pEntity->CollisionProp()->GetCollisionOrigin();
  725. pEntity->ComputeWorldSpaceSurroundingBox( &vMins, &vMaxs );
  726. physcollision->TraceBox( ptCenter, ptCenter, vMins, vMaxs, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  727. }
  728. break;
  729. default:
  730. Assert( false ); //make a handler
  731. };
  732. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  733. if( sv_debug_dumpportalhole_nextcheck.GetBool() )
  734. sv_debug_dumpportalhole_nextcheck.SetValue( false );
  735. #endif
  736. return false;
  737. }
  738. bool CPortalSimulator::EntityHitBoxExtentIsInPortalHole( CBaseAnimating *pBaseAnimating, bool bUseCollisionAABB ) const
  739. {
  740. if( m_bLocalDataIsReady == false )
  741. return false;
  742. Vector vMinsOut, vMaxsOut;
  743. Vector vCenter;
  744. if ( !bUseCollisionAABB || portal_ghost_force_hitbox.GetBool() )
  745. {
  746. CStudioHdr *pStudioHdr = pBaseAnimating->GetModelPtr();
  747. if ( !pStudioHdr )
  748. return false;
  749. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pBaseAnimating->m_nHitboxSet );
  750. if ( !set )
  751. return false;
  752. matrix3x4_t matTransform;
  753. Vector vMins, vMaxs;
  754. for ( int i = 0; i < set->numhitboxes; i++ )
  755. {
  756. mstudiobbox_t *pbox = set->pHitbox( i );
  757. pBaseAnimating->GetBoneTransform( pbox->bone, matTransform );
  758. TransformAABB( matTransform, pbox->bbmin, pbox->bbmax, vMins, vMaxs );
  759. if ( i == 0 )
  760. {
  761. vMinsOut = vMins;
  762. vMaxsOut = vMaxs;
  763. }
  764. else
  765. {
  766. vMinsOut = vMinsOut.Min( vMins );
  767. vMaxsOut = vMaxsOut.Max( vMaxs );
  768. }
  769. }
  770. vCenter = (vMinsOut + vMaxsOut) * 0.5f;
  771. vMinsOut -= vCenter;
  772. vMaxsOut -= vCenter;
  773. #ifdef CLIENT_DLL
  774. // offset the center to render origin
  775. Vector vOffset = pBaseAnimating->GetRenderOrigin() - pBaseAnimating->GetAbsOrigin();
  776. vCenter += vOffset;
  777. #endif // CLIENT_DLL
  778. }
  779. else
  780. {
  781. CCollisionProperty *pCollisionProp = pBaseAnimating->CollisionProp();
  782. pCollisionProp->WorldSpaceAABB( &vMinsOut, &vMaxsOut);
  783. vCenter = (vMinsOut + vMaxsOut) * 0.5f;
  784. vMinsOut -= vCenter;
  785. vMaxsOut -= vCenter;
  786. }
  787. #ifdef CLIENT_DLL
  788. if ( portal_ghost_show_bbox.GetBool() )
  789. {
  790. NDebugOverlay::BoxAngles( vCenter, vMinsOut, vMaxsOut, vec3_angle, 200, 200, 50, 50, NDEBUG_PERSIST_TILL_NEXT_SERVER );
  791. }
  792. #endif // CLIENT_DLL
  793. float flScaleFactor = portal_ghosts_scale.GetFloat();
  794. vMinsOut *= flScaleFactor;
  795. vMaxsOut *= flScaleFactor;
  796. trace_t Trace;
  797. physcollision->TraceBox( vCenter, vCenter, vMinsOut, vMaxsOut, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  798. if( Trace.startsolid )
  799. return true;
  800. return false;
  801. }
  802. void CPortalSimulator::RemoveEntityFromPortalHole( CBaseEntity *pEntity )
  803. {
  804. switch( pEntity->GetMoveType() )
  805. {
  806. case MOVETYPE_PUSH:
  807. case MOVETYPE_NOCLIP:
  808. case MOVETYPE_LADDER:
  809. case MOVETYPE_OBSERVER:
  810. case MOVETYPE_CUSTOM:
  811. return;
  812. }
  813. if( EntityIsInPortalHole( pEntity ) )
  814. {
  815. #if defined( GAME_DLL )
  816. if( !FindClosestPassableSpace( pEntity, m_InternalData.Placement.PortalPlane.m_Normal, pEntity->IsPlayer() ? MASK_PLAYERSOLID : MASK_SOLID ) )
  817. {
  818. if( pEntity->IsPlayer() )
  819. {
  820. CTakeDamageInfo dmgInfo( GetWorldEntity(), GetWorldEntity(), vec3_origin, vec3_origin, 1000, DMG_CRUSH );
  821. dmgInfo.SetDamageForce( Vector( 0, 0, -1 ) );
  822. dmgInfo.SetDamagePosition( pEntity->GetAbsOrigin() );
  823. pEntity->TakeDamage( dmgInfo );
  824. }
  825. }
  826. #if defined( DBGFLAG_ASSERT )
  827. else
  828. {
  829. trace_t trAssert;
  830. UTIL_TraceEntity( pEntity, pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin(), pEntity->IsPlayer() ? MASK_PLAYERSOLID : MASK_SOLID, pEntity, pEntity->GetCollisionGroup(), &trAssert );
  831. Assert( !trAssert.startsolid );
  832. }
  833. #endif
  834. #else
  835. FindClosestPassableSpace( pEntity, m_InternalData.Placement.PortalPlane.m_Normal );
  836. #endif
  837. }
  838. }
  839. extern ConVar sv_portal_new_player_trace;
  840. RayInPortalHoleResult_t CPortalSimulator::IsRayInPortalHole( const Ray_t &ray ) const
  841. {
  842. AssertMsg( m_InternalData.Placement.pHoleShapeCollideable, "Portal wasn't set up properly." );
  843. if( m_InternalData.Placement.pHoleShapeCollideable == NULL ) //should probably catch this case higher up
  844. return RIPHR_NOT_TOUCHING_HOLE;
  845. trace_t Trace;
  846. UTIL_ClearTrace( Trace );
  847. physcollision->TraceBox( ray, m_InternalData.Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, &Trace );
  848. if( sv_portal_new_player_trace.GetBool() == false )
  849. {
  850. return Trace.DidHit() ? RIPHR_TOUCHING_HOLE_NOT_WALL : RIPHR_NOT_TOUCHING_HOLE;
  851. }
  852. if( Trace.DidHit() )
  853. {
  854. if( m_InternalData.Placement.pInvHoleShapeCollideable == NULL )
  855. return RIPHR_TOUCHING_HOLE_NOT_WALL;
  856. trace_t TraceInv;
  857. UTIL_ClearTrace( TraceInv );
  858. physcollision->TraceBox( ray, m_InternalData.Placement.pInvHoleShapeCollideable, vec3_origin, vec3_angle, &TraceInv );
  859. if( ray.m_IsSwept )
  860. {
  861. //we get a little funky when handling a swept ray
  862. //There are two distinct cases to consider, rays originating in the portal hole and rays travelling into the portal hole
  863. //
  864. if( TraceInv.DidHit() )
  865. {
  866. //if originating entirely from within the portal, we'll call this a portal-only touch
  867. return (Trace.startsolid && !TraceInv.startsolid) ? RIPHR_TOUCHING_HOLE_NOT_WALL : RIPHR_TOUCHING_HOLE_AND_WALL;
  868. }
  869. else
  870. {
  871. return RIPHR_TOUCHING_HOLE_NOT_WALL;
  872. }
  873. }
  874. return TraceInv.DidHit() ? RIPHR_TOUCHING_HOLE_AND_WALL : RIPHR_TOUCHING_HOLE_NOT_WALL;
  875. }
  876. else
  877. {
  878. return RIPHR_NOT_TOUCHING_HOLE;
  879. }
  880. }
  881. static inline void SetupEntityPortalHoleCarvePlanes( PS_PlacementData_t &PlacementData, VMatrix &matTransform, float fClip_Front[4], float fClip_BackTop[2][4], float fClip_BackBottom[2][4], float fClip_BackLeft[4][4], float fClip_BackRight[4][4] )
  882. {
  883. const float fHalfHoleWidth = PlacementData.fHalfWidth + PORTAL_HOLE_HALF_WIDTH_MOD + PORTAL_WALL_MIN_THICKNESS;
  884. const float fHalfHoleHeight = PlacementData.fHalfHeight + PORTAL_HOLE_HALF_HEIGHT_MOD + PORTAL_WALL_MIN_THICKNESS;
  885. Vector vTransformedForward = matTransform.ApplyRotation( PlacementData.vForward );
  886. Vector vTransformedRight = matTransform.ApplyRotation( PlacementData.vRight );
  887. Vector vTransformedUp = matTransform.ApplyRotation( PlacementData.vUp );
  888. Vector vTransformedCenter = matTransform * PlacementData.ptCenter;
  889. Vector vTransformedDown = -vTransformedUp;
  890. Vector vTransformedLeft = -vTransformedRight;
  891. //forward reverse conventions signify whether the normal is the same direction as m_InternalData.Placement.PortalPlane.m_Normal
  892. float fClipPlane_Forward[4] = { vTransformedForward.x,
  893. vTransformedForward.y,
  894. vTransformedForward.z,
  895. vTransformedForward.Dot( vTransformedCenter ) + PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT };
  896. //fClipPlane_Front is the negated version of fClipPlane_Forward
  897. fClip_Front[0] = -fClipPlane_Forward[0];
  898. fClip_Front[1] = -fClipPlane_Forward[1];
  899. fClip_Front[2] = -fClipPlane_Forward[2];
  900. fClip_Front[3] = -fClipPlane_Forward[3];
  901. memcpy( &fClip_BackTop[0][0], &fClipPlane_Forward[0], sizeof( float ) * 4 );
  902. memcpy( &fClip_BackTop[1][0], &vTransformedDown.x, sizeof( float ) * 3 );
  903. fClip_BackTop[1][3] = vTransformedDown.Dot( vTransformedCenter + (vTransformedUp * fHalfHoleHeight) );
  904. memcpy( &fClip_BackBottom[0][0], &fClipPlane_Forward[0], sizeof( float ) * 4 );
  905. memcpy( &fClip_BackBottom[1][0], &vTransformedUp.x, sizeof( float ) * 3 );
  906. fClip_BackBottom[1][3] = vTransformedUp.Dot( vTransformedCenter + (vTransformedDown * fHalfHoleHeight) );
  907. memcpy( &fClip_BackLeft[0][0], &fClip_BackBottom[0][0], sizeof( float ) * 7 );
  908. fClip_BackLeft[1][3] = vTransformedUp.Dot( vTransformedCenter + (vTransformedUp * fHalfHoleHeight) );
  909. memcpy( &fClip_BackLeft[2][0], &vTransformedDown.x, sizeof( float ) * 3 );
  910. fClip_BackLeft[2][3] = vTransformedDown.Dot( vTransformedCenter + (vTransformedDown * fHalfHoleHeight) );
  911. memcpy( &fClip_BackLeft[3][0], &vTransformedRight.x, sizeof( float ) * 3 );
  912. fClip_BackLeft[3][3] = vTransformedRight.Dot( vTransformedCenter + (vTransformedLeft * fHalfHoleWidth) );
  913. memcpy( &fClip_BackRight[0][0], &fClip_BackLeft[0][0], sizeof( float ) * 12 );
  914. memcpy( &fClip_BackRight[3][0], &vTransformedLeft.x, sizeof( float ) * 3 );
  915. fClip_BackRight[3][3] = vTransformedLeft.Dot( vTransformedCenter + (vTransformedRight * fHalfHoleWidth) );
  916. }
  917. static void CarveEntity( PS_PlacementData_t &PlacementData, PS_SD_Dynamic_CarvedEntities_t &CarvedEntities, PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &CarvedRepresentation )
  918. {
  919. Assert( CarvedRepresentation.pSourceEntity != NULL );
  920. Assert( CarvedRepresentation.pCollide == NULL );
  921. //create the polyhedrons and collideables
  922. ICollideable *pProp = CarvedRepresentation.pSourceEntity->GetCollideable();
  923. VMatrix matCollisionToWorld( pProp->CollisionToWorldTransform() );
  924. VMatrix matWorldToCollision;
  925. MatrixInverseTR( matCollisionToWorld, matWorldToCollision );
  926. SolidType_t solidType = CarvedRepresentation.pSourceEntity->GetSolid();
  927. if( solidType == SOLID_VPHYSICS )
  928. {
  929. vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModelIndex() );
  930. Assert( pCollide != NULL );
  931. if( pCollide != NULL )
  932. {
  933. CPhysConvex *ConvexesArray[1024];
  934. int iConvexCount = 0;
  935. for( int i = 0; i != pCollide->solidCount; ++i )
  936. {
  937. iConvexCount += physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 - iConvexCount );
  938. }
  939. CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex = CarvedEntities.Polyhedrons.Count();
  940. for( int i = 0; i != iConvexCount; ++i )
  941. {
  942. CPolyhedron *pFullPolyhedron = physcollision->PolyhedronFromConvex( ConvexesArray[i], false );
  943. if( pFullPolyhedron != NULL )
  944. {
  945. CarvedEntities.Polyhedrons.AddToTail( pFullPolyhedron );
  946. }
  947. }
  948. CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons = CarvedEntities.Polyhedrons.Count() - CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex;
  949. }
  950. }
  951. else if( solidType == SOLID_BSP )
  952. {
  953. CBrushQuery brushQuery;
  954. //enginetrace->GetBrushesInAABB( vAABBMins, vAABBMaxs, WorldBrushes, MASK_SOLID_BRUSHONLY|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP );
  955. enginetrace->GetBrushesInCollideable( pProp, brushQuery );
  956. //create locally clipped polyhedrons for the world
  957. {
  958. CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex = CarvedEntities.Polyhedrons.Count();
  959. uint32 *pBrushList = brushQuery.Base();
  960. int iBrushCount = brushQuery.Count();
  961. ConvertBrushListToClippedPolyhedronList( pBrushList, iBrushCount, NULL, 0, PORTAL_POLYHEDRON_CUT_EPSILON, &CarvedEntities.Polyhedrons );
  962. CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons = CarvedEntities.Polyhedrons.Count() - CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex;
  963. }
  964. }
  965. CPolyhedron **pPolyhedrons = (CPolyhedron **)stackalloc( sizeof( CPolyhedron * ) * CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons * 5 ); //*5 for front, back left, back right, back top, back bottom.
  966. int iPolyhedronCount = 0;
  967. float fClip_Front[4];
  968. float fClip_BackTop[2][4];
  969. float fClip_BackBottom[2][4];
  970. float fClip_BackLeft[4][4];
  971. float fClip_BackRight[4][4];
  972. SetupEntityPortalHoleCarvePlanes( PlacementData, matWorldToCollision, fClip_Front, fClip_BackTop, fClip_BackBottom, fClip_BackLeft, fClip_BackRight );
  973. for( int i = 0; i != CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons; ++i )
  974. {
  975. CPolyhedron *pUncarvedPolyhedron = CarvedEntities.Polyhedrons[CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex + i];
  976. CPolyhedron *pCarvedPolyhedron;
  977. //clip to in front of the plane, single piece
  978. pCarvedPolyhedron = ClipPolyhedron( pUncarvedPolyhedron, (float *)fClip_Front, 1, PORTAL_POLYHEDRON_CUT_EPSILON );
  979. if( pCarvedPolyhedron != NULL )
  980. {
  981. pPolyhedrons[iPolyhedronCount++] = pCarvedPolyhedron;
  982. }
  983. //4 carves behind the plane to form the pieces around the hole
  984. pCarvedPolyhedron = ClipPolyhedron( pUncarvedPolyhedron, (float *)fClip_BackTop, 2, PORTAL_POLYHEDRON_CUT_EPSILON );
  985. if( pCarvedPolyhedron != NULL )
  986. {
  987. pPolyhedrons[iPolyhedronCount++] = pCarvedPolyhedron;
  988. }
  989. pCarvedPolyhedron = ClipPolyhedron( pUncarvedPolyhedron, (float *)fClip_BackBottom, 2, PORTAL_POLYHEDRON_CUT_EPSILON );
  990. if( pCarvedPolyhedron != NULL )
  991. {
  992. pPolyhedrons[iPolyhedronCount++] = pCarvedPolyhedron;
  993. }
  994. pCarvedPolyhedron = ClipPolyhedron( pUncarvedPolyhedron, (float *)fClip_BackLeft, 4, PORTAL_POLYHEDRON_CUT_EPSILON );
  995. if( pCarvedPolyhedron != NULL )
  996. {
  997. pPolyhedrons[iPolyhedronCount++] = pCarvedPolyhedron;
  998. }
  999. pCarvedPolyhedron = ClipPolyhedron( pUncarvedPolyhedron, (float *)fClip_BackRight, 4, PORTAL_POLYHEDRON_CUT_EPSILON );
  1000. if( pCarvedPolyhedron != NULL )
  1001. {
  1002. pPolyhedrons[iPolyhedronCount++] = pCarvedPolyhedron;
  1003. }
  1004. }
  1005. CarvedRepresentation.CarvedPolyhedronGroup.iStartIndex = CarvedEntities.Polyhedrons.Count();
  1006. if( iPolyhedronCount != 0 )
  1007. {
  1008. CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons = iPolyhedronCount;
  1009. CarvedEntities.Polyhedrons.AddMultipleToTail( iPolyhedronCount, pPolyhedrons );
  1010. }
  1011. else
  1012. {
  1013. CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons = 0;
  1014. }
  1015. }
  1016. static void DestroyCollideable( CPhysCollide **ppCollide )
  1017. {
  1018. if ( *ppCollide )
  1019. {
  1020. #if defined( GAME_DLL )
  1021. physenv->DestroyCollideOnDeadObjectFlush( *ppCollide );
  1022. #else
  1023. physcollision->DestroyCollide( *ppCollide );
  1024. #endif
  1025. *ppCollide = NULL;
  1026. }
  1027. }
  1028. void CPortalSimulator::AddCarvedEntity( CBaseEntity *pEntity )
  1029. {
  1030. PS_SD_Dynamic_CarvedEntities_t &CarvedEntities = m_InternalData.Simulation.Dynamic.CarvedEntities;
  1031. //make sure it's not already in the list
  1032. int iCarvedEntityCount = CarvedEntities.CarvedRepresentations.Count();
  1033. for( int i = 0; i != iCarvedEntityCount; ++i )
  1034. {
  1035. if( CarvedEntities.CarvedRepresentations[i].pSourceEntity == pEntity )
  1036. {
  1037. Assert( IsEntityCarvedByPortal( pEntity->entindex() ) );
  1038. return;
  1039. }
  1040. }
  1041. Assert( !IsEntityCarvedByPortal( pEntity->entindex() ) );
  1042. int iEntIndex = pEntity->entindex();
  1043. int iArrayIndex = iEntIndex / 32;
  1044. m_InternalData.Simulation.Dynamic.HasCarvedVersionOfEntity[iArrayIndex] |= (1 << (iEntIndex - (iArrayIndex * 32)));
  1045. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &CarvedRepresentation = CarvedEntities.CarvedRepresentations[CarvedEntities.CarvedRepresentations.AddToTail()];
  1046. CarvedRepresentation.pSourceEntity = pEntity;
  1047. CarvedRepresentation.pCollide = NULL;
  1048. #ifndef CLIENT_DLL
  1049. CarvedRepresentation.pPhysicsObject = NULL;
  1050. #endif
  1051. CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex = 0;
  1052. CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons = 0;
  1053. CarvedRepresentation.CarvedPolyhedronGroup.iStartIndex = 0;
  1054. CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons = 0;
  1055. #ifndef CLIENT_DLL
  1056. //we don't clone entities that we carve
  1057. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_CLONES_ENTITY_FROM_MAIN;
  1058. #endif
  1059. convertconvexparams_t params;
  1060. params.Defaults();
  1061. params.buildOptimizedTraceTables = true;
  1062. params.bUseFastApproximateInertiaTensor = true;
  1063. //some immediate setup may be required
  1064. if( IsCollisionGenerationEnabled() && m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists )
  1065. {
  1066. CarveEntity( m_InternalData.Placement, CarvedEntities, CarvedRepresentation );
  1067. if( CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons != 0 )
  1068. {
  1069. CPolyhedron **ppPolyhedrons = CarvedEntities.Polyhedrons.Base() + CarvedRepresentation.CarvedPolyhedronGroup.iStartIndex;
  1070. CPhysConvex **pCarvedConvexes = (CPhysConvex **)stackalloc( sizeof( CPhysConvex * ) * CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons );
  1071. for( int i = 0; i != CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons; ++i )
  1072. {
  1073. pCarvedConvexes[i] = physcollision->ConvexFromConvexPolyhedron( *ppPolyhedrons[i] );
  1074. Assert( pCarvedConvexes[i] != NULL );
  1075. }
  1076. CarvedRepresentation.pCollide = physcollision->ConvertConvexToCollideParams( pCarvedConvexes, CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons, params );
  1077. Assert( CarvedRepresentation.pCollide != NULL );
  1078. #ifndef CLIENT_DLL
  1079. if( CarvedRepresentation.pCollide && IsSimulatingVPhysics() && m_InternalData.Simulation.Dynamic.CarvedEntities.bPhysicsExists )
  1080. {
  1081. ICollideable *pProp = CarvedRepresentation.pSourceEntity->GetCollideable();
  1082. // Create the physics object
  1083. objectparams_t params = g_PhysDefaultObjectParams;
  1084. params.pGameData = m_InternalData.Simulation.hCollisionEntity;
  1085. //add to the collision entity
  1086. //CarvedRepresentation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObject( CarvedRepresentation.pCollide, physprops->GetSurfaceIndex( "default" ), pProp->GetCollisionOrigin(), pProp->GetCollisionAngles(), &params );
  1087. CarvedRepresentation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( CarvedRepresentation.pCollide, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, pProp->GetCollisionOrigin(), pProp->GetCollisionAngles(), &params );
  1088. }
  1089. #endif
  1090. }
  1091. }
  1092. }
  1093. void CPortalSimulator::ReleaseCarvedEntity( CBaseEntity *pEntity )
  1094. {
  1095. PS_SD_Dynamic_CarvedEntities_t &CarvedEntities = m_InternalData.Simulation.Dynamic.CarvedEntities;
  1096. if( !IsEntityCarvedByPortal( pEntity->entindex() ) )
  1097. return;
  1098. int iCarvedEntityCount = CarvedEntities.CarvedRepresentations.Count();
  1099. for( int i = 0; i != iCarvedEntityCount; ++i )
  1100. {
  1101. if( CarvedEntities.CarvedRepresentations[i].pSourceEntity == pEntity )
  1102. {
  1103. //found it, kill it
  1104. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &CarvedRepresentation = CarvedEntities.CarvedRepresentations[i];
  1105. #ifndef CLIENT_DLL
  1106. if( CarvedRepresentation.pPhysicsObject != NULL )
  1107. {
  1108. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( CarvedRepresentation.pPhysicsObject );
  1109. CarvedRepresentation.pPhysicsObject = NULL;
  1110. }
  1111. #endif
  1112. DestroyCollideable( &CarvedRepresentation.pCollide );
  1113. if( (CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons != 0) || (CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons != 0) )
  1114. {
  1115. int iStart = CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex;
  1116. Assert( (CarvedRepresentation.UncarvedPolyhedronGroup.iStartIndex + CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons) == CarvedRepresentation.CarvedPolyhedronGroup.iStartIndex ); //We assume the groups are back to back
  1117. int iPolyhedronCount = CarvedRepresentation.UncarvedPolyhedronGroup.iNumPolyhedrons + CarvedRepresentation.CarvedPolyhedronGroup.iNumPolyhedrons;
  1118. for( int j = 0; j != iPolyhedronCount; ++j )
  1119. {
  1120. CarvedEntities.Polyhedrons[j + iStart]->Release();
  1121. }
  1122. CarvedEntities.Polyhedrons.RemoveMultiple( iStart, iPolyhedronCount );
  1123. for( int j = 0; j != iCarvedEntityCount; ++j )
  1124. {
  1125. //shift every polyhedron group's start index to cover up the hole we just made. This invalidates our own start indices
  1126. CarvedEntities.CarvedRepresentations[j].UncarvedPolyhedronGroup.iStartIndex -= iPolyhedronCount;
  1127. CarvedEntities.CarvedRepresentations[j].CarvedPolyhedronGroup.iStartIndex -= iPolyhedronCount;
  1128. }
  1129. }
  1130. CarvedEntities.CarvedRepresentations.FastRemove( i );
  1131. int iEntIndex = pEntity->entindex();
  1132. int iArrayIndex = iEntIndex / 32;
  1133. m_InternalData.Simulation.Dynamic.HasCarvedVersionOfEntity[iArrayIndex] &= ~(1 << (iEntIndex - (iArrayIndex * 32)));
  1134. #ifndef CLIENT_DLL
  1135. if( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Find( pEntity ) != m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.InvalidIndex() )
  1136. {
  1137. //re-enabled cloning since we've stopped carving
  1138. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_CLONES_ENTITY_FROM_MAIN;
  1139. }
  1140. #endif
  1141. break;
  1142. }
  1143. }
  1144. }
  1145. bool CPortalSimulator::IsEntityCarvedByPortal( int iEntIndex ) const
  1146. {
  1147. if( iEntIndex < 0 )
  1148. return false;
  1149. Assert( (iEntIndex >= 0) && (iEntIndex < MAX_EDICTS) );
  1150. int iArrayIndex = iEntIndex / 32;
  1151. return (m_InternalData.Simulation.Dynamic.HasCarvedVersionOfEntity[iArrayIndex] & (1 << (iEntIndex - (iArrayIndex * 32)))) != 0;
  1152. }
  1153. CPhysCollide *CPortalSimulator::GetCollideForCarvedEntity( CBaseEntity *pEntity ) const
  1154. {
  1155. Assert( pEntity != NULL );
  1156. if( (m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists == false) || (m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count() == 0) )
  1157. return NULL;
  1158. CUtlVector<PS_SD_Dynamic_CarvedEntities_CarvedEntity_t> const &CarvedRepresentations = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations;
  1159. int iCarvedEntityCount = CarvedRepresentations.Count();
  1160. const PS_SD_Dynamic_CarvedEntities_CarvedEntity_t * pCarvedEntities = CarvedRepresentations.Base();
  1161. for( int i = 0; i != iCarvedEntityCount; ++i )
  1162. {
  1163. if( pCarvedEntities[i].pSourceEntity == pEntity )
  1164. {
  1165. return pCarvedEntities[i].pCollide;
  1166. }
  1167. }
  1168. return NULL;
  1169. }
  1170. void CPortalSimulator::SetCarvedParent( CBaseEntity *pPortalPlacementParent )
  1171. {
  1172. CBaseEntity *pExistingParent = m_InternalData.Placement.hPortalPlacementParent.Get();
  1173. if( pPortalPlacementParent == pExistingParent )
  1174. return;
  1175. m_InternalData.Placement.hPortalPlacementParent = pPortalPlacementParent;
  1176. if( pExistingParent != NULL )
  1177. {
  1178. ReleaseCarvedEntity( pExistingParent );
  1179. }
  1180. if( pPortalPlacementParent )
  1181. {
  1182. AddCarvedEntity( pPortalPlacementParent );
  1183. }
  1184. bool bOldIsShrunk = m_InternalData.Placement.bParentIsVPhysicsSolidBrush;
  1185. if( pPortalPlacementParent && (pPortalPlacementParent->GetSolid() == SOLID_VPHYSICS) )
  1186. {
  1187. const model_t *pModel = pPortalPlacementParent->GetModel();
  1188. m_InternalData.Placement.bParentIsVPhysicsSolidBrush = pModel && ((modtype_t)modelinfo->GetModelType( pModel ) == mod_brush);
  1189. }
  1190. else
  1191. {
  1192. m_InternalData.Placement.bParentIsVPhysicsSolidBrush = false;
  1193. }
  1194. #if 1
  1195. //if the entity is a brush model using SOLID_VPHYSICS then it's model is actually half an inch smaller than the brushes on all sides! See usage of VPHYSICS_SHRINK in utils\vbsp\ivp.cpp
  1196. //TODO: instead of assuming this shrinkage exists, encode it in the map somehow. We can't just blindly go with the brush geometry because the collision will be wrong, and we can't
  1197. // blindly go with the collision geometry because the portal will be behind the rendering surface of the brush. Need to be actively aware of the discrepancy.
  1198. {
  1199. if( bOldIsShrunk != m_InternalData.Placement.bParentIsVPhysicsSolidBrush )
  1200. {
  1201. //recarve the tube collideable
  1202. for( int i = 0; i != m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count(); ++i )
  1203. {
  1204. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons[i]->Release();
  1205. }
  1206. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.RemoveAll();
  1207. #if defined( GAME_DLL )
  1208. bool bHadPhysObject = false;
  1209. bool bWasCollisionEntPhys = false;
  1210. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject != NULL )
  1211. {
  1212. bHadPhysObject = true;
  1213. if( m_InternalData.Simulation.hCollisionEntity &&
  1214. (m_InternalData.Simulation.hCollisionEntity->VPhysicsGetObject() == m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject) )
  1215. {
  1216. bWasCollisionEntPhys = true;
  1217. m_InternalData.Simulation.hCollisionEntity->VPhysicsSetObject( NULL );
  1218. }
  1219. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject );
  1220. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject = NULL;
  1221. }
  1222. #endif
  1223. CreateTubePolyhedrons();
  1224. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable != NULL )
  1225. {
  1226. DestroyCollideable( &m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable );
  1227. if( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() != 0 )
  1228. {
  1229. 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() );
  1230. }
  1231. }
  1232. #if defined( GAME_DLL )
  1233. if( bHadPhysObject )
  1234. {
  1235. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable != NULL )
  1236. {
  1237. //int iDefaultSurfaceIndex = physprops->GetSurfaceIndex( "default" );
  1238. objectparams_t params = g_PhysDefaultObjectParams;
  1239. // Any non-moving object can point to world safely-- Make sure we dont use 'params' for something other than that beyond this point.
  1240. if( m_InternalData.Simulation.hCollisionEntity )
  1241. {
  1242. params.pGameData = m_InternalData.Simulation.hCollisionEntity;
  1243. }
  1244. else
  1245. {
  1246. params.pGameData = GetWorldEntity();
  1247. }
  1248. 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 );
  1249. if( bWasCollisionEntPhys )
  1250. {
  1251. m_InternalData.Simulation.hCollisionEntity->VPhysicsSetObject(m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject);
  1252. }
  1253. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1254. }
  1255. }
  1256. #endif
  1257. }
  1258. }
  1259. #endif
  1260. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS )
  1261. if( sv_dump_portalsimulator_collision.GetBool() )
  1262. {
  1263. const char *szFileName = "pscd_" s_szDLLName "_carvedparent.txt";
  1264. filesystem->RemoveFile( szFileName );
  1265. DumpActiveCollision( this, szFileName );
  1266. if( m_pLinkedPortal )
  1267. {
  1268. szFileName = "pscd_" s_szDLLName "_linked_carvedparent.txt";
  1269. filesystem->RemoveFile( szFileName );
  1270. DumpActiveCollision( m_pLinkedPortal, szFileName );
  1271. }
  1272. }
  1273. #endif
  1274. }
  1275. void CPortalSimulator::ClearEverything( void )
  1276. {
  1277. CREATEDEBUGTIMER( functionTimer );
  1278. STARTDEBUGTIMER( functionTimer );
  1279. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::Clear() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1280. INCREMENTTABSPACING();
  1281. #ifndef CLIENT_DLL
  1282. ClearAllPhysics();
  1283. #endif
  1284. ClearAllCollision();
  1285. ClearPolyhedrons();
  1286. ReleaseAllEntityOwnership();
  1287. #ifndef CLIENT_DLL
  1288. Assert( (m_InternalData.Simulation.hCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.hCollisionEntity) );
  1289. #endif
  1290. STOPDEBUGTIMER( functionTimer );
  1291. DECREMENTTABSPACING();
  1292. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::Clear() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1293. }
  1294. void CPortalSimulator::AttachTo( CPortalSimulator *pLinkedPortalSimulator )
  1295. {
  1296. Assert( pLinkedPortalSimulator );
  1297. if( pLinkedPortalSimulator == m_pLinkedPortal )
  1298. return;
  1299. CREATEDEBUGTIMER( functionTimer );
  1300. STARTDEBUGTIMER( functionTimer );
  1301. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::AttachTo() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1302. INCREMENTTABSPACING();
  1303. DetachFromLinked();
  1304. m_pLinkedPortal = pLinkedPortalSimulator;
  1305. pLinkedPortalSimulator->m_pLinkedPortal = this;
  1306. if( m_bLocalDataIsReady && m_pLinkedPortal->m_bLocalDataIsReady )
  1307. {
  1308. UpdateLinkMatrix();
  1309. CreateLinkedCollision();
  1310. #ifndef CLIENT_DLL
  1311. CreateLinkedPhysics();
  1312. #endif
  1313. }
  1314. #if defined( DEBUG_PORTAL_COLLISION_ENVIRONMENTS )
  1315. if( sv_dump_portalsimulator_collision.GetBool() )
  1316. {
  1317. const char *szFileName = "pscd_" s_szDLLName ".txt";
  1318. filesystem->RemoveFile( szFileName );
  1319. DumpActiveCollision( this, szFileName );
  1320. if( m_pLinkedPortal )
  1321. {
  1322. szFileName = "pscd_" s_szDLLName "_linked.txt";
  1323. filesystem->RemoveFile( szFileName );
  1324. DumpActiveCollision( m_pLinkedPortal, szFileName );
  1325. }
  1326. }
  1327. #endif
  1328. STOPDEBUGTIMER( functionTimer );
  1329. DECREMENTTABSPACING();
  1330. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::AttachTo() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1331. }
  1332. void CPortalSimulator::TakeOwnershipOfEntity( CBaseEntity *pEntity )
  1333. {
  1334. AssertMsg( m_bLocalDataIsReady, "Tell the portal simulator where it is with MoveTo() before using it in any other way." );
  1335. Assert( pEntity != NULL );
  1336. if( pEntity == NULL )
  1337. return;
  1338. if( pEntity->entindex() < 0 )
  1339. return;
  1340. if( pEntity->IsWorld() )
  1341. return;
  1342. #if defined( GAME_DLL )
  1343. if( CPhysicsShadowClone::IsShadowClone( pEntity ) )
  1344. return;
  1345. 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
  1346. return;
  1347. #endif
  1348. if( OwnsEntity( pEntity ) )
  1349. return;
  1350. Assert( GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  1351. MarkAsOwned( pEntity );
  1352. Assert( GetSimulatorThatOwnsEntity( pEntity ) == this );
  1353. if( EntityIsInPortalHole( pEntity ) )
  1354. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] |= PSEF_IS_IN_PORTAL_HOLE;
  1355. else
  1356. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_IS_IN_PORTAL_HOLE;
  1357. #if defined( GAME_DLL )
  1358. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] );
  1359. #endif
  1360. m_pCallbacks->PortalSimulator_TookOwnershipOfEntity( pEntity );
  1361. #if defined( GAME_DLL )
  1362. if( IsSimulatingVPhysics() )
  1363. TakePhysicsOwnership( pEntity );
  1364. #endif
  1365. pEntity->CollisionRulesChanged(); //absolutely necessary in single-environment mode, possibly expendable in multi-environment moder
  1366. //pEntity->SetGroundEntity( NULL );
  1367. IPhysicsObject *pObject = pEntity->VPhysicsGetObject();
  1368. if( pObject )
  1369. {
  1370. pObject->Wake();
  1371. pObject->RecheckContactPoints();
  1372. }
  1373. CUtlVector<CBaseEntity *> childrenList;
  1374. GetAllChildren( pEntity, childrenList );
  1375. for ( int i = childrenList.Count(); --i >= 0; )
  1376. {
  1377. CBaseEntity *pEnt = childrenList[i];
  1378. CPortalSimulator *pOwningSimulator = GetSimulatorThatOwnsEntity( pEnt );
  1379. if( pOwningSimulator != this )
  1380. {
  1381. if( pOwningSimulator != NULL )
  1382. pOwningSimulator->ReleaseOwnershipOfEntity( pEnt, (pOwningSimulator == m_pLinkedPortal) );
  1383. TakeOwnershipOfEntity( childrenList[i] );
  1384. }
  1385. }
  1386. }
  1387. void RecheckEntityCollision( CBaseEntity *pEntity )
  1388. {
  1389. CCallQueue *pCallQueue;
  1390. if ( (pCallQueue = GetPortalCallQueue()) != NULL )
  1391. {
  1392. pCallQueue->QueueCall( RecheckEntityCollision, pEntity );
  1393. return;
  1394. }
  1395. pEntity->CollisionRulesChanged(); //absolutely necessary in single-environment mode, possibly expendable in multi-environment mode
  1396. //pEntity->SetGroundEntity( NULL );
  1397. IPhysicsObject *pObject = pEntity->VPhysicsGetObject();
  1398. if( pObject )
  1399. {
  1400. pObject->Wake();
  1401. pObject->RecheckContactPoints();
  1402. }
  1403. }
  1404. void CPortalSimulator::ReleaseOwnershipOfEntity( CBaseEntity *pEntity, bool bMovingToLinkedSimulator /*= false*/ )
  1405. {
  1406. if( pEntity == NULL )
  1407. return;
  1408. if( pEntity->IsWorld() )
  1409. return;
  1410. if( !OwnsEntity( pEntity ) )
  1411. return;
  1412. #if defined( GAME_DLL )
  1413. if( m_InternalData.Simulation.pPhysicsEnvironment )
  1414. ReleasePhysicsOwnership( pEntity, true, bMovingToLinkedSimulator );
  1415. #endif
  1416. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_IS_IN_PORTAL_HOLE;
  1417. #if defined( GAME_DLL )
  1418. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] );
  1419. #endif
  1420. Assert( GetSimulatorThatOwnsEntity( pEntity ) == this );
  1421. MarkAsReleased( pEntity );
  1422. Assert( GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  1423. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1424. {
  1425. if( m_InternalData.Simulation.Dynamic.OwnedEntities[i] == pEntity )
  1426. {
  1427. m_InternalData.Simulation.Dynamic.OwnedEntities.FastRemove(i);
  1428. break;
  1429. }
  1430. }
  1431. if( bMovingToLinkedSimulator == false )
  1432. {
  1433. RecheckEntityCollision( pEntity );
  1434. }
  1435. m_pCallbacks->PortalSimulator_ReleasedOwnershipOfEntity( pEntity );
  1436. CUtlVector<CBaseEntity *> childrenList;
  1437. GetAllChildren( pEntity, childrenList );
  1438. for ( int i = childrenList.Count(); --i >= 0; )
  1439. ReleaseOwnershipOfEntity( childrenList[i], bMovingToLinkedSimulator );
  1440. }
  1441. void CPortalSimulator::ReleaseAllEntityOwnership( void )
  1442. {
  1443. //Assert( m_bLocalDataIsReady || (m_InternalData.Simulation.Dynamic.OwnedEntities.Count() == 0) );
  1444. int iSkippedObjects = 0;
  1445. while( m_InternalData.Simulation.Dynamic.OwnedEntities.Count() != iSkippedObjects ) //the release function changes OwnedEntities
  1446. {
  1447. CBaseEntity *pEntity = m_InternalData.Simulation.Dynamic.OwnedEntities[iSkippedObjects];
  1448. #if defined( GAME_DLL )
  1449. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity )
  1450. || CPhysicsShadowClone::IsShadowClone( pEntity ) )
  1451. {
  1452. ++iSkippedObjects;
  1453. continue;
  1454. }
  1455. #endif
  1456. RemoveEntityFromPortalHole( pEntity ); //assume that whenever someone wants to release all entities, it's because the portal is going away
  1457. ReleaseOwnershipOfEntity( pEntity );
  1458. }
  1459. #if defined( GAME_DLL )
  1460. //HACK: should probably separate out these releases of cloned objects. But the calling pattern is identical to outside code for now and the leafy bits are a bit too leafy for this late of a change
  1461. int iReleaseClonedEnts = m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.Count();
  1462. if( iReleaseClonedEnts != 0 )
  1463. {
  1464. CBaseEntity **pReleaseEnts = (CBaseEntity **)stackalloc( sizeof( CBaseEntity * ) * iReleaseClonedEnts );
  1465. memcpy( pReleaseEnts, m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.Base(), sizeof( CBaseEntity * ) * iReleaseClonedEnts );
  1466. for( int i = iReleaseClonedEnts; --i >= 0; )
  1467. {
  1468. StopCloningEntityAcrossPortals( pReleaseEnts[i] );
  1469. }
  1470. }
  1471. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.Count() == 0 );
  1472. Assert( (m_InternalData.Simulation.hCollisionEntity == NULL) || OwnsEntity(m_InternalData.Simulation.hCollisionEntity) );
  1473. #endif
  1474. }
  1475. void CPortalSimulator::MarkAsOwned( CBaseEntity *pEntity )
  1476. {
  1477. Assert( pEntity != NULL );
  1478. int iEntIndex = pEntity->entindex();
  1479. Assert( s_OwnedEntityMap[iEntIndex] == NULL );
  1480. #ifdef _DEBUG
  1481. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1482. Assert( m_InternalData.Simulation.Dynamic.OwnedEntities[i] != pEntity );
  1483. #endif
  1484. Assert( (m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY) == 0 );
  1485. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_OWNS_ENTITY;
  1486. s_OwnedEntityMap[iEntIndex] = this;
  1487. m_InternalData.Simulation.Dynamic.OwnedEntities.AddToTail( pEntity );
  1488. }
  1489. void CPortalSimulator::MarkAsReleased( CBaseEntity *pEntity )
  1490. {
  1491. Assert( pEntity != NULL );
  1492. int iEntIndex = pEntity->entindex();
  1493. Assert( s_OwnedEntityMap[iEntIndex] == this );
  1494. #if defined( GAME_DLL )
  1495. Assert( ((m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY) != 0) || CPSCollisionEntity::IsPortalSimulatorCollisionEntity(pEntity) );
  1496. #else
  1497. Assert( (m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] & PSEF_OWNS_ENTITY) != 0 );
  1498. #endif
  1499. s_OwnedEntityMap[iEntIndex] = NULL;
  1500. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_OWNS_ENTITY;
  1501. int i;
  1502. for( i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1503. {
  1504. if( m_InternalData.Simulation.Dynamic.OwnedEntities[i] == pEntity )
  1505. {
  1506. m_InternalData.Simulation.Dynamic.OwnedEntities.FastRemove(i);
  1507. break;
  1508. }
  1509. }
  1510. Assert( i >= 0 );
  1511. }
  1512. #ifndef CLIENT_DLL
  1513. void CPortalSimulator::TakePhysicsOwnership( CBaseEntity *pEntity )
  1514. {
  1515. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  1516. return;
  1517. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  1518. return;
  1519. Assert( CPhysicsShadowClone::IsShadowClone( pEntity ) == false );
  1520. Assert( OwnsEntity( pEntity ) ); //taking physics ownership happens AFTER general ownership
  1521. if( OwnsPhysicsForEntity( pEntity ) )
  1522. return;
  1523. int iEntIndex = pEntity->entindex();
  1524. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_OWNS_PHYSICS;
  1525. //physics cloning
  1526. {
  1527. #ifdef _DEBUG
  1528. {
  1529. int iDebugIndex;
  1530. for( iDebugIndex = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  1531. {
  1532. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  1533. break;
  1534. }
  1535. AssertMsg( iDebugIndex < 0, "Trying to own an entity, when a clone from the linked portal already exists" );
  1536. if( m_pLinkedPortal )
  1537. {
  1538. for( iDebugIndex = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  1539. {
  1540. if( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  1541. break;
  1542. }
  1543. AssertMsg( iDebugIndex < 0, "Trying to own an entity, when we're already exporting a clone to the linked portal" );
  1544. }
  1545. //Don't require a copy from main to already exist
  1546. }
  1547. #endif
  1548. EHANDLE hEnt = pEntity;
  1549. //To linked portal
  1550. if( m_pLinkedPortal && m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment )
  1551. {
  1552. DBG_CODE(
  1553. for( int i = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1554. AssertMsg( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i]->GetClonedEntity() != pEntity, "Already cloning to linked portal." );
  1555. );
  1556. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::TakePhysicsOwnership(): To Linked Portal", &m_InternalData.Placement.matThisToLinked.As3x4() );
  1557. if( pClone )
  1558. {
  1559. //bool bHeldByPhyscannon = false;
  1560. CBaseEntity *pHeldEntity = NULL;
  1561. CPortal_Player *pPlayer = (CPortal_Player *)GetPlayerHoldingEntity( pEntity );
  1562. if ( !pPlayer && pEntity->IsPlayer() )
  1563. {
  1564. pPlayer = (CPortal_Player *)pEntity;
  1565. }
  1566. if ( pPlayer && !pPlayer->IsUsingVMGrab() )
  1567. {
  1568. pHeldEntity = GetPlayerHeldEntity( pPlayer );
  1569. /*if ( !pHeldEntity )
  1570. {
  1571. pHeldEntity = PhysCannonGetHeldEntity( pPlayer->GetActiveWeapon() );
  1572. bHeldByPhyscannon = true;
  1573. }*/
  1574. if( pHeldEntity )
  1575. {
  1576. //player is holding the entity, force them to pick it back up again
  1577. bool bIsHeldObjectOnOppositeSideOfPortal = pPlayer->IsHeldObjectOnOppositeSideOfPortal();
  1578. pPlayer->m_bSilentDropAndPickup = true;
  1579. pPlayer->ForceDropOfCarriedPhysObjects( pHeldEntity );
  1580. pPlayer->SetHeldObjectOnOppositeSideOfPortal( bIsHeldObjectOnOppositeSideOfPortal );
  1581. }
  1582. }
  1583. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  1584. m_pLinkedPortal->MarkAsOwned( pClone );
  1585. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS;
  1586. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_IS_IN_PORTAL_HOLE;
  1587. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  1588. if( pHeldEntity )
  1589. {
  1590. /*if ( bHeldByPhyscannon )
  1591. {
  1592. PhysCannonPickupObject( pPlayer, pHeldEntity );
  1593. }
  1594. else*/
  1595. {
  1596. PlayerPickupObject( pPlayer, pHeldEntity );
  1597. }
  1598. pPlayer->m_bSilentDropAndPickup = false;
  1599. }
  1600. }
  1601. }
  1602. }
  1603. m_pCallbacks->PortalSimulator_TookPhysicsOwnershipOfEntity( pEntity );
  1604. }
  1605. void CPortalSimulator::ReleasePhysicsOwnership( CBaseEntity *pEntity, bool bContinuePhysicsCloning /*= true*/, bool bMovingToLinkedSimulator /*= false*/ )
  1606. {
  1607. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  1608. return;
  1609. Assert( OwnsEntity( pEntity ) ); //releasing physics ownership happens BEFORE releasing general ownership
  1610. Assert( CPhysicsShadowClone::IsShadowClone( pEntity ) == false );
  1611. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  1612. return;
  1613. if( !OwnsPhysicsForEntity( pEntity ) )
  1614. return;
  1615. if( IsSimulatingVPhysics() == false )
  1616. bContinuePhysicsCloning = false;
  1617. int iEntIndex = pEntity->entindex();
  1618. m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_OWNS_PHYSICS;
  1619. //physics cloning
  1620. {
  1621. #ifdef _DEBUG
  1622. {
  1623. int iDebugIndex;
  1624. for( iDebugIndex = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --iDebugIndex >= 0; )
  1625. {
  1626. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[iDebugIndex]->GetClonedEntity() == pEntity )
  1627. break;
  1628. }
  1629. AssertMsg( iDebugIndex < 0, "Trying to release an entity, when a clone from the linked portal already exists." );
  1630. }
  1631. #endif
  1632. //clear exported clones
  1633. {
  1634. DBG_CODE_NOSCOPE( bool bFoundAlready = false; );
  1635. DBG_CODE_NOSCOPE( const char *szLastFoundMarker = NULL; );
  1636. //to linked portal
  1637. if( m_pLinkedPortal )
  1638. {
  1639. DBG_CODE_NOSCOPE( bFoundAlready = false; );
  1640. for( int i = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1641. {
  1642. if( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i]->GetClonedEntity() == pEntity )
  1643. {
  1644. CPhysicsShadowClone *pClone = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  1645. AssertMsg( bFoundAlready == false, "Multiple clones to linked portal found." );
  1646. DBG_CODE_NOSCOPE( bFoundAlready = true; );
  1647. DBG_CODE_NOSCOPE( szLastFoundMarker = pClone->m_szDebugMarker );
  1648. //bool bHeldByPhyscannon = false;
  1649. CBaseEntity *pHeldEntity = NULL;
  1650. CPortal_Player *pPlayer = (CPortal_Player *)GetPlayerHoldingEntity( pEntity );
  1651. if ( !pPlayer && pEntity->IsPlayer() )
  1652. {
  1653. pPlayer = (CPortal_Player *)pEntity;
  1654. }
  1655. if ( pPlayer && !pPlayer->IsUsingVMGrab() )
  1656. {
  1657. pHeldEntity = GetPlayerHeldEntity( pPlayer );
  1658. /*if ( !pHeldEntity )
  1659. {
  1660. pHeldEntity = PhysCannonGetHeldEntity( pPlayer->GetActiveWeapon() );
  1661. bHeldByPhyscannon = true;
  1662. }*/
  1663. if( pHeldEntity )
  1664. {
  1665. //player is holding the entity, force them to pick it back up again
  1666. bool bIsHeldObjectOnOppositeSideOfPortal = pPlayer->IsHeldObjectOnOppositeSideOfPortal();
  1667. pPlayer->m_bSilentDropAndPickup = true;
  1668. pPlayer->ForceDropOfCarriedPhysObjects( pHeldEntity );
  1669. pPlayer->SetHeldObjectOnOppositeSideOfPortal( bIsHeldObjectOnOppositeSideOfPortal );
  1670. }
  1671. else
  1672. {
  1673. pHeldEntity = NULL;
  1674. }
  1675. }
  1676. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  1677. m_pLinkedPortal->MarkAsReleased( pClone );
  1678. pClone->Free();
  1679. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.FastRemove(i);
  1680. if( pHeldEntity )
  1681. {
  1682. /*if ( bHeldByPhyscannon )
  1683. {
  1684. PhysCannonPickupObject( pPlayer, pHeldEntity );
  1685. }
  1686. else*/
  1687. {
  1688. PlayerPickupObject( pPlayer, pHeldEntity );
  1689. }
  1690. pPlayer->m_bSilentDropAndPickup = false;
  1691. }
  1692. DBG_CODE_NOSCOPE( continue; );
  1693. break;
  1694. }
  1695. }
  1696. }
  1697. }
  1698. }
  1699. m_pCallbacks->PortalSimulator_ReleasedPhysicsOwnershipOfEntity( pEntity );
  1700. }
  1701. void CPortalSimulator::StartCloningEntityFromMain( CBaseEntity *pEntity )
  1702. {
  1703. if( CPhysicsShadowClone::IsShadowClone( pEntity ) || CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  1704. return;
  1705. if( (m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_FROM_MAIN) != 0 )
  1706. return; //already cloned, no work to do
  1707. #ifdef _DEBUG
  1708. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Count(); --i >= 0; )
  1709. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain[i] != pEntity );
  1710. #endif
  1711. //NDebugOverlay::EntityBounds( pEntity, 0, 255, 0, 50, 5.0f );
  1712. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.AddToTail( pEntity );
  1713. if( !IsEntityCarvedByPortal( pEntity ) )
  1714. {
  1715. //only set the flag to clone if we're not currently carving. We'll still hold it in the ShouldCloneFromMain list in case we stop carving it
  1716. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] |= PSEF_CLONES_ENTITY_FROM_MAIN;
  1717. }
  1718. pEntity->CollisionRulesChanged();
  1719. }
  1720. void CPortalSimulator::StopCloningEntityFromMain( CBaseEntity *pEntity )
  1721. {
  1722. if( ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_FROM_MAIN) == 0) && !IsEntityCarvedByPortal( pEntity ) )
  1723. {
  1724. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.Find( pEntity ) == -1 );
  1725. return; //not cloned, no work to do
  1726. }
  1727. //NDebugOverlay::EntityBounds( pEntity, 255, 0, 0, 50, 5.0f );
  1728. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneFromMain.FindAndFastRemove( pEntity );
  1729. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_CLONES_ENTITY_FROM_MAIN;
  1730. pEntity->CollisionRulesChanged();
  1731. }
  1732. void CPortalSimulator::StartCloningEntityAcrossPortals( CBaseEntity *pEntity )
  1733. {
  1734. if( CPhysicsShadowClone::IsShadowClone( pEntity ) || CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) )
  1735. return;
  1736. if( (m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_ACROSS_PORTAL_FROM_MAIN) != 0 )
  1737. return; //already cloned, no work to do
  1738. #ifdef _DEBUG
  1739. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.Count(); --i >= 0; )
  1740. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal[i] != pEntity );
  1741. #endif
  1742. //NDebugOverlay::EntityBounds( pEntity, 0, 255, 0, 50, 5.0f );
  1743. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.AddToTail( pEntity );
  1744. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] |= PSEF_CLONES_ENTITY_ACROSS_PORTAL_FROM_MAIN;
  1745. //push the clone now
  1746. if( m_pLinkedPortal && m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment && m_pLinkedPortal->m_CreationChecklist.bLinkedPhysicsGenerated )
  1747. {
  1748. EHANDLE hEnt = pEntity;
  1749. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_pLinkedPortal->m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::StartCloningEntityAcrossPortals(): To Linked Portal", &m_InternalData.Placement.matThisToLinked.As3x4() );
  1750. if( pClone )
  1751. {
  1752. m_pLinkedPortal->MarkAsOwned( pClone );
  1753. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS | (m_InternalData.Simulation.Dynamic.EntFlags[hEnt->entindex()] & PSEF_IS_IN_PORTAL_HOLE);
  1754. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  1755. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  1756. }
  1757. }
  1758. }
  1759. void CPortalSimulator::StopCloningEntityAcrossPortals( CBaseEntity *pEntity )
  1760. {
  1761. if( ((m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] & PSEF_CLONES_ENTITY_ACROSS_PORTAL_FROM_MAIN) == 0) )
  1762. {
  1763. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.Find( pEntity ) == -1 );
  1764. return; //not cloned, no work to do
  1765. }
  1766. //NDebugOverlay::EntityBounds( pEntity, 255, 0, 0, 50, 5.0f );
  1767. m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal.FindAndFastRemove( pEntity );
  1768. m_InternalData.Simulation.Dynamic.EntFlags[pEntity->entindex()] &= ~PSEF_CLONES_ENTITY_ACROSS_PORTAL_FROM_MAIN;
  1769. //clear exported clones
  1770. if( m_pLinkedPortal )
  1771. {
  1772. for( int i = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  1773. {
  1774. if( m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i]->GetClonedEntity() == pEntity )
  1775. {
  1776. CPhysicsShadowClone *pClone = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  1777. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  1778. m_pLinkedPortal->MarkAsReleased( pClone );
  1779. pClone->Free();
  1780. m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.FastRemove(i);
  1781. break;
  1782. }
  1783. }
  1784. }
  1785. }
  1786. /*void CPortalSimulator::TeleportEntityToLinkedPortal( CBaseEntity *pEntity )
  1787. {
  1788. //TODO: migrate teleportation code from CPortal_Base2D::Touch to here
  1789. }*/
  1790. void CPortalSimulator::CreateAllPhysics( void )
  1791. {
  1792. if( IsSimulatingVPhysics() == false )
  1793. return;
  1794. CREATEDEBUGTIMER( functionTimer );
  1795. STARTDEBUGTIMER( functionTimer );
  1796. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1797. INCREMENTTABSPACING();
  1798. CreateMinimumPhysics();
  1799. CreateLocalPhysics();
  1800. CreateLinkedPhysics();
  1801. STOPDEBUGTIMER( functionTimer );
  1802. DECREMENTTABSPACING();
  1803. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1804. }
  1805. void CPortalSimulator::CreateMinimumPhysics( void )
  1806. {
  1807. if( IsSimulatingVPhysics() == false )
  1808. return;
  1809. if( m_InternalData.Simulation.pPhysicsEnvironment != NULL )
  1810. return;
  1811. CREATEDEBUGTIMER( functionTimer );
  1812. STARTDEBUGTIMER( functionTimer );
  1813. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateMinimumPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1814. INCREMENTTABSPACING();
  1815. m_InternalData.Simulation.pPhysicsEnvironment = physenv_main;
  1816. STOPDEBUGTIMER( functionTimer );
  1817. DECREMENTTABSPACING();
  1818. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateMinimumPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1819. }
  1820. void CPortalSimulator::CreateLocalPhysics( void )
  1821. {
  1822. if( IsSimulatingVPhysics() == false )
  1823. return;
  1824. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create local physics before being placed." );
  1825. if( m_CreationChecklist.bLocalPhysicsGenerated )
  1826. return;
  1827. CREATEDEBUGTIMER( functionTimer );
  1828. STARTDEBUGTIMER( functionTimer );
  1829. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1830. INCREMENTTABSPACING();
  1831. CreateMinimumPhysics();
  1832. //int iDefaultSurfaceIndex = physprops->GetSurfaceIndex( "default" );
  1833. objectparams_t params = g_PhysDefaultObjectParams;
  1834. // Any non-moving object can point to world safely-- Make sure we dont use 'params' for something other than that beyond this point.
  1835. if( m_InternalData.Simulation.hCollisionEntity )
  1836. {
  1837. params.pGameData = m_InternalData.Simulation.hCollisionEntity;
  1838. }
  1839. else
  1840. {
  1841. params.pGameData = GetWorldEntity();
  1842. }
  1843. CPSCollisionEntity *pSetPhysicsObject = NULL;
  1844. if( m_InternalData.Simulation.hCollisionEntity && (m_InternalData.Simulation.hCollisionEntity->VPhysicsGetObject() == NULL) )
  1845. {
  1846. pSetPhysicsObject = m_InternalData.Simulation.hCollisionEntity;
  1847. }
  1848. //World
  1849. {
  1850. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  1851. {
  1852. Assert( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1853. if( (m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable != NULL) &&
  1854. ((m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].iSolidMask & MASK_SOLID_BRUSHONLY) != 0) )
  1855. {
  1856. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  1857. if( pSetPhysicsObject )
  1858. {
  1859. pSetPhysicsObject->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject);
  1860. pSetPhysicsObject = NULL;
  1861. }
  1862. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1863. }
  1864. }
  1865. if( m_InternalData.Simulation.Static.World.Displacements.pCollideable != NULL )
  1866. {
  1867. m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.World.Displacements.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  1868. if( pSetPhysicsObject )
  1869. {
  1870. pSetPhysicsObject->VPhysicsSetObject(m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject);
  1871. pSetPhysicsObject = NULL;
  1872. }
  1873. m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1874. }
  1875. //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
  1876. #ifdef _DEBUG
  1877. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1878. {
  1879. 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
  1880. }
  1881. #endif
  1882. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0 )
  1883. {
  1884. Assert( m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists );
  1885. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  1886. {
  1887. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  1888. Assert( Representation.pCollide != NULL );
  1889. Assert( Representation.pPhysicsObject == NULL );
  1890. Representation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( Representation.pCollide, Representation.iTraceSurfaceProps, vec3_origin, vec3_angle, &params );
  1891. Assert( Representation.pPhysicsObject != NULL );
  1892. if( Representation.pPhysicsObject != NULL )
  1893. {
  1894. Representation.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1895. }
  1896. else
  1897. {
  1898. physcollision->DestroyCollide( Representation.pCollide );
  1899. m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Remove( i );
  1900. }
  1901. }
  1902. }
  1903. m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists = true;
  1904. }
  1905. //Wall
  1906. {
  1907. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  1908. {
  1909. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  1910. if( (m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable != NULL) &&
  1911. ((m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].iSolidMask & MASK_SOLID_BRUSHONLY) != 0) )
  1912. {
  1913. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  1914. if( pSetPhysicsObject )
  1915. {
  1916. pSetPhysicsObject->VPhysicsSetObject(m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject);
  1917. pSetPhysicsObject = NULL;
  1918. }
  1919. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1920. }
  1921. }
  1922. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject == NULL );
  1923. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable != NULL )
  1924. {
  1925. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, vec3_origin, vec3_angle, &params );
  1926. if( pSetPhysicsObject )
  1927. {
  1928. pSetPhysicsObject->VPhysicsSetObject(m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject);
  1929. pSetPhysicsObject = NULL;
  1930. }
  1931. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1932. }
  1933. 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
  1934. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable != NULL )
  1935. {
  1936. 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 );
  1937. if( pSetPhysicsObject )
  1938. {
  1939. pSetPhysicsObject->VPhysicsSetObject(m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject);
  1940. pSetPhysicsObject = NULL;
  1941. }
  1942. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1943. }
  1944. if( m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count() != 0 )
  1945. {
  1946. objectparams_t params = g_PhysDefaultObjectParams;
  1947. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists );
  1948. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  1949. {
  1950. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &Representation = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i];
  1951. if( Representation.pCollide != NULL )
  1952. {
  1953. Assert( Representation.pPhysicsObject == NULL );
  1954. ICollideable *pProp = Representation.pSourceEntity->GetCollideable();
  1955. params.pGameData = m_InternalData.Simulation.hCollisionEntity;
  1956. //add to the collision entity
  1957. //Representation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObject( Representation.pCollide, physprops->GetSurfaceIndex( "default" ), pProp->GetCollisionOrigin(), pProp->GetCollisionAngles(), &params );
  1958. Representation.pPhysicsObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( Representation.pCollide, m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, pProp->GetCollisionOrigin(), pProp->GetCollisionAngles(), &params );
  1959. Assert( Representation.pPhysicsObject != NULL );
  1960. Representation.pPhysicsObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  1961. }
  1962. }
  1963. }
  1964. m_InternalData.Simulation.Dynamic.CarvedEntities.bPhysicsExists = true;
  1965. }
  1966. //re-acquire environment physics for owned entities
  1967. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  1968. TakePhysicsOwnership( m_InternalData.Simulation.Dynamic.OwnedEntities[i] );
  1969. if( m_InternalData.Simulation.hCollisionEntity )
  1970. {
  1971. m_InternalData.Simulation.hCollisionEntity->CollisionRulesChanged();
  1972. }
  1973. STOPDEBUGTIMER( functionTimer );
  1974. DECREMENTTABSPACING();
  1975. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  1976. m_CreationChecklist.bLocalPhysicsGenerated = true;
  1977. }
  1978. void CPortalSimulator::CreateLinkedPhysics( void )
  1979. {
  1980. if( IsSimulatingVPhysics() == false )
  1981. return;
  1982. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create linked physics before being placed itself." );
  1983. if( (m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_bLocalDataIsReady == false) )
  1984. return;
  1985. if( m_CreationChecklist.bLinkedPhysicsGenerated )
  1986. return;
  1987. CREATEDEBUGTIMER( functionTimer );
  1988. STARTDEBUGTIMER( functionTimer );
  1989. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLinkedPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  1990. INCREMENTTABSPACING();
  1991. CreateMinimumPhysics();
  1992. //int iDefaultSurfaceIndex = physprops->GetSurfaceIndex( "default" );
  1993. objectparams_t params = g_PhysDefaultObjectParams;
  1994. if( m_InternalData.Simulation.hCollisionEntity )
  1995. params.pGameData = m_InternalData.Simulation.hCollisionEntity;
  1996. else
  1997. params.pGameData = GetWorldEntity();
  1998. //everything in our linked collision should be based on the linked portal's world collision
  1999. PS_SD_Static_World_t &RemoteSimulationStaticWorld = m_pLinkedPortal->m_InternalData.Simulation.Static.World;
  2000. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects ); ++iBrushSet )
  2001. {
  2002. Assert( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  2003. if( (RemoteSimulationStaticWorld.Brushes.BrushSets[iBrushSet].pCollideable != NULL) &&
  2004. ((RemoteSimulationStaticWorld.Brushes.BrushSets[iBrushSet].iSolidMask & MASK_SOLID_BRUSHONLY) != 0) )
  2005. {
  2006. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( RemoteSimulationStaticWorld.Brushes.BrushSets[iBrushSet].pCollideable, m_pLinkedPortal->m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform, m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, &params );
  2007. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet]->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  2008. }
  2009. }
  2010. 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
  2011. if( RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations.Count() != 0 )
  2012. {
  2013. for( int i = RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2014. {
  2015. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = RemoteSimulationStaticWorld.StaticProps.ClippedRepresentations[i];
  2016. IPhysicsObject *pPhysObject = m_InternalData.Simulation.pPhysicsEnvironment->CreatePolyObjectStatic( Representation.pCollide, Representation.iTraceSurfaceProps, m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform, m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform, &params );
  2017. if( pPhysObject )
  2018. {
  2019. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.AddToTail( pPhysObject );
  2020. pPhysObject->RecheckCollisionFilter(); //some filters only work after the variable is stored in the class
  2021. }
  2022. }
  2023. }
  2024. //re-clone physicsshadowclones from the remote environment
  2025. CUtlVector<CBaseEntity *> &RemoteOwnedEntities = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.OwnedEntities;
  2026. for( int i = RemoteOwnedEntities.Count(); --i >= 0; )
  2027. {
  2028. if( CPhysicsShadowClone::IsShadowClone( RemoteOwnedEntities[i] ) ||
  2029. CPSCollisionEntity::IsPortalSimulatorCollisionEntity( RemoteOwnedEntities[i] ) )
  2030. continue;
  2031. int j;
  2032. for( j = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --j >= 0; )
  2033. {
  2034. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[j]->GetClonedEntity() == RemoteOwnedEntities[i] )
  2035. break;
  2036. }
  2037. if( j >= 0 ) //already cloning
  2038. continue;
  2039. EHANDLE hEnt = RemoteOwnedEntities[i];
  2040. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::CreateLinkedPhysics(): From Linked Portal", &m_InternalData.Placement.matLinkedToThis.As3x4() );
  2041. if( pClone )
  2042. {
  2043. MarkAsOwned( pClone );
  2044. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS | (m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[hEnt->entindex()] & PSEF_IS_IN_PORTAL_HOLE);
  2045. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  2046. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  2047. }
  2048. }
  2049. CUtlVector<CBaseEntity *> &RemoteClonedEntities = m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.ShouldCloneToRemotePortal;
  2050. for( int i = RemoteClonedEntities.Count(); --i >= 0; )
  2051. {
  2052. int j;
  2053. for( j = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --j >= 0; )
  2054. {
  2055. if( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[j]->GetClonedEntity() == RemoteClonedEntities[i] )
  2056. break;
  2057. }
  2058. if( j >= 0 ) //already cloning
  2059. continue;
  2060. EHANDLE hEnt = RemoteClonedEntities[i];
  2061. CPhysicsShadowClone *pClone = CPhysicsShadowClone::CreateShadowClone( m_InternalData.Simulation.pPhysicsEnvironment, hEnt, "CPortalSimulator::CreateLinkedPhysics(): From Linked Portal", &m_InternalData.Placement.matLinkedToThis.As3x4() );
  2062. if( pClone )
  2063. {
  2064. MarkAsOwned( pClone );
  2065. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] |= PSEF_OWNS_PHYSICS | (m_pLinkedPortal->m_InternalData.Simulation.Dynamic.EntFlags[hEnt->entindex()] & PSEF_IS_IN_PORTAL_HOLE);
  2066. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.AddToTail( pClone );
  2067. pClone->CollisionRulesChanged(); //adding the clone to the portal simulator changes how it collides
  2068. }
  2069. }
  2070. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  2071. {
  2072. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  2073. m_bInCrossLinkedFunction = true;
  2074. m_pLinkedPortal->CreateLinkedPhysics();
  2075. m_bInCrossLinkedFunction = false;
  2076. }
  2077. if( m_InternalData.Simulation.hCollisionEntity )
  2078. m_InternalData.Simulation.hCollisionEntity->CollisionRulesChanged();
  2079. STOPDEBUGTIMER( functionTimer );
  2080. DECREMENTTABSPACING();
  2081. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLinkedPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2082. m_CreationChecklist.bLinkedPhysicsGenerated = true;
  2083. }
  2084. void CPortalSimulator::ClearAllPhysics( void )
  2085. {
  2086. CREATEDEBUGTIMER( functionTimer );
  2087. STARTDEBUGTIMER( functionTimer );
  2088. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2089. INCREMENTTABSPACING();
  2090. ClearLinkedPhysics();
  2091. ClearLocalPhysics();
  2092. ClearMinimumPhysics();
  2093. STOPDEBUGTIMER( functionTimer );
  2094. DECREMENTTABSPACING();
  2095. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2096. }
  2097. void CPortalSimulator::ClearMinimumPhysics( void )
  2098. {
  2099. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  2100. return;
  2101. CREATEDEBUGTIMER( functionTimer );
  2102. STARTDEBUGTIMER( functionTimer );
  2103. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearMinimumPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2104. INCREMENTTABSPACING();
  2105. m_InternalData.Simulation.pPhysicsEnvironment = NULL;
  2106. STOPDEBUGTIMER( functionTimer );
  2107. DECREMENTTABSPACING();
  2108. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearMinimumPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2109. }
  2110. void CPortalSimulator::ClearLocalPhysics( void )
  2111. {
  2112. if( m_CreationChecklist.bLocalPhysicsGenerated == false )
  2113. return;
  2114. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  2115. return;
  2116. CREATEDEBUGTIMER( functionTimer );
  2117. STARTDEBUGTIMER( functionTimer );
  2118. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2119. INCREMENTTABSPACING();
  2120. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  2121. 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
  2122. if( m_InternalData.Simulation.hCollisionEntity )
  2123. {
  2124. m_InternalData.Simulation.hCollisionEntity->VPhysicsSetObject( NULL );
  2125. }
  2126. //world brushes
  2127. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  2128. {
  2129. if( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject )
  2130. {
  2131. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject );
  2132. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject = NULL;
  2133. }
  2134. }
  2135. //world displacement surfaces
  2136. if( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject )
  2137. {
  2138. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject );
  2139. m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject = NULL;
  2140. }
  2141. //world static props
  2142. if( m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists &&
  2143. (m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) )
  2144. {
  2145. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2146. {
  2147. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  2148. if( Representation.pPhysicsObject )
  2149. {
  2150. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( Representation.pPhysicsObject );
  2151. Representation.pPhysicsObject = NULL;
  2152. }
  2153. }
  2154. }
  2155. m_InternalData.Simulation.Static.World.StaticProps.bPhysicsExists = false;
  2156. //carved entities
  2157. if( m_InternalData.Simulation.Dynamic.CarvedEntities.bPhysicsExists &&
  2158. (m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count() != 0) )
  2159. {
  2160. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  2161. {
  2162. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &Representation = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i];
  2163. if( Representation.pPhysicsObject )
  2164. {
  2165. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( Representation.pPhysicsObject );
  2166. Representation.pPhysicsObject = NULL;
  2167. }
  2168. }
  2169. }
  2170. m_InternalData.Simulation.Dynamic.CarvedEntities.bPhysicsExists = false;
  2171. //wall brushes
  2172. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  2173. {
  2174. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject )
  2175. {
  2176. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject );
  2177. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject = NULL;
  2178. }
  2179. }
  2180. //clipped func_clip_vphysics
  2181. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject )
  2182. {
  2183. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject );
  2184. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject = NULL;
  2185. }
  2186. //wall tube props
  2187. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject )
  2188. {
  2189. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject );
  2190. m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject = NULL;
  2191. }
  2192. //all physics clones
  2193. {
  2194. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  2195. {
  2196. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  2197. Assert( GetSimulatorThatOwnsEntity( pClone ) == this );
  2198. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  2199. MarkAsReleased( pClone );
  2200. Assert( GetSimulatorThatOwnsEntity( pClone ) == NULL );
  2201. pClone->Free();
  2202. }
  2203. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  2204. }
  2205. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0 );
  2206. //release physics ownership of owned entities
  2207. for( int i = m_InternalData.Simulation.Dynamic.OwnedEntities.Count(); --i >= 0; )
  2208. ReleasePhysicsOwnership( m_InternalData.Simulation.Dynamic.OwnedEntities[i], false );
  2209. Assert( m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0 );
  2210. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  2211. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( false );
  2212. if( m_InternalData.Simulation.hCollisionEntity )
  2213. m_InternalData.Simulation.hCollisionEntity->CollisionRulesChanged();
  2214. STOPDEBUGTIMER( functionTimer );
  2215. DECREMENTTABSPACING();
  2216. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2217. m_CreationChecklist.bLocalPhysicsGenerated = false;
  2218. }
  2219. void CPortalSimulator::ClearLinkedPhysics( void )
  2220. {
  2221. if( m_CreationChecklist.bLinkedPhysicsGenerated == false )
  2222. return;
  2223. if( m_InternalData.Simulation.pPhysicsEnvironment == NULL )
  2224. return;
  2225. CREATEDEBUGTIMER( functionTimer );
  2226. STARTDEBUGTIMER( functionTimer );
  2227. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLinkedPhysics() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2228. INCREMENTTABSPACING();
  2229. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  2230. 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
  2231. //static collideables
  2232. {
  2233. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects ); ++iBrushSet )
  2234. {
  2235. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] )
  2236. {
  2237. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] );
  2238. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] = NULL;
  2239. }
  2240. }
  2241. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count() )
  2242. {
  2243. for( int i = m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count(); --i >= 0; )
  2244. m_InternalData.Simulation.pPhysicsEnvironment->DestroyObject( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects[i] );
  2245. m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.RemoveAll();
  2246. }
  2247. }
  2248. //clones from the linked portal
  2249. {
  2250. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  2251. {
  2252. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  2253. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  2254. MarkAsReleased( pClone );
  2255. pClone->Free();
  2256. }
  2257. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  2258. }
  2259. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  2260. {
  2261. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  2262. m_bInCrossLinkedFunction = true;
  2263. m_pLinkedPortal->ClearLinkedPhysics();
  2264. m_bInCrossLinkedFunction = false;
  2265. }
  2266. Assert( (m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0) &&
  2267. ((m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count() == 0)) );
  2268. m_InternalData.Simulation.pPhysicsEnvironment->CleanupDeleteList();
  2269. m_InternalData.Simulation.pPhysicsEnvironment->SetQuickDelete( false );
  2270. if( m_InternalData.Simulation.hCollisionEntity )
  2271. m_InternalData.Simulation.hCollisionEntity->CollisionRulesChanged();
  2272. STOPDEBUGTIMER( functionTimer );
  2273. DECREMENTTABSPACING();
  2274. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLinkedPhysics() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2275. m_CreationChecklist.bLinkedPhysicsGenerated = false;
  2276. }
  2277. void CPortalSimulator::ClearLinkedEntities( void )
  2278. {
  2279. //clones from the linked portal
  2280. {
  2281. for( int i = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.Count(); --i >= 0; )
  2282. {
  2283. CPhysicsShadowClone *pClone = m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal[i];
  2284. m_InternalData.Simulation.Dynamic.EntFlags[pClone->entindex()] &= ~PSEF_OWNS_PHYSICS;
  2285. MarkAsReleased( pClone );
  2286. pClone->Free();
  2287. }
  2288. m_InternalData.Simulation.Dynamic.ShadowClones.FromLinkedPortal.RemoveAll();
  2289. }
  2290. }
  2291. #endif //#ifndef CLIENT_DLL
  2292. void CPortalSimulator::SetCollisionGenerationEnabled( bool bEnabled )
  2293. {
  2294. if( bEnabled != m_bGenerateCollision )
  2295. {
  2296. m_bGenerateCollision = bEnabled;
  2297. if( bEnabled )
  2298. {
  2299. CreatePolyhedrons();
  2300. CreateAllCollision();
  2301. #ifndef CLIENT_DLL
  2302. CreateAllPhysics();
  2303. #endif
  2304. }
  2305. else
  2306. {
  2307. #ifndef CLIENT_DLL
  2308. ClearAllPhysics();
  2309. #endif
  2310. ClearAllCollision();
  2311. ClearPolyhedrons();
  2312. }
  2313. }
  2314. }
  2315. void CPortalSimulator::CreateAllCollision( void )
  2316. {
  2317. CREATEDEBUGTIMER( functionTimer );
  2318. STARTDEBUGTIMER( functionTimer );
  2319. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2320. INCREMENTTABSPACING();
  2321. CreateLocalCollision();
  2322. CreateLinkedCollision();
  2323. STOPDEBUGTIMER( functionTimer );
  2324. DECREMENTTABSPACING();
  2325. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateAllCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2326. }
  2327. void CPortalSimulator::CreateLocalCollision( void )
  2328. {
  2329. AssertMsg( m_bLocalDataIsReady, "Portal simulator attempting to create local collision before being placed." );
  2330. if( m_CreationChecklist.bLocalCollisionGenerated )
  2331. return;
  2332. if( IsCollisionGenerationEnabled() == false )
  2333. return;
  2334. DEBUGTIMERONLY( s_iPortalSimulatorGUID = GetPortalSimulatorGUID() );
  2335. CREATEDEBUGTIMER( functionTimer );
  2336. STARTDEBUGTIMER( functionTimer );
  2337. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2338. INCREMENTTABSPACING();
  2339. CREATEDEBUGTIMER( worldBrushTimer );
  2340. STARTDEBUGTIMER( worldBrushTimer );
  2341. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  2342. {
  2343. Assert( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  2344. if( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() != 0 )
  2345. {
  2346. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Base(), m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() );
  2347. }
  2348. }
  2349. STOPDEBUGTIMER( worldBrushTimer );
  2350. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldBrushTimer.GetDuration().GetMillisecondsF() ); );
  2351. // Displacements
  2352. if ( portal_clone_displacements.GetBool() )
  2353. {
  2354. VPlane displacementRejectRegions[6];
  2355. displacementRejectRegions[0].m_Normal = -m_InternalData.Placement.vForward;
  2356. displacementRejectRegions[0].m_Dist = displacementRejectRegions[0].m_Normal.Dot( m_InternalData.Placement.ptCenter );
  2357. displacementRejectRegions[1].m_Normal = m_InternalData.Placement.vForward;
  2358. displacementRejectRegions[1].m_Dist = displacementRejectRegions[1].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.x;
  2359. displacementRejectRegions[2].m_Normal = m_InternalData.Placement.vRight;
  2360. displacementRejectRegions[2].m_Dist = displacementRejectRegions[2].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.y;
  2361. displacementRejectRegions[3].m_Normal = -m_InternalData.Placement.vRight;
  2362. displacementRejectRegions[3].m_Dist = displacementRejectRegions[3].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.y;
  2363. displacementRejectRegions[4].m_Normal = m_InternalData.Placement.vUp;
  2364. displacementRejectRegions[4].m_Dist = displacementRejectRegions[4].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.z;
  2365. displacementRejectRegions[5].m_Normal = -m_InternalData.Placement.vUp;
  2366. displacementRejectRegions[5].m_Dist = displacementRejectRegions[5].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.z;
  2367. CREATEDEBUGTIMER( dispTimer );
  2368. STARTDEBUGTIMER( dispTimer );
  2369. Assert( m_InternalData.Simulation.Static.World.Displacements.pCollideable == NULL );
  2370. virtualmeshlist_t DisplacementMeshes[32];
  2371. int iMeshes = enginetrace->GetMeshesFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs, DisplacementMeshes, ARRAYSIZE(DisplacementMeshes) );
  2372. if( iMeshes > 0 )
  2373. {
  2374. CPhysPolysoup *pDispCollideSoup = physcollision->PolysoupCreate();
  2375. // Count total triangles added to this poly soup- Can't support more than 65535.
  2376. int iTriCount = 0;
  2377. for( int i = 0; (i != iMeshes) && (iTriCount < 65535); ++i )
  2378. {
  2379. virtualmeshlist_t *pMesh = &DisplacementMeshes[i];
  2380. for ( int j = 0; j < pMesh->indexCount; j+=3 )
  2381. {
  2382. Vector *points[3] = { &pMesh->pVerts[ pMesh->indices[j+0] ], &pMesh->pVerts[ pMesh->indices[j+1] ], &pMesh->pVerts[ pMesh->indices[j+2] ] };
  2383. //test for triangles that lie completely outside our collision area
  2384. {
  2385. int k;
  2386. for( k = 0; k != ARRAYSIZE( displacementRejectRegions ); ++k )
  2387. {
  2388. //test all 3 points on each plane
  2389. if( (displacementRejectRegions[k].DistTo( *points[0] ) >= 0.0f) &&
  2390. (displacementRejectRegions[k].DistTo( *points[1] ) >= 0.0f) &&
  2391. (displacementRejectRegions[k].DistTo( *points[2] ) >= 0.0f) )
  2392. {
  2393. break; //break out if all 3 are in front of a rejection plane
  2394. }
  2395. }
  2396. if( k != ARRAYSIZE( displacementRejectRegions ) )
  2397. {
  2398. //was fully rejected by a plane
  2399. continue;
  2400. }
  2401. }
  2402. //clip to portal plane
  2403. {
  2404. //we do however need to clip to the wall plane
  2405. int iFront = 0;
  2406. int iBack = 0;
  2407. float fDists[3];
  2408. int iForwardPoints[3];
  2409. int iBackPoints[3];
  2410. for( int k = 0; k != 3; ++k )
  2411. {
  2412. fDists[k] = m_InternalData.Placement.PortalPlane.DistTo( *points[k] );
  2413. if( fDists[k] >= 0.0f )
  2414. {
  2415. iForwardPoints[iFront] = k;
  2416. ++iFront;
  2417. }
  2418. else
  2419. {
  2420. iBackPoints[iBack] = k;
  2421. ++iBack;
  2422. }
  2423. }
  2424. if( iFront != 0 )
  2425. {
  2426. if( iBack != 0 )
  2427. {
  2428. //need to clip the triangle
  2429. Vector vClippedPoints[2]; //guaranteed to intersect exactly twice
  2430. if( iBack == 2 )
  2431. {
  2432. if( fDists[iForwardPoints[0]] < 0.1f )
  2433. continue;
  2434. //easy case.
  2435. float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]];
  2436. if( fTotalDist < 0.1f )
  2437. continue;
  2438. vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist));
  2439. points[iBackPoints[0]] = &vClippedPoints[0];
  2440. fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[1]];
  2441. if( fTotalDist < 0.1f )
  2442. continue;
  2443. vClippedPoints[1] = ((*points[iBackPoints[1]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[1]]/fTotalDist));
  2444. points[iBackPoints[1]] = &vClippedPoints[1];
  2445. physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
  2446. ++iTriCount;
  2447. }
  2448. else
  2449. {
  2450. if( fDists[iBackPoints[0]] > -0.1f )
  2451. {
  2452. physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
  2453. ++iTriCount;
  2454. continue;
  2455. }
  2456. //need to create 2 triangles
  2457. float fTotalDist = fDists[iForwardPoints[0]] - fDists[iBackPoints[0]];
  2458. vClippedPoints[0] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[0]]/fTotalDist)) - ((*points[iForwardPoints[0]]) * (fDists[iBackPoints[0]]/fTotalDist));
  2459. fTotalDist = fDists[iForwardPoints[1]] - fDists[iBackPoints[0]];
  2460. vClippedPoints[1] = ((*points[iBackPoints[0]]) * (fDists[iForwardPoints[1]]/fTotalDist)) - ((*points[iForwardPoints[1]]) * (fDists[iBackPoints[0]]/fTotalDist));
  2461. points[iBackPoints[0]] = &vClippedPoints[0];
  2462. physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
  2463. ++iTriCount;
  2464. points[iBackPoints[0]] = &vClippedPoints[1];
  2465. points[iForwardPoints[0]] = &vClippedPoints[0];
  2466. physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
  2467. ++iTriCount;
  2468. }
  2469. }
  2470. else
  2471. {
  2472. //triangle resides wholly in front of the portal plane
  2473. physcollision->PolysoupAddTriangle( pDispCollideSoup, *points[0], *points[1], *points[2], pMesh->surfacePropsIndex );
  2474. ++iTriCount;
  2475. }
  2476. if( iTriCount >= 65535 )
  2477. {
  2478. break;
  2479. }
  2480. }
  2481. }
  2482. }// triangle loop
  2483. }
  2484. m_InternalData.Simulation.Static.World.Displacements.pCollideable = physcollision->ConvertPolysoupToCollide( pDispCollideSoup, false );
  2485. // clean up poly soup
  2486. physcollision->PolysoupDestroy( pDispCollideSoup );
  2487. }
  2488. //m_InternalData.Simulation.Static.World.Displacements.pCollideable = enginetrace->GetCollidableFromDisplacementsInAABB( m_InternalData.Placement.vecCurAABBMins, m_InternalData.Placement.vecCurAABBMaxs );
  2489. STOPDEBUGTIMER( dispTimer );
  2490. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sDisplacement Surfaces=%fms\n", GetPortalSimulatorGUID(), TABSPACING, dispTimer.GetDuration().GetMillisecondsF() ); );
  2491. }
  2492. //static props
  2493. CREATEDEBUGTIMER( worldPropTimer );
  2494. STARTDEBUGTIMER( worldPropTimer );
  2495. #ifdef _DEBUG
  2496. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2497. {
  2498. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide == NULL );
  2499. }
  2500. #endif
  2501. 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
  2502. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0 )
  2503. {
  2504. Assert( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() != 0 );
  2505. CPolyhedron **pPolyhedronsBase = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Base();
  2506. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2507. {
  2508. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  2509. Assert( Representation.pCollide == NULL );
  2510. Representation.pCollide = ConvertPolyhedronsToCollideable( &pPolyhedronsBase[Representation.PolyhedronGroup.iStartIndex], Representation.PolyhedronGroup.iNumPolyhedrons );
  2511. Assert( Representation.pCollide != NULL );
  2512. if( Representation.pCollide == NULL )
  2513. {
  2514. //we really shouldn't get here, but we do sometimes. Ideally we should either solve the conversion from polyhedrons to collideables, or throw away the polyhedrons as we carve them.
  2515. m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Remove( i ); //this will temporarily leak the polyhedrons we're referencing. But they'll get removed en-masse with the rest of the static prop polyhedrons when we move or destruct
  2516. }
  2517. }
  2518. }
  2519. m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists = true;
  2520. STOPDEBUGTIMER( worldPropTimer );
  2521. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Props=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldPropTimer.GetDuration().GetMillisecondsF() ); );
  2522. //carved entities
  2523. CREATEDEBUGTIMER( worldEntityTimer );
  2524. STARTDEBUGTIMER( worldEntityTimer );
  2525. #ifdef _DEBUG
  2526. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  2527. {
  2528. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pCollide == NULL );
  2529. }
  2530. #endif
  2531. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists == false ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  2532. if( m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count() != 0 )
  2533. {
  2534. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons.Count() != 0 );
  2535. CPolyhedron **pPolyhedronsBase = m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons.Base();
  2536. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  2537. {
  2538. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &Representation = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i];
  2539. if( Representation.CarvedPolyhedronGroup.iNumPolyhedrons != 0 )
  2540. {
  2541. Assert( Representation.pCollide == NULL );
  2542. Representation.pCollide = ConvertPolyhedronsToCollideable( &pPolyhedronsBase[Representation.CarvedPolyhedronGroup.iStartIndex], Representation.CarvedPolyhedronGroup.iNumPolyhedrons );
  2543. Assert( Representation.pCollide != NULL );
  2544. }
  2545. }
  2546. }
  2547. m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists = true;
  2548. STOPDEBUGTIMER( worldEntityTimer );
  2549. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWorld Entities=%fms\n", GetPortalSimulatorGUID(), TABSPACING, worldEntityTimer.GetDuration().GetMillisecondsF() ); );
  2550. //TODO: replace the complete wall with the wall shell
  2551. CREATEDEBUGTIMER( wallBrushTimer );
  2552. STARTDEBUGTIMER( wallBrushTimer );
  2553. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  2554. {
  2555. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  2556. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() != 0 )
  2557. {
  2558. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Base(), m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() );
  2559. }
  2560. }
  2561. STOPDEBUGTIMER( wallBrushTimer );
  2562. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWall Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, wallBrushTimer.GetDuration().GetMillisecondsF() ); );
  2563. #if defined( GAME_DLL )
  2564. CREATEDEBUGTIMER( func_clip_vphysics_timer );
  2565. STARTDEBUGTIMER( func_clip_vphysics_timer );
  2566. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable == NULL ); //Be sure to find graceful fixes for asserts, performance is a big concern with portal simulation
  2567. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.Count() != 0 )
  2568. {
  2569. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable = ConvertPolyhedronsToCollideable( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.Base(), m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.Count() );
  2570. }
  2571. STOPDEBUGTIMER( func_clip_vphysics_timer );
  2572. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sfunc_clip_vphysics Brushes=%fms\n", GetPortalSimulatorGUID(), TABSPACING, func_clip_vphysics_timer.GetDuration().GetMillisecondsF() ); );
  2573. #endif
  2574. CREATEDEBUGTIMER( wallTubeTimer );
  2575. STARTDEBUGTIMER( wallTubeTimer );
  2576. 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
  2577. if( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() != 0 )
  2578. 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() );
  2579. STOPDEBUGTIMER( wallTubeTimer );
  2580. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sWall Tube=%fms\n", GetPortalSimulatorGUID(), TABSPACING, wallTubeTimer.GetDuration().GetMillisecondsF() ); );
  2581. //grab surface properties to use for the portal environment
  2582. {
  2583. CTraceFilterWorldAndPropsOnly filter;
  2584. trace_t Trace;
  2585. 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 );
  2586. if( Trace.fraction != 1.0f )
  2587. {
  2588. m_InternalData.Simulation.Static.SurfaceProperties.contents = Trace.contents;
  2589. m_InternalData.Simulation.Static.SurfaceProperties.surface = Trace.surface;
  2590. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = Trace.m_pEnt;
  2591. }
  2592. else
  2593. {
  2594. m_InternalData.Simulation.Static.SurfaceProperties.contents = CONTENTS_SOLID;
  2595. m_InternalData.Simulation.Static.SurfaceProperties.surface.name = "**empty**";
  2596. m_InternalData.Simulation.Static.SurfaceProperties.surface.flags = 0;
  2597. m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps = 0;
  2598. #ifndef CLIENT_DLL
  2599. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = GetWorldEntity();
  2600. #else
  2601. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = GetClientWorldEntity();
  2602. #endif
  2603. }
  2604. if( m_InternalData.Simulation.hCollisionEntity )
  2605. m_InternalData.Simulation.Static.SurfaceProperties.pEntity = m_InternalData.Simulation.hCollisionEntity;
  2606. }
  2607. STOPDEBUGTIMER( functionTimer );
  2608. DECREMENTTABSPACING();
  2609. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreateLocalCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2610. m_CreationChecklist.bLocalCollisionGenerated = true;
  2611. }
  2612. void CPortalSimulator::CreateLinkedCollision( void )
  2613. {
  2614. if( m_CreationChecklist.bLinkedCollisionGenerated )
  2615. return;
  2616. if( IsCollisionGenerationEnabled() == false )
  2617. return;
  2618. //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.
  2619. m_CreationChecklist.bLinkedCollisionGenerated = true;
  2620. }
  2621. void CPortalSimulator::ClearAllCollision( void )
  2622. {
  2623. CREATEDEBUGTIMER( functionTimer );
  2624. STARTDEBUGTIMER( functionTimer );
  2625. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2626. INCREMENTTABSPACING();
  2627. ClearLinkedCollision();
  2628. ClearLocalCollision();
  2629. STOPDEBUGTIMER( functionTimer );
  2630. DECREMENTTABSPACING();
  2631. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearAllCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2632. }
  2633. void CPortalSimulator::ClearLinkedCollision( void )
  2634. {
  2635. if( m_CreationChecklist.bLinkedCollisionGenerated == false )
  2636. return;
  2637. //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.
  2638. m_CreationChecklist.bLinkedCollisionGenerated = false;
  2639. }
  2640. void CPortalSimulator::ClearLocalCollision( void )
  2641. {
  2642. if( m_CreationChecklist.bLocalCollisionGenerated == false )
  2643. return;
  2644. CREATEDEBUGTIMER( functionTimer );
  2645. STARTDEBUGTIMER( functionTimer );
  2646. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalCollision() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2647. INCREMENTTABSPACING();
  2648. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  2649. {
  2650. DestroyCollideable( &m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable );
  2651. }
  2652. #if defined( GAME_DLL )
  2653. DestroyCollideable( &m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable );
  2654. #endif
  2655. DestroyCollideable( &m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable );
  2656. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  2657. {
  2658. DestroyCollideable( &m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable );
  2659. }
  2660. DestroyCollideable( &m_InternalData.Simulation.Static.World.Displacements.pCollideable );
  2661. if( m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists &&
  2662. (m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count() != 0) )
  2663. {
  2664. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  2665. {
  2666. PS_SD_Static_World_StaticProps_ClippedProp_t &Representation = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i];
  2667. DestroyCollideable( &Representation.pCollide );
  2668. }
  2669. }
  2670. m_InternalData.Simulation.Static.World.StaticProps.bCollisionExists = false;
  2671. //carved entities
  2672. if( m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists &&
  2673. (m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count() != 0) )
  2674. {
  2675. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  2676. {
  2677. PS_SD_Dynamic_CarvedEntities_CarvedEntity_t &Representation = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i];
  2678. DestroyCollideable( &Representation.pCollide );
  2679. }
  2680. }
  2681. m_InternalData.Simulation.Dynamic.CarvedEntities.bCollisionExists = false;
  2682. STOPDEBUGTIMER( functionTimer );
  2683. DECREMENTTABSPACING();
  2684. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearLocalCollision() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  2685. m_CreationChecklist.bLocalCollisionGenerated = false;
  2686. }
  2687. void CPortalSimulator::CreatePolyhedrons( void )
  2688. {
  2689. if( m_CreationChecklist.bPolyhedronsGenerated )
  2690. return;
  2691. if( IsCollisionGenerationEnabled() == false )
  2692. return;
  2693. CREATEDEBUGTIMER( functionTimer );
  2694. STARTDEBUGTIMER( functionTimer );
  2695. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreatePolyhedrons() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  2696. INCREMENTTABSPACING();
  2697. const float fHalfHoleWidth = m_InternalData.Placement.fHalfWidth + PORTAL_HOLE_HALF_WIDTH_MOD;
  2698. const float fHalfHoleHeight = m_InternalData.Placement.fHalfHeight + PORTAL_HOLE_HALF_HEIGHT_MOD;
  2699. //forward reverse conventions signify whether the normal is the same direction as m_InternalData.Placement.PortalPlane.m_Normal
  2700. //World and wall conventions signify whether it's been shifted in front of the portal plane or behind it
  2701. float fWorldClipPlane_Forward[4] = { m_InternalData.Placement.PortalPlane.m_Normal.x,
  2702. m_InternalData.Placement.PortalPlane.m_Normal.y,
  2703. m_InternalData.Placement.PortalPlane.m_Normal.z,
  2704. m_InternalData.Placement.PortalPlane.m_Dist + PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT };
  2705. float fWorldClipPlane_Reverse[4] = { -fWorldClipPlane_Forward[0],
  2706. -fWorldClipPlane_Forward[1],
  2707. -fWorldClipPlane_Forward[2],
  2708. -fWorldClipPlane_Forward[3] };
  2709. float fWallClipPlane_Forward[4] = { m_InternalData.Placement.PortalPlane.m_Normal.x,
  2710. m_InternalData.Placement.PortalPlane.m_Normal.y,
  2711. m_InternalData.Placement.PortalPlane.m_Normal.z,
  2712. m_InternalData.Placement.PortalPlane.m_Dist }; // - PORTAL_WORLD_WALL_HALF_SEPARATION_AMOUNT
  2713. //float fWallClipPlane_Reverse[4] = { -fWallClipPlane_Forward[0],
  2714. // -fWallClipPlane_Forward[1],
  2715. // -fWallClipPlane_Forward[2],
  2716. // -fWallClipPlane_Forward[3] };
  2717. VPlane collisionClip[6];
  2718. collisionClip[0].m_Normal = *(Vector *)fWorldClipPlane_Reverse;
  2719. collisionClip[0].m_Dist = fWorldClipPlane_Reverse[3];
  2720. collisionClip[1].m_Normal = m_InternalData.Placement.vForward;
  2721. collisionClip[1].m_Dist = collisionClip[1].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.x;
  2722. collisionClip[2].m_Normal = m_InternalData.Placement.vRight;
  2723. collisionClip[2].m_Dist = collisionClip[2].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.y;
  2724. collisionClip[3].m_Normal = -m_InternalData.Placement.vRight;
  2725. collisionClip[3].m_Dist = collisionClip[3].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.y;
  2726. collisionClip[4].m_Normal = m_InternalData.Placement.vUp;
  2727. collisionClip[4].m_Dist = collisionClip[4].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.z;
  2728. collisionClip[5].m_Normal = -m_InternalData.Placement.vUp;
  2729. collisionClip[5].m_Dist = collisionClip[5].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.z;
  2730. //World
  2731. {
  2732. Vector vOBBForward = m_InternalData.Placement.vForward;
  2733. Vector vOBBRight = m_InternalData.Placement.vRight;
  2734. Vector vOBBUp = m_InternalData.Placement.vUp;
  2735. vOBBForward *= m_InternalData.Placement.vCollisionCloneExtents.x;
  2736. vOBBRight *= m_InternalData.Placement.vCollisionCloneExtents.y;
  2737. vOBBUp *= m_InternalData.Placement.vCollisionCloneExtents.z;
  2738. Vector ptOBBOrigin = m_InternalData.Placement.ptCenter;
  2739. ptOBBOrigin -= vOBBRight;
  2740. ptOBBOrigin -= vOBBUp;
  2741. vOBBRight *= 2.0f;
  2742. vOBBUp *= 2.0f;
  2743. Vector vAABBMins, vAABBMaxs;
  2744. vAABBMins = vAABBMaxs = ptOBBOrigin;
  2745. for( int i = 1; i != 8; ++i )
  2746. {
  2747. Vector ptTest = ptOBBOrigin;
  2748. if( i & (1 << 0) ) ptTest += vOBBForward;
  2749. if( i & (1 << 1) ) ptTest += vOBBRight;
  2750. if( i & (1 << 2) ) ptTest += vOBBUp;
  2751. if( ptTest.x < vAABBMins.x ) vAABBMins.x = ptTest.x;
  2752. if( ptTest.y < vAABBMins.y ) vAABBMins.y = ptTest.y;
  2753. if( ptTest.z < vAABBMins.z ) vAABBMins.z = ptTest.z;
  2754. if( ptTest.x > vAABBMaxs.x ) vAABBMaxs.x = ptTest.x;
  2755. if( ptTest.y > vAABBMaxs.y ) vAABBMaxs.y = ptTest.y;
  2756. if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z;
  2757. }
  2758. m_InternalData.Placement.vecCurAABBMins = vAABBMins;
  2759. m_InternalData.Placement.vecCurAABBMaxs = vAABBMaxs;
  2760. //Brushes
  2761. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  2762. {
  2763. Assert( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() == 0 );
  2764. //CUtlVector<int> WorldBrushes;
  2765. CBrushQuery WorldBrushes;
  2766. enginetrace->GetBrushesInAABB( vAABBMins, vAABBMaxs, WorldBrushes, m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].iSolidMask );
  2767. //create locally clipped polyhedrons for the world
  2768. {
  2769. uint32 *pBrushList = WorldBrushes.Base();
  2770. int iBrushCount = WorldBrushes.Count();
  2771. ConvertBrushListToClippedPolyhedronList( pBrushList, iBrushCount, (float *)collisionClip, ARRAYSIZE( collisionClip ), PORTAL_POLYHEDRON_CUT_EPSILON, &m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons );
  2772. }
  2773. }
  2774. //static props
  2775. {
  2776. Assert( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() == 0 );
  2777. CUtlVector<ICollideable *> StaticProps;
  2778. staticpropmgr->GetAllStaticPropsInAABB( vAABBMins, vAABBMaxs, &StaticProps );
  2779. for( int i = StaticProps.Count(); --i >= 0; )
  2780. {
  2781. ICollideable *pProp = StaticProps[i];
  2782. // Don't consider props that aren't solid!
  2783. if ( pProp->GetSolid() == SOLID_NONE || (pProp->GetSolidFlags() & FSOLID_NOT_SOLID) )
  2784. continue;
  2785. VPlane transformedCollisionClip[6];
  2786. //TODO: should be able to just strip out the VectorRotate() math
  2787. const VMatrix matCollisionToWorld( pProp->CollisionToWorldTransform() );
  2788. matrix3x4_t matWorldToCollision_RotationOnly;
  2789. MatrixTranspose( matCollisionToWorld.As3x4(), matWorldToCollision_RotationOnly );
  2790. Vector vPropTranslation = matCollisionToWorld.GetTranslation();
  2791. for( int clip = 0; clip != ARRAYSIZE( collisionClip ); ++clip )
  2792. {
  2793. VectorRotate( collisionClip[clip].m_Normal, matWorldToCollision_RotationOnly, transformedCollisionClip[clip].m_Normal );
  2794. transformedCollisionClip[clip].m_Dist = collisionClip[clip].m_Dist - collisionClip[clip].m_Normal.Dot( vPropTranslation );
  2795. }
  2796. const CPolyhedron *PolyhedronArray[1024];
  2797. int iPolyhedronCount = g_StaticCollisionPolyhedronCache.GetStaticPropPolyhedrons( pProp, PolyhedronArray, 1024 );
  2798. PropPolyhedronGroup_t indices;
  2799. indices.iStartIndex = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count();
  2800. for( int j = 0; j != iPolyhedronCount; ++j )
  2801. {
  2802. CPolyhedron *pClippedPropPolyhedron = ClipPolyhedron( PolyhedronArray[j], (float *)transformedCollisionClip, 6, PORTAL_WORLDCLIP_EPSILON, false );
  2803. if( pClippedPropPolyhedron )
  2804. {
  2805. //transform the output polyhedron into world space
  2806. for( int k = 0; k != pClippedPropPolyhedron->iVertexCount; ++k )
  2807. {
  2808. pClippedPropPolyhedron->pVertices[k] = matCollisionToWorld * pClippedPropPolyhedron->pVertices[k];
  2809. }
  2810. for( int k = 0; k != pClippedPropPolyhedron->iPolygonCount; ++k )
  2811. {
  2812. pClippedPropPolyhedron->pPolygons[k].polyNormal = matCollisionToWorld.ApplyRotation( pClippedPropPolyhedron->pPolygons[k].polyNormal );
  2813. }
  2814. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.AddToTail( pClippedPropPolyhedron );
  2815. }
  2816. }
  2817. g_StaticCollisionPolyhedronCache.ReleaseStaticPropPolyhedrons( pProp, PolyhedronArray, iPolyhedronCount );
  2818. indices.iNumPolyhedrons = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() - indices.iStartIndex;
  2819. if( indices.iNumPolyhedrons != 0 )
  2820. {
  2821. int index = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.AddToTail();
  2822. PS_SD_Static_World_StaticProps_ClippedProp_t &NewEntry = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[index];
  2823. NewEntry.PolyhedronGroup = indices;
  2824. NewEntry.pCollide = NULL;
  2825. #ifndef CLIENT_DLL
  2826. NewEntry.pPhysicsObject = NULL;
  2827. #endif
  2828. NewEntry.pSourceProp = pProp->GetEntityHandle();
  2829. const model_t *pModel = pProp->GetCollisionModel();
  2830. bool bIsStudioModel = pModel && (modelinfo->GetModelType( pModel ) == mod_studio);
  2831. AssertOnce( bIsStudioModel );
  2832. if( bIsStudioModel )
  2833. {
  2834. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pModel );
  2835. Assert( pStudioHdr != NULL );
  2836. NewEntry.iTraceContents = pStudioHdr->contents;
  2837. NewEntry.iTraceSurfaceProps = pStudioHdr->GetSurfaceProp();
  2838. }
  2839. else
  2840. {
  2841. NewEntry.iTraceContents = m_InternalData.Simulation.Static.SurfaceProperties.contents;
  2842. NewEntry.iTraceSurfaceProps = m_InternalData.Simulation.Static.SurfaceProperties.surface.surfaceProps;
  2843. }
  2844. }
  2845. }
  2846. }
  2847. }
  2848. //carved entities
  2849. {
  2850. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  2851. {
  2852. Assert( (m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].CarvedPolyhedronGroup.iNumPolyhedrons == 0) && (m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].UncarvedPolyhedronGroup.iNumPolyhedrons == 0) );
  2853. CarveEntity( m_InternalData.Placement, m_InternalData.Simulation.Dynamic.CarvedEntities, m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i] );
  2854. }
  2855. }
  2856. //(Holy) Wall
  2857. {
  2858. Vector vBackward = -m_InternalData.Placement.vForward;
  2859. Vector vLeft = -m_InternalData.Placement.vRight;
  2860. Vector vDown = -m_InternalData.Placement.vUp;
  2861. Vector vOBBForward = -m_InternalData.Placement.vForward;
  2862. Vector vOBBRight = -m_InternalData.Placement.vRight;
  2863. Vector vOBBUp = m_InternalData.Placement.vUp;
  2864. //scale the extents to usable sizes
  2865. vOBBForward *= MAX( m_InternalData.Placement.fHalfHeight, m_InternalData.Placement.fHalfWidth ) * 2.0f;
  2866. vOBBRight *= m_InternalData.Placement.fHalfWidth * 8.0f;
  2867. vOBBUp *= m_InternalData.Placement.fHalfHeight * 8.0f;
  2868. Vector ptOBBOrigin = m_InternalData.Placement.ptCenter;
  2869. ptOBBOrigin -= vOBBRight / 2.0f;
  2870. ptOBBOrigin -= vOBBUp / 2.0f;
  2871. Vector vAABBMins, vAABBMaxs;
  2872. vAABBMins = vAABBMaxs = ptOBBOrigin;
  2873. for( int i = 1; i != 8; ++i )
  2874. {
  2875. Vector ptTest = ptOBBOrigin;
  2876. if( i & (1 << 0) ) ptTest += vOBBForward;
  2877. if( i & (1 << 1) ) ptTest += vOBBRight;
  2878. if( i & (1 << 2) ) ptTest += vOBBUp;
  2879. if( ptTest.x < vAABBMins.x ) vAABBMins.x = ptTest.x;
  2880. if( ptTest.y < vAABBMins.y ) vAABBMins.y = ptTest.y;
  2881. if( ptTest.z < vAABBMins.z ) vAABBMins.z = ptTest.z;
  2882. if( ptTest.x > vAABBMaxs.x ) vAABBMaxs.x = ptTest.x;
  2883. if( ptTest.y > vAABBMaxs.y ) vAABBMaxs.y = ptTest.y;
  2884. if( ptTest.z > vAABBMaxs.z ) vAABBMaxs.z = ptTest.z;
  2885. }
  2886. float fPlanes[6 * 4];
  2887. //first and second planes are always forward and backward planes
  2888. fPlanes[(0*4) + 0] = fWallClipPlane_Forward[0];
  2889. fPlanes[(0*4) + 1] = fWallClipPlane_Forward[1];
  2890. fPlanes[(0*4) + 2] = fWallClipPlane_Forward[2];
  2891. fPlanes[(0*4) + 3] = fWallClipPlane_Forward[3];
  2892. fPlanes[(1*4) + 0] = vBackward.x;
  2893. fPlanes[(1*4) + 1] = vBackward.y;
  2894. fPlanes[(1*4) + 2] = vBackward.z;
  2895. fPlanes[(1*4) + 3] = vBackward.Dot( m_InternalData.Placement.ptCenter ) + 1.0f;
  2896. //the remaining planes will always have the same ordering of normals, with different distances plugged in for each convex we're creating
  2897. //normal order is up, down, left, right
  2898. fPlanes[(2*4) + 0] = m_InternalData.Placement.vUp.x;
  2899. fPlanes[(2*4) + 1] = m_InternalData.Placement.vUp.y;
  2900. fPlanes[(2*4) + 2] = m_InternalData.Placement.vUp.z;
  2901. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  2902. fPlanes[(3*4) + 0] = vDown.x;
  2903. fPlanes[(3*4) + 1] = vDown.y;
  2904. fPlanes[(3*4) + 2] = vDown.z;
  2905. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  2906. fPlanes[(4*4) + 0] = vLeft.x;
  2907. fPlanes[(4*4) + 1] = vLeft.y;
  2908. fPlanes[(4*4) + 2] = vLeft.z;
  2909. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleWidth;
  2910. fPlanes[(5*4) + 0] = m_InternalData.Placement.vRight.x;
  2911. fPlanes[(5*4) + 1] = m_InternalData.Placement.vRight.y;
  2912. fPlanes[(5*4) + 2] = m_InternalData.Placement.vRight.z;
  2913. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleWidth;
  2914. //these 2 get re-used a bit
  2915. float fFarRightPlaneDistance = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter + m_InternalData.Placement.vRight * (m_InternalData.Placement.fHalfWidth * 40.0f) );
  2916. float fFarLeftPlaneDistance = vLeft.Dot( m_InternalData.Placement.ptCenter + vLeft * (m_InternalData.Placement.fHalfHeight * 40.0f) );
  2917. collisionClip[0].m_Normal = -m_InternalData.Placement.vForward;
  2918. collisionClip[0].m_Dist = collisionClip[0].m_Normal.Dot( m_InternalData.Placement.ptCenter ) + m_InternalData.Placement.vCollisionCloneExtents.x;
  2919. collisionClip[1].m_Normal = *(Vector *)fWallClipPlane_Forward;
  2920. collisionClip[1].m_Dist = fWallClipPlane_Forward[3];
  2921. CUtlVector<CPolyhedron *> WallBrushPolyhedrons_ClippedToWall;
  2922. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  2923. {
  2924. Assert( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() == 0 );
  2925. //CUtlVector<int> WallBrushes;
  2926. CBrushQuery WallBrushes;
  2927. enginetrace->GetBrushesInAABB( vAABBMins, vAABBMaxs, WallBrushes, m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].iSolidMask );
  2928. if( WallBrushes.Count() != 0 )
  2929. ConvertBrushListToClippedPolyhedronList( WallBrushes.Base(), WallBrushes.Count(), (float *)collisionClip, ARRAYSIZE( collisionClip ), PORTAL_POLYHEDRON_CUT_EPSILON, &WallBrushPolyhedrons_ClippedToWall );
  2930. CarveWallBrushes_Sub( fPlanes, WallBrushPolyhedrons_ClippedToWall, m_InternalData, m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons, fFarRightPlaneDistance, fFarLeftPlaneDistance, vLeft, vDown );
  2931. for( int i = WallBrushPolyhedrons_ClippedToWall.Count(); --i >= 0; )
  2932. WallBrushPolyhedrons_ClippedToWall[i]->Release();
  2933. WallBrushPolyhedrons_ClippedToWall.RemoveAll();
  2934. }
  2935. #if defined( GAME_DLL )
  2936. //func_clip_vphysics
  2937. if( portal_carve_vphysics_clips.GetBool() )
  2938. {
  2939. s_VPhysicsClipWatcher.Cache();
  2940. for( int i = 0; i != s_VPhysicsClipWatcher.m_VPhysicsClipEntities.Count(); ++i )
  2941. {
  2942. VPhysicsClipEntry_t &checkEntry = s_VPhysicsClipWatcher.m_VPhysicsClipEntities[i];
  2943. if( !((checkEntry.vAABBMins.x >= vAABBMaxs.x) ||
  2944. (checkEntry.vAABBMins.y >= vAABBMaxs.y) ||
  2945. (checkEntry.vAABBMins.z >= vAABBMaxs.z) ||
  2946. (checkEntry.vAABBMaxs.x <= vAABBMins.x) ||
  2947. (checkEntry.vAABBMaxs.y <= vAABBMins.y) ||
  2948. (checkEntry.vAABBMaxs.z <= vAABBMins.z)) )
  2949. {
  2950. CBaseEntity *pClip = checkEntry.hEnt;
  2951. if( pClip && (pClip->GetMoveParent() == NULL) )
  2952. {
  2953. CCollisionProperty *pProp = pClip->CollisionProp();
  2954. if( pProp )
  2955. {
  2956. SolidType_t solidType = pClip->GetSolid();
  2957. if( solidType == SOLID_VPHYSICS )
  2958. {
  2959. vcollide_t *pCollide = modelinfo->GetVCollide( pProp->GetCollisionModelIndex() );
  2960. Assert( pCollide != NULL );
  2961. if( pCollide != NULL )
  2962. {
  2963. CPhysConvex *ConvexesArray[1024];
  2964. int iConvexCount = 0;
  2965. for( int i = 0; i != pCollide->solidCount; ++i )
  2966. {
  2967. iConvexCount += physcollision->GetConvexesUsedInCollideable( pCollide->solids[i], ConvexesArray, 1024 - iConvexCount );
  2968. }
  2969. for( int j = 0; j != iConvexCount; ++j )
  2970. {
  2971. CPolyhedron *pFullPolyhedron = physcollision->PolyhedronFromConvex( ConvexesArray[j], true );
  2972. if( pFullPolyhedron != NULL )
  2973. {
  2974. CPolyhedron *pClippedPolyhedron = ClipPolyhedron( pFullPolyhedron, (float *)collisionClip, ARRAYSIZE( collisionClip ), PORTAL_POLYHEDRON_CUT_EPSILON, false );
  2975. if( pClippedPolyhedron )
  2976. {
  2977. WallBrushPolyhedrons_ClippedToWall.AddToTail( pClippedPolyhedron );
  2978. }
  2979. pFullPolyhedron->Release();
  2980. }
  2981. }
  2982. }
  2983. }
  2984. else if( solidType == SOLID_BSP )
  2985. {
  2986. CBrushQuery brushQuery;
  2987. enginetrace->GetBrushesInCollideable( pProp, brushQuery );
  2988. if( brushQuery.Count() != 0 )
  2989. ConvertBrushListToClippedPolyhedronList( brushQuery.Base(), brushQuery.Count(), (float *)collisionClip, ARRAYSIZE( collisionClip ), PORTAL_POLYHEDRON_CUT_EPSILON, &WallBrushPolyhedrons_ClippedToWall );
  2990. }
  2991. }
  2992. }
  2993. }
  2994. }
  2995. CarveWallBrushes_Sub( fPlanes, WallBrushPolyhedrons_ClippedToWall, m_InternalData, m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons, fFarRightPlaneDistance, fFarLeftPlaneDistance, vLeft, vDown );
  2996. for( int i = WallBrushPolyhedrons_ClippedToWall.Count(); --i >= 0; )
  2997. WallBrushPolyhedrons_ClippedToWall[i]->Release();
  2998. WallBrushPolyhedrons_ClippedToWall.RemoveAll();
  2999. }
  3000. #endif
  3001. }
  3002. CreateTubePolyhedrons();
  3003. STOPDEBUGTIMER( functionTimer );
  3004. DECREMENTTABSPACING();
  3005. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::CreatePolyhedrons() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  3006. m_CreationChecklist.bPolyhedronsGenerated = true;
  3007. }
  3008. void CarveWallBrushes_Sub( float *fPlanes, CUtlVector<CPolyhedron *> &WallBrushPolyhedrons_ClippedToWall, PS_InternalData_t &InternalData, CUtlVector<CPolyhedron *> &OutputPolyhedrons, float fFarRightPlaneDistance, float fFarLeftPlaneDistance, const Vector &vLeft, const Vector &vDown )
  3009. {
  3010. const float fHalfHoleWidth = InternalData.Placement.fHalfWidth + PORTAL_HOLE_HALF_WIDTH_MOD;
  3011. const float fHalfHoleHeight = InternalData.Placement.fHalfHeight + PORTAL_HOLE_HALF_HEIGHT_MOD;
  3012. float *fSidePlanesOnly = &fPlanes[(2*4)];
  3013. float fPlaneDistBackups[6];
  3014. for( int i = 0; i != 6; ++i )
  3015. {
  3016. fPlaneDistBackups[i] = fPlanes[(i * 4) + 3];
  3017. }
  3018. CPolyhedron **pWallClippedPolyhedrons = NULL;
  3019. int iWallClippedPolyhedronCount = 0;
  3020. if( WallBrushPolyhedrons_ClippedToWall.Count() != 0 )
  3021. {
  3022. for( int i = WallBrushPolyhedrons_ClippedToWall.Count(); --i >= 0; )
  3023. {
  3024. CPolyhedron *pPolyhedron = ClipPolyhedron( WallBrushPolyhedrons_ClippedToWall[i], fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, true );
  3025. if( pPolyhedron )
  3026. {
  3027. //a chunk of this brush passes through the hole, not eligible to be removed from cutting
  3028. pPolyhedron->Release();
  3029. }
  3030. else
  3031. {
  3032. //no part of this brush interacts with the hole, no point in cutting the brush any later
  3033. OutputPolyhedrons.AddToTail( WallBrushPolyhedrons_ClippedToWall[i] );
  3034. WallBrushPolyhedrons_ClippedToWall.FastRemove( i );
  3035. }
  3036. }
  3037. if( WallBrushPolyhedrons_ClippedToWall.Count() != 0 ) //might have become 0 while removing uncut brushes
  3038. {
  3039. pWallClippedPolyhedrons = WallBrushPolyhedrons_ClippedToWall.Base();
  3040. iWallClippedPolyhedronCount = WallBrushPolyhedrons_ClippedToWall.Count();
  3041. }
  3042. }
  3043. if( iWallClippedPolyhedronCount != 0 )
  3044. {
  3045. //upper wall
  3046. {
  3047. //fPlanes[(1*4) + 3] += 2000.0f;
  3048. fPlanes[(2*4) + 3] = InternalData.Placement.vUp.Dot( InternalData.Placement.ptCenter ) + (InternalData.Placement.fHalfHeight * 40.0f);
  3049. fPlanes[(3*4) + 3] = vDown.Dot( InternalData.Placement.ptCenter ) - (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3050. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  3051. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  3052. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &OutputPolyhedrons );
  3053. }
  3054. //lower wall
  3055. {
  3056. //fPlanes[(1*4) + 3] += 2000.0f;
  3057. fPlanes[(2*4) + 3] = InternalData.Placement.vUp.Dot( InternalData.Placement.ptCenter ) - (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3058. fPlanes[(3*4) + 3] = vDown.Dot( InternalData.Placement.ptCenter ) + (InternalData.Placement.fHalfHeight * 40.0f);
  3059. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  3060. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  3061. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &OutputPolyhedrons );
  3062. }
  3063. //left wall
  3064. {
  3065. //fPlanes[(1*4) + 3] += 2000.0f;
  3066. fPlanes[(2*4) + 3] = InternalData.Placement.vUp.Dot( InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3067. fPlanes[(3*4) + 3] = vDown.Dot( InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3068. fPlanes[(4*4) + 3] = fFarLeftPlaneDistance;
  3069. fPlanes[(5*4) + 3] = InternalData.Placement.vRight.Dot( InternalData.Placement.ptCenter ) - (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3070. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &OutputPolyhedrons );
  3071. }
  3072. //right wall
  3073. {
  3074. //fPlanes[(1*4) + 3] += 2000.0f;
  3075. fPlanes[(2*4) + 3] = InternalData.Placement.vUp.Dot( InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3076. fPlanes[(3*4) + 3] = vDown.Dot( InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3077. fPlanes[(4*4) + 3] = vLeft.Dot( InternalData.Placement.ptCenter ) - (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3078. fPlanes[(5*4) + 3] = fFarRightPlaneDistance;
  3079. ClipPolyhedrons( pWallClippedPolyhedrons, iWallClippedPolyhedronCount, fSidePlanesOnly, 4, PORTAL_POLYHEDRON_CUT_EPSILON, &OutputPolyhedrons );
  3080. }
  3081. }
  3082. for( int i = 0; i != 6; ++i )
  3083. {
  3084. fPlanes[(i * 4) + 3] = fPlaneDistBackups[i];
  3085. }
  3086. }
  3087. void CPortalSimulator::CreateTubePolyhedrons( void )
  3088. {
  3089. Assert( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() == 0 );
  3090. Vector vBackward = -m_InternalData.Placement.vForward;
  3091. Vector vLeft = -m_InternalData.Placement.vRight;
  3092. Vector vDown = -m_InternalData.Placement.vUp;
  3093. const float fHalfHoleWidth = m_InternalData.Placement.fHalfWidth + PORTAL_HOLE_HALF_WIDTH_MOD;
  3094. const float fHalfHoleHeight = m_InternalData.Placement.fHalfHeight + PORTAL_HOLE_HALF_HEIGHT_MOD;
  3095. float fPlanes[6 * 4];
  3096. float fTubeOffset = PORTAL_WALL_TUBE_OFFSET;
  3097. if( m_InternalData.Placement.bParentIsVPhysicsSolidBrush )
  3098. {
  3099. fTubeOffset += VPHYSICS_SHRINK; //need to match VBSP shrinkage of brushes converted to physics models
  3100. }
  3101. //first and second planes are always forward and backward planes
  3102. fPlanes[(0*4) + 0] = m_InternalData.Placement.vForward.x;
  3103. fPlanes[(0*4) + 1] = m_InternalData.Placement.vForward.y;
  3104. fPlanes[(0*4) + 2] = m_InternalData.Placement.vForward.z;
  3105. fPlanes[(0*4) + 3] = m_InternalData.Placement.vForward.Dot( m_InternalData.Placement.ptCenter ) - fTubeOffset;
  3106. fPlanes[(1*4) + 0] = vBackward.x;
  3107. fPlanes[(1*4) + 1] = vBackward.y;
  3108. fPlanes[(1*4) + 2] = vBackward.z;
  3109. fPlanes[(1*4) + 3] = vBackward.Dot( m_InternalData.Placement.ptCenter ) + (PORTAL_WALL_TUBE_DEPTH + fTubeOffset);
  3110. fPlanes[(2*4) + 0] = m_InternalData.Placement.vUp.x;
  3111. fPlanes[(2*4) + 1] = m_InternalData.Placement.vUp.y;
  3112. fPlanes[(2*4) + 2] = m_InternalData.Placement.vUp.z;
  3113. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3114. fPlanes[(3*4) + 0] = vDown.x;
  3115. fPlanes[(3*4) + 1] = vDown.y;
  3116. fPlanes[(3*4) + 2] = vDown.z;
  3117. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3118. fPlanes[(4*4) + 0] = vLeft.x;
  3119. fPlanes[(4*4) + 1] = vLeft.y;
  3120. fPlanes[(4*4) + 2] = vLeft.z;
  3121. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleWidth;
  3122. fPlanes[(5*4) + 0] = m_InternalData.Placement.vRight.x;
  3123. fPlanes[(5*4) + 1] = m_InternalData.Placement.vRight.y;
  3124. fPlanes[(5*4) + 2] = m_InternalData.Placement.vRight.z;
  3125. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleWidth;
  3126. //upper wall
  3127. {
  3128. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  3129. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3130. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) - fHalfHoleHeight;
  3131. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3132. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3133. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  3134. if( pTubePolyhedron )
  3135. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  3136. }
  3137. //lower wall
  3138. {
  3139. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  3140. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) - fHalfHoleHeight;
  3141. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleHeight + PORTAL_WALL_MIN_THICKNESS);
  3142. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3143. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3144. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  3145. if( pTubePolyhedron )
  3146. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  3147. }
  3148. //left wall
  3149. {
  3150. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  3151. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3152. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3153. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3154. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) - fHalfHoleWidth;
  3155. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  3156. if( pTubePolyhedron )
  3157. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  3158. }
  3159. //right wall
  3160. {
  3161. //minimal portion that extends into the hole space
  3162. //fPlanes[(1*4) + 3] = fTubeDepthDist;
  3163. fPlanes[(2*4) + 3] = m_InternalData.Placement.vUp.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3164. fPlanes[(3*4) + 3] = vDown.Dot( m_InternalData.Placement.ptCenter ) + fHalfHoleHeight;
  3165. fPlanes[(4*4) + 3] = vLeft.Dot( m_InternalData.Placement.ptCenter ) - fHalfHoleWidth;
  3166. fPlanes[(5*4) + 3] = m_InternalData.Placement.vRight.Dot( m_InternalData.Placement.ptCenter ) + (fHalfHoleWidth + PORTAL_WALL_MIN_THICKNESS);
  3167. CPolyhedron *pTubePolyhedron = GeneratePolyhedronFromPlanes( fPlanes, 6, PORTAL_POLYHEDRON_CUT_EPSILON );
  3168. if( pTubePolyhedron )
  3169. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.AddToTail( pTubePolyhedron );
  3170. }
  3171. }
  3172. void CPortalSimulator::ClearPolyhedrons( void )
  3173. {
  3174. if( m_CreationChecklist.bPolyhedronsGenerated == false )
  3175. return;
  3176. CREATEDEBUGTIMER( functionTimer );
  3177. STARTDEBUGTIMER( functionTimer );
  3178. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearPolyhedrons() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  3179. INCREMENTTABSPACING();
  3180. //world brushes
  3181. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3182. {
  3183. if( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() != 0 )
  3184. {
  3185. for( int i = m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.Count(); --i >= 0; )
  3186. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons[i]->Release();
  3187. m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].Polyhedrons.RemoveAll();
  3188. }
  3189. }
  3190. //world static props
  3191. if( m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count() != 0 )
  3192. {
  3193. for( int i = m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.Count(); --i >= 0; )
  3194. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons[i]->Release();
  3195. m_InternalData.Simulation.Static.World.StaticProps.Polyhedrons.RemoveAll();
  3196. }
  3197. #ifdef _DEBUG
  3198. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  3199. {
  3200. #ifndef CLIENT_DLL
  3201. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pPhysicsObject == NULL );
  3202. #endif
  3203. Assert( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide == NULL );
  3204. }
  3205. #endif
  3206. m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.RemoveAll();
  3207. //carved entities
  3208. if( m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons.Count() != 0 )
  3209. {
  3210. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons.Count(); --i >= 0; )
  3211. m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons[i]->Release();
  3212. m_InternalData.Simulation.Dynamic.CarvedEntities.Polyhedrons.RemoveAll();
  3213. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  3214. {
  3215. m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].CarvedPolyhedronGroup.iStartIndex = 0;
  3216. m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].CarvedPolyhedronGroup.iNumPolyhedrons = 0;
  3217. m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].UncarvedPolyhedronGroup.iStartIndex = 0;
  3218. m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].UncarvedPolyhedronGroup.iNumPolyhedrons = 0;
  3219. }
  3220. }
  3221. #ifdef _DEBUG
  3222. for( int i = m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  3223. {
  3224. #ifndef CLIENT_DLL
  3225. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pPhysicsObject == NULL );
  3226. #endif
  3227. Assert( m_InternalData.Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pCollide == NULL );
  3228. }
  3229. #endif
  3230. //wall brushes
  3231. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  3232. {
  3233. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Count() != 0 )
  3234. {
  3235. for( int i = m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.Count(); --i >= 0; )
  3236. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons[i]->Release();
  3237. m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].Polyhedrons.RemoveAll();
  3238. }
  3239. }
  3240. #if defined( GAME_DLL )
  3241. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.Count() != 0 )
  3242. {
  3243. for( int i = m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.Count(); --i >= 0; )
  3244. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons[i]->Release();
  3245. m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.Polyhedrons.RemoveAll();
  3246. }
  3247. #endif
  3248. //wall tube props
  3249. if( m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count() != 0 )
  3250. {
  3251. for( int i = m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.Count(); --i >= 0; )
  3252. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons[i]->Release();
  3253. m_InternalData.Simulation.Static.Wall.Local.Tube.Polyhedrons.RemoveAll();
  3254. }
  3255. STOPDEBUGTIMER( functionTimer );
  3256. DECREMENTTABSPACING();
  3257. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::ClearPolyhedrons() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  3258. m_CreationChecklist.bPolyhedronsGenerated = false;
  3259. }
  3260. void CPortalSimulator::DebugCollisionOverlay( bool noDepthTest, float flDuration ) const
  3261. {
  3262. if( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable )
  3263. {
  3264. UTIL_DebugOverlay_CPhysCollide( m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable, 255, 255, 255, noDepthTest, flDuration );
  3265. }
  3266. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  3267. {
  3268. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable )
  3269. {
  3270. UTIL_DebugOverlay_CPhysCollide( m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable, 0, 255, 0, noDepthTest, flDuration );
  3271. }
  3272. }
  3273. #if defined( GAME_DLL )
  3274. if( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable )
  3275. {
  3276. UTIL_DebugOverlay_CPhysCollide( m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable, 255, 255, 0, noDepthTest, flDuration );
  3277. }
  3278. #endif
  3279. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3280. {
  3281. if( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable )
  3282. {
  3283. UTIL_DebugOverlay_CPhysCollide( m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable, 0, 255, 0, noDepthTest, flDuration );
  3284. }
  3285. }
  3286. for( int i = 0; i != m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); ++i )
  3287. {
  3288. UTIL_DebugOverlay_CPhysCollide( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, 0, 255, 255, noDepthTest, flDuration );
  3289. }
  3290. if( m_pLinkedPortal != NULL )
  3291. {
  3292. VMatrix linkedToThis = SetupMatrixOrgAngles( m_InternalData.Placement.ptaap_LinkedToThis.ptOriginTransform, m_InternalData.Placement.ptaap_LinkedToThis.qAngleTransform );
  3293. if( m_pLinkedPortal->m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable )
  3294. {
  3295. UTIL_DebugOverlay_CPhysCollide( m_pLinkedPortal->m_InternalData.Simulation.Static.Wall.Local.Tube.pCollideable, 128, 128, 128, noDepthTest, flDuration, &linkedToThis.As3x4() );
  3296. }
  3297. /*if( m_pLinkedPortal->m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable )
  3298. {
  3299. UTIL_DebugOverlay_CPhysCollide( m_pLinkedPortal->m_InternalData.Simulation.Static.Wall.Local.Brushes.pCollideable, 255, 0, 0, noDepthTest, flDuration, &linkedToThis.As3x4() );
  3300. }*/
  3301. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_pLinkedPortal->m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3302. {
  3303. if( m_pLinkedPortal->m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable )
  3304. {
  3305. UTIL_DebugOverlay_CPhysCollide( m_pLinkedPortal->m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable, 255, 0, 0, noDepthTest, flDuration, &linkedToThis.As3x4() );
  3306. }
  3307. }
  3308. for( int i = 0; i != m_pLinkedPortal->m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); ++i )
  3309. {
  3310. UTIL_DebugOverlay_CPhysCollide( m_pLinkedPortal->m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, 255, 0, 255, noDepthTest, flDuration, &linkedToThis.As3x4() );
  3311. }
  3312. }
  3313. }
  3314. void CPortalSimulator::DetachFromLinked( void )
  3315. {
  3316. if( m_pLinkedPortal == NULL )
  3317. return;
  3318. CREATEDEBUGTIMER( functionTimer );
  3319. STARTDEBUGTIMER( functionTimer );
  3320. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DetachFromLinked() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  3321. INCREMENTTABSPACING();
  3322. //IMPORTANT: Physics objects must be destroyed before their associated collision data or a fairly cryptic crash will ensue
  3323. #ifndef CLIENT_DLL
  3324. ClearLinkedEntities();
  3325. ClearLinkedPhysics();
  3326. #endif
  3327. ClearLinkedCollision();
  3328. if( m_pLinkedPortal->m_bInCrossLinkedFunction == false )
  3329. {
  3330. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  3331. m_bInCrossLinkedFunction = true;
  3332. m_pLinkedPortal->DetachFromLinked();
  3333. m_bInCrossLinkedFunction = false;
  3334. }
  3335. m_pLinkedPortal = NULL;
  3336. STOPDEBUGTIMER( functionTimer );
  3337. DECREMENTTABSPACING();
  3338. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DetachFromLinked() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  3339. }
  3340. void CPortalSimulator::SetPortalSimulatorCallbacks( CPortalSimulatorEventCallbacks *pCallbacks )
  3341. {
  3342. if( pCallbacks )
  3343. m_pCallbacks = pCallbacks;
  3344. else
  3345. m_pCallbacks = &s_DummyPortalSimulatorCallback; //always keep the pointer valid
  3346. }
  3347. #ifndef CLIENT_DLL
  3348. void CPortalSimulator::SetVPhysicsSimulationEnabled( bool bEnabled )
  3349. {
  3350. AssertMsg( (m_pLinkedPortal == NULL) || (m_pLinkedPortal->m_bSimulateVPhysics == m_bSimulateVPhysics), "Linked portals are in disagreement as to whether they would simulate VPhysics." );
  3351. if( bEnabled == m_bSimulateVPhysics )
  3352. return;
  3353. CREATEDEBUGTIMER( functionTimer );
  3354. STARTDEBUGTIMER( functionTimer );
  3355. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetVPhysicsSimulationEnabled() START\n", GetPortalSimulatorGUID(), TABSPACING ); );
  3356. INCREMENTTABSPACING();
  3357. m_bSimulateVPhysics = bEnabled;
  3358. if( bEnabled )
  3359. {
  3360. //we took some local collision shortcuts when generating while physics simulation is off, regenerate
  3361. ClearLocalCollision();
  3362. ClearPolyhedrons();
  3363. CreatePolyhedrons();
  3364. CreateLocalCollision();
  3365. CreateAllPhysics();
  3366. }
  3367. else
  3368. {
  3369. ClearAllPhysics();
  3370. }
  3371. if( m_pLinkedPortal && (m_pLinkedPortal->m_bInCrossLinkedFunction == false) )
  3372. {
  3373. Assert( m_bInCrossLinkedFunction == false ); //I'm pretty sure switching to a stack would have negative repercussions
  3374. m_bInCrossLinkedFunction = true;
  3375. m_pLinkedPortal->SetVPhysicsSimulationEnabled( bEnabled );
  3376. m_bInCrossLinkedFunction = false;
  3377. }
  3378. STOPDEBUGTIMER( functionTimer );
  3379. DECREMENTTABSPACING();
  3380. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::SetVPhysicsSimulationEnabled() FINISH: %fms\n", GetPortalSimulatorGUID(), TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  3381. }
  3382. #endif
  3383. #ifndef CLIENT_DLL
  3384. void CPortalSimulator::PrePhysFrame( void )
  3385. {
  3386. int iPortalSimulators = s_PortalSimulators.Count();
  3387. if( iPortalSimulators != 0 )
  3388. {
  3389. CPortalSimulator **pAllSimulators = s_PortalSimulators.Base();
  3390. for( int i = 0; i != iPortalSimulators; ++i )
  3391. {
  3392. CPortalSimulator *pSimulator = pAllSimulators[i];
  3393. if( !pSimulator->IsReadyToSimulate() )
  3394. continue;
  3395. int iOwnedEntities = pSimulator->m_InternalData.Simulation.Dynamic.OwnedEntities.Count();
  3396. if( iOwnedEntities != 0 )
  3397. {
  3398. CBaseEntity **pOwnedEntities = pSimulator->m_InternalData.Simulation.Dynamic.OwnedEntities.Base();
  3399. for( int j = 0; j != iOwnedEntities; ++j )
  3400. {
  3401. CBaseEntity *pEntity = pOwnedEntities[j];
  3402. if( CPhysicsShadowClone::IsShadowClone( pEntity ) )
  3403. continue;
  3404. Assert( (pEntity != NULL) && (pEntity->IsMarkedForDeletion() == false) );
  3405. IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
  3406. if( (pPhysObject == NULL) || pPhysObject->IsAsleep() )
  3407. continue;
  3408. int iEntIndex = pEntity->entindex();
  3409. int iExistingFlags = pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex];
  3410. if( pSimulator->EntityIsInPortalHole( pEntity ) )
  3411. pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] |= PSEF_IS_IN_PORTAL_HOLE;
  3412. else
  3413. pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] &= ~PSEF_IS_IN_PORTAL_HOLE;
  3414. UpdateShadowClonesPortalSimulationFlags( pEntity, PSEF_IS_IN_PORTAL_HOLE, pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] );
  3415. if( ((iExistingFlags ^ pSimulator->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex]) & PSEF_IS_IN_PORTAL_HOLE) != 0 ) //value changed
  3416. {
  3417. pEntity->CollisionRulesChanged(); //entity moved into or out of the portal hole, need to either add or remove collision with transformed geometry
  3418. CPhysicsShadowCloneLL *pClones = CPhysicsShadowClone::GetClonesOfEntity( pEntity );
  3419. while( pClones )
  3420. {
  3421. pClones->pClone->CollisionRulesChanged();
  3422. pClones = pClones->pNext;
  3423. }
  3424. }
  3425. }
  3426. }
  3427. }
  3428. }
  3429. }
  3430. void CPortalSimulator::PostPhysFrame( void )
  3431. {
  3432. for( int i = 1; i <= gpGlobals->maxClients; ++i )
  3433. {
  3434. CPortal_Player* pPlayer = (CPortal_Player *)UTIL_PlayerByIndex( i );
  3435. if( pPlayer )
  3436. {
  3437. CPortal_Base2D* pTouchedPortal = pPlayer->m_hPortalEnvironment.Get();
  3438. CPortalSimulator* pSim = GetSimulatorThatOwnsEntity( pPlayer );
  3439. if ( pTouchedPortal && pSim && (pTouchedPortal->m_PortalSimulator.GetPortalSimulatorGUID() != pSim->GetPortalSimulatorGUID()) )
  3440. {
  3441. 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" );
  3442. ADD_DEBUG_HISTORY( HISTORY_PLAYER_DAMAGE, UTIL_VarArgs( "Player in PortalSimulator but not touching a portal, removing from sim at : %f\n", gpGlobals->curtime ) );
  3443. if ( pSim )
  3444. {
  3445. pSim->ReleaseOwnershipOfEntity( pPlayer, false );
  3446. }
  3447. }
  3448. }
  3449. }
  3450. }
  3451. #endif //#ifndef CLIENT_DLL
  3452. CPortalSimulator *CPortalSimulator::GetSimulatorThatOwnsEntity( const CBaseEntity *pEntity )
  3453. {
  3454. int nEntIndex = pEntity->entindex();
  3455. if( nEntIndex < 0 )
  3456. return NULL;
  3457. #ifdef _DEBUG
  3458. CPortalSimulator *pOwningSimulatorCheck = NULL;
  3459. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3460. {
  3461. if( s_PortalSimulators[i]->m_InternalData.Simulation.Dynamic.EntFlags[nEntIndex] & PSEF_OWNS_ENTITY )
  3462. {
  3463. AssertMsg( pOwningSimulatorCheck == NULL, "More than one portal simulator found owning the same entity." );
  3464. pOwningSimulatorCheck = s_PortalSimulators[i];
  3465. }
  3466. }
  3467. AssertMsg( pOwningSimulatorCheck == s_OwnedEntityMap[nEntIndex], "Owned entity mapping out of sync with individual simulator ownership flags." );
  3468. #endif
  3469. return s_OwnedEntityMap[nEntIndex];
  3470. }
  3471. #ifndef CLIENT_DLL
  3472. int CPortalSimulator::GetMoveableOwnedEntities( CBaseEntity **pEntsOut, int iEntOutLimit )
  3473. {
  3474. int iOwnedEntCount = m_InternalData.Simulation.Dynamic.OwnedEntities.Count();
  3475. int iOutputCount = 0;
  3476. for( int i = 0; i != iOwnedEntCount; ++i )
  3477. {
  3478. CBaseEntity *pEnt = m_InternalData.Simulation.Dynamic.OwnedEntities[i];
  3479. Assert( pEnt != NULL );
  3480. if( CPhysicsShadowClone::IsShadowClone( pEnt ) )
  3481. continue;
  3482. if( CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEnt ) )
  3483. continue;
  3484. if( pEnt->GetMoveType() == MOVETYPE_NONE )
  3485. continue;
  3486. pEntsOut[iOutputCount] = pEnt;
  3487. ++iOutputCount;
  3488. if( iOutputCount == iEntOutLimit )
  3489. break;
  3490. }
  3491. return iOutputCount;
  3492. }
  3493. CPortalSimulator *CPortalSimulator::GetSimulatorThatCreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType )
  3494. {
  3495. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3496. {
  3497. if( s_PortalSimulators[i]->CreatedPhysicsObject( pObject, pOut_SourceType ) )
  3498. return s_PortalSimulators[i];
  3499. }
  3500. return NULL;
  3501. }
  3502. bool CPortalSimulator::CreatedPhysicsObject( const IPhysicsObject *pObject, PS_PhysicsObjectSourceType_t *pOut_SourceType ) const
  3503. {
  3504. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3505. {
  3506. if( (pObject == m_InternalData.Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject) || (pObject == m_InternalData.Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject) )
  3507. {
  3508. if( pOut_SourceType )
  3509. *pOut_SourceType = PSPOST_LOCAL_BRUSHES;
  3510. return true;
  3511. }
  3512. }
  3513. #if defined( GAME_DLL )
  3514. if( pObject == m_InternalData.Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject )
  3515. {
  3516. if( pOut_SourceType )
  3517. *pOut_SourceType = PSPOST_LOCAL_BRUSHES;
  3518. return true;
  3519. }
  3520. #endif
  3521. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects ); ++iBrushSet )
  3522. {
  3523. if( pObject == m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] )
  3524. {
  3525. if( pOut_SourceType )
  3526. *pOut_SourceType = PSPOST_REMOTE_BRUSHES;
  3527. return true;
  3528. }
  3529. }
  3530. for( int i = m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  3531. {
  3532. if( m_InternalData.Simulation.Static.World.StaticProps.ClippedRepresentations[i].pPhysicsObject == pObject )
  3533. {
  3534. if( pOut_SourceType )
  3535. *pOut_SourceType = PSPOST_LOCAL_STATICPROPS;
  3536. return true;
  3537. }
  3538. }
  3539. for( int i = m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects.Count(); --i >= 0; )
  3540. {
  3541. if( m_InternalData.Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.PhysicsObjects[i] == pObject )
  3542. {
  3543. if( pOut_SourceType )
  3544. *pOut_SourceType = PSPOST_REMOTE_STATICPROPS;
  3545. return true;
  3546. }
  3547. }
  3548. if( pObject == m_InternalData.Simulation.Static.Wall.Local.Tube.pPhysicsObject )
  3549. {
  3550. if( pOut_SourceType )
  3551. *pOut_SourceType = PSPOST_HOLYWALL_TUBE;
  3552. return true;
  3553. }
  3554. if( pObject == m_InternalData.Simulation.Static.World.Displacements.pPhysicsObject )
  3555. {
  3556. if( pOut_SourceType )
  3557. *pOut_SourceType = PSPOST_LOCAL_DISPLACEMENT;
  3558. return true;
  3559. }
  3560. return false;
  3561. }
  3562. #endif //#ifndef CLIENT_DLL
  3563. static void ConvertBrushListToClippedPolyhedronList( const uint32 *pBrushes, int iBrushCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList )
  3564. {
  3565. if( pPolyhedronList == NULL )
  3566. return;
  3567. if( (pBrushes == NULL) || (iBrushCount == 0) )
  3568. return;
  3569. for( int i = 0; i != iBrushCount; ++i )
  3570. {
  3571. const CPolyhedron *pBrushPolyhedron = g_StaticCollisionPolyhedronCache.GetBrushPolyhedron( pBrushes[i] );
  3572. CPolyhedron *pPolyhedron = ClipPolyhedron( pBrushPolyhedron, pOutwardFacingClipPlanes, iClipPlaneCount, fClipEpsilon );
  3573. if( pPolyhedron )
  3574. {
  3575. pPolyhedronList->AddToTail( pPolyhedron );
  3576. }
  3577. g_StaticCollisionPolyhedronCache.ReleaseBrushPolyhedron( pBrushes[i], pBrushPolyhedron );
  3578. }
  3579. }
  3580. static void ClipPolyhedrons( CPolyhedron * const *pExistingPolyhedrons, int iPolyhedronCount, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fClipEpsilon, CUtlVector<CPolyhedron *> *pPolyhedronList )
  3581. {
  3582. if( pPolyhedronList == NULL )
  3583. return;
  3584. if( (pExistingPolyhedrons == NULL) || (iPolyhedronCount == 0) )
  3585. return;
  3586. for( int i = 0; i != iPolyhedronCount; ++i )
  3587. {
  3588. CPolyhedron *pPolyhedron = ClipPolyhedron( pExistingPolyhedrons[i], pOutwardFacingClipPlanes, iClipPlaneCount, fClipEpsilon );
  3589. if( pPolyhedron )
  3590. pPolyhedronList->AddToTail( pPolyhedron );
  3591. }
  3592. }
  3593. //#define DUMP_POLYHEDRON_BEFORE_CONVERSION //uncomment to enable code that dumps each polyhedron just before it converts to a CPhysConvex (a very common place to crash if anything is amiss with the polyhedron).
  3594. static CPhysCollide *ConvertPolyhedronsToCollideable( CPolyhedron **pPolyhedrons, int iPolyhedronCount )
  3595. {
  3596. if( (pPolyhedrons == NULL) || (iPolyhedronCount == 0 ) )
  3597. return NULL;
  3598. CREATEDEBUGTIMER( functionTimer );
  3599. STARTDEBUGTIMER( functionTimer );
  3600. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvertPolyhedronsToCollideable() START\n", s_iPortalSimulatorGUID, TABSPACING ); );
  3601. INCREMENTTABSPACING();
  3602. CPhysConvex **pConvexes = (CPhysConvex **)stackalloc( iPolyhedronCount * sizeof( CPhysConvex * ) );
  3603. int iConvexCount = 0;
  3604. #ifdef DUMP_POLYHEDRON_BEFORE_CONVERSION
  3605. VMatrix matScaleNearOrigin;
  3606. matScaleNearOrigin.Identity();
  3607. const float cScale = 10.0f;
  3608. matScaleNearOrigin = matScaleNearOrigin.Scale( Vector( cScale, cScale, cScale ) );
  3609. #endif
  3610. CREATEDEBUGTIMER( convexTimer );
  3611. STARTDEBUGTIMER( convexTimer );
  3612. for( int i = 0; i != iPolyhedronCount; ++i )
  3613. {
  3614. #ifdef DUMP_POLYHEDRON_BEFORE_CONVERSION
  3615. {
  3616. matScaleNearOrigin.SetTranslation( -pPolyhedrons[i]->Center() * cScale );
  3617. #ifndef CLIENT_DLL
  3618. const char *szDumpFile = "PolyConvertServer.txt";
  3619. #else
  3620. const char *szDumpFile = "PolyConvertClient.txt";
  3621. #endif
  3622. DumpPolyhedronToGLView( pPolyhedrons[i], szDumpFile, &matScaleNearOrigin, "wb" );
  3623. }
  3624. #endif
  3625. pConvexes[iConvexCount] = physcollision->ConvexFromConvexPolyhedron( *pPolyhedrons[i] );
  3626. Assert( pConvexes[iConvexCount] != NULL );
  3627. if( pConvexes[iConvexCount] )
  3628. ++iConvexCount;
  3629. }
  3630. STOPDEBUGTIMER( convexTimer );
  3631. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvex Generation:%fms\n", s_iPortalSimulatorGUID, TABSPACING, convexTimer.GetDuration().GetMillisecondsF() ); );
  3632. CPhysCollide *pReturn;
  3633. if( iConvexCount != 0 )
  3634. {
  3635. CREATEDEBUGTIMER( collideTimer );
  3636. STARTDEBUGTIMER( collideTimer );
  3637. convertconvexparams_t params;
  3638. params.Defaults();
  3639. params.buildOptimizedTraceTables = true;
  3640. params.bUseFastApproximateInertiaTensor = true;
  3641. params.bBuildAABBTree = true;
  3642. pReturn = physcollision->ConvertConvexToCollideParams( pConvexes, iConvexCount, params );
  3643. STOPDEBUGTIMER( collideTimer );
  3644. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCollideable Generation:%fms\n", s_iPortalSimulatorGUID, TABSPACING, collideTimer.GetDuration().GetMillisecondsF() ); );
  3645. }
  3646. else
  3647. {
  3648. pReturn = NULL;
  3649. }
  3650. STOPDEBUGTIMER( functionTimer );
  3651. DECREMENTTABSPACING();
  3652. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sConvertPolyhedronsToCollideable() FINISH: %fms\n", s_iPortalSimulatorGUID, TABSPACING, functionTimer.GetDuration().GetMillisecondsF() ); );
  3653. return pReturn;
  3654. }
  3655. static inline CPolyhedron *TransformAndClipSinglePolyhedron( CPolyhedron *pExistingPolyhedron, const VMatrix &Transform, const float *pOutwardFacingClipPlanes, int iClipPlaneCount, float fCutEpsilon, bool bUseTempMemory )
  3656. {
  3657. Vector *pTempPointArray = (Vector *)stackalloc( sizeof( Vector ) * pExistingPolyhedron->iVertexCount );
  3658. Polyhedron_IndexedPolygon_t *pTempPolygonArray = (Polyhedron_IndexedPolygon_t *)stackalloc( sizeof( Polyhedron_IndexedPolygon_t ) * pExistingPolyhedron->iPolygonCount );
  3659. Polyhedron_IndexedPolygon_t *pOriginalPolygons = pExistingPolyhedron->pPolygons;
  3660. pExistingPolyhedron->pPolygons = pTempPolygonArray;
  3661. Vector *pOriginalPoints = pExistingPolyhedron->pVertices;
  3662. pExistingPolyhedron->pVertices = pTempPointArray;
  3663. for( int j = 0; j != pExistingPolyhedron->iPolygonCount; ++j )
  3664. {
  3665. pTempPolygonArray[j].iFirstIndex = pOriginalPolygons[j].iFirstIndex;
  3666. pTempPolygonArray[j].iIndexCount = pOriginalPolygons[j].iIndexCount;
  3667. pTempPolygonArray[j].polyNormal = Transform.ApplyRotation( pOriginalPolygons[j].polyNormal );
  3668. }
  3669. for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j )
  3670. {
  3671. pTempPointArray[j] = Transform * pOriginalPoints[j];
  3672. }
  3673. CPolyhedron *pNewPolyhedron = ClipPolyhedron( pExistingPolyhedron, pOutwardFacingClipPlanes, iClipPlaneCount, fCutEpsilon, bUseTempMemory ); //copy the polyhedron
  3674. //restore the original polyhedron to its former self
  3675. pExistingPolyhedron->pVertices = pOriginalPoints;
  3676. pExistingPolyhedron->pPolygons = pOriginalPolygons;
  3677. return pNewPolyhedron;
  3678. }
  3679. static int GetEntityPhysicsObjects( IPhysicsEnvironment *pEnvironment, CBaseEntity *pEntity, IPhysicsObject **pRetList, int iRetListArraySize )
  3680. {
  3681. int iCount, iRetCount = 0;
  3682. const IPhysicsObject **pList = pEnvironment->GetObjectList( &iCount );
  3683. if( iCount > iRetListArraySize )
  3684. iCount = iRetListArraySize;
  3685. for ( int i = 0; i < iCount; ++i )
  3686. {
  3687. CBaseEntity *pEnvEntity = reinterpret_cast<CBaseEntity *>(pList[i]->GetGameData());
  3688. if ( pEntity == pEnvEntity )
  3689. {
  3690. pRetList[iRetCount] = (IPhysicsObject *)(pList[i]);
  3691. ++iRetCount;
  3692. }
  3693. }
  3694. return iRetCount;
  3695. }
  3696. #ifndef CLIENT_DLL
  3697. //Move all entities back to the main environment for removal, and make sure the main environment is in control during the UTIL_Remove process
  3698. struct UTIL_Remove_PhysicsStack_t
  3699. {
  3700. IPhysicsEnvironment *pPhysicsEnvironment;
  3701. CEntityList *pShadowList;
  3702. };
  3703. static CUtlVector<UTIL_Remove_PhysicsStack_t> s_UTIL_Remove_PhysicsStack;
  3704. void CPortalSimulator::Pre_UTIL_Remove( CBaseEntity *pEntity )
  3705. {
  3706. int index = s_UTIL_Remove_PhysicsStack.AddToTail();
  3707. s_UTIL_Remove_PhysicsStack[index].pPhysicsEnvironment = physenv;
  3708. s_UTIL_Remove_PhysicsStack[index].pShadowList = g_pShadowEntities;
  3709. int iEntIndex = pEntity->entindex();
  3710. //NDebugOverlay::EntityBounds( pEntity, 0, 0, 0, 50, 5.0f );
  3711. if( (CPhysicsShadowClone::IsShadowClone( pEntity ) == false) &&
  3712. (CPSCollisionEntity::IsPortalSimulatorCollisionEntity( pEntity ) == false) )
  3713. {
  3714. CPortalSimulator *pOwningSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity );
  3715. if( pOwningSimulator )
  3716. {
  3717. pOwningSimulator->ReleasePhysicsOwnership( pEntity, false );
  3718. pOwningSimulator->ReleaseOwnershipOfEntity( pEntity );
  3719. }
  3720. //might be cloned from main to a few environments
  3721. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3722. {
  3723. s_PortalSimulators[i]->StopCloningEntityFromMain( pEntity );
  3724. s_PortalSimulators[i]->StopCloningEntityAcrossPortals( pEntity );
  3725. }
  3726. }
  3727. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3728. {
  3729. s_PortalSimulators[i]->m_InternalData.Simulation.Dynamic.EntFlags[iEntIndex] = 0;
  3730. }
  3731. physenv = physenv_main;
  3732. g_pShadowEntities = g_pShadowEntities_Main;
  3733. }
  3734. void CPortalSimulator::Post_UTIL_Remove( CBaseEntity *pEntity )
  3735. {
  3736. int index = s_UTIL_Remove_PhysicsStack.Count() - 1;
  3737. Assert( index >= 0 );
  3738. UTIL_Remove_PhysicsStack_t &PhysicsStackEntry = s_UTIL_Remove_PhysicsStack[index];
  3739. physenv = PhysicsStackEntry.pPhysicsEnvironment;
  3740. g_pShadowEntities = PhysicsStackEntry.pShadowList;
  3741. s_UTIL_Remove_PhysicsStack.FastRemove(index);
  3742. #ifdef _DEBUG
  3743. for( int i = CPhysicsShadowClone::g_ShadowCloneList.Count(); --i >= 0; )
  3744. {
  3745. Assert( CPhysicsShadowClone::g_ShadowCloneList[i]->GetClonedEntity() != pEntity ); //shouldn't be any clones of this object anymore
  3746. }
  3747. #endif
  3748. }
  3749. void UpdateShadowClonesPortalSimulationFlags( const CBaseEntity *pSourceEntity, unsigned int iFlags, int iSourceFlags )
  3750. {
  3751. Assert( !CPhysicsShadowClone::IsShadowClone( pSourceEntity ) );
  3752. unsigned int iOrFlags = iSourceFlags & iFlags;
  3753. CPhysicsShadowCloneLL *pClones = CPhysicsShadowClone::GetClonesOfEntity( pSourceEntity );
  3754. while( pClones )
  3755. {
  3756. CPhysicsShadowClone *pClone = pClones->pClone;
  3757. CPortalSimulator *pCloneSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pClone );
  3758. unsigned int *pFlags = (unsigned int *)&pCloneSimulator->GetInternalData().Simulation.Dynamic.EntFlags[pClone->entindex()];
  3759. *pFlags &= ~iFlags;
  3760. *pFlags |= iOrFlags;
  3761. Assert( ((iSourceFlags ^ *pFlags) & iFlags) == 0 );
  3762. pClones = pClones->pNext;
  3763. }
  3764. }
  3765. #endif
  3766. #ifdef GAME_DLL
  3767. class CPS_AutoGameSys_EntityListener : public CAutoGameSystem, public IEntityListener
  3768. #else
  3769. class CPS_AutoGameSys_EntityListener : public CAutoGameSystem, public IClientEntityListener
  3770. #endif
  3771. {
  3772. public:
  3773. virtual void LevelInitPreEntity( void )
  3774. {
  3775. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3776. s_PortalSimulators[i]->ClearEverything();
  3777. }
  3778. virtual void LevelShutdownPreEntity( void )
  3779. {
  3780. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3781. s_PortalSimulators[i]->ClearEverything();
  3782. }
  3783. virtual bool Init( void )
  3784. {
  3785. #if defined( GAME_DLL )
  3786. gEntList.AddListenerEntity( this );
  3787. #else
  3788. ClientEntityList().AddListenerEntity( this );
  3789. #endif
  3790. return true;
  3791. }
  3792. //virtual void OnEntityCreated( CBaseEntity *pEntity ) {}
  3793. virtual void OnEntityDeleted( CBaseEntity *pEntity )
  3794. {
  3795. #if defined( CLIENT_DLL )
  3796. if( pEntity->entindex() < 0 )
  3797. return;
  3798. #endif
  3799. CPortalSimulator *pSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity );
  3800. if( pSimulator )
  3801. {
  3802. #if defined( GAME_DLL )
  3803. pSimulator->ReleasePhysicsOwnership( pEntity, false );
  3804. #endif
  3805. pSimulator->ReleaseOwnershipOfEntity( pEntity );
  3806. }
  3807. Assert( CPortalSimulator::GetSimulatorThatOwnsEntity( pEntity ) == NULL );
  3808. for( int i = s_PortalSimulators.Count(); --i >= 0; )
  3809. {
  3810. #if defined( DBGFLAG_ASSERT )
  3811. CPortalSimulator *pSimulator = s_PortalSimulators[i];
  3812. for( int j = pSimulator->GetInternalData().Simulation.Dynamic.OwnedEntities.Count(); --j >= 0; )
  3813. {
  3814. Assert( pSimulator->GetInternalData().Simulation.Dynamic.OwnedEntities[j] != pEntity );
  3815. }
  3816. #endif
  3817. s_PortalSimulators[i]->ReleaseCarvedEntity( pEntity );
  3818. }
  3819. }
  3820. };
  3821. static CPS_AutoGameSys_EntityListener s_CPS_AGS_EL_Singleton;
  3822. #ifdef GAME_DLL
  3823. IMPLEMENT_SERVERCLASS_ST( CPSCollisionEntity, DT_PSCollisionEntity )
  3824. END_SEND_TABLE()
  3825. #else
  3826. IMPLEMENT_CLIENTCLASS_DT( CPSCollisionEntity, DT_PSCollisionEntity, CPSCollisionEntity )
  3827. END_RECV_TABLE()
  3828. #endif // ifdef GAME_DLL
  3829. LINK_ENTITY_TO_CLASS( portalsimulator_collisionentity, CPSCollisionEntity );
  3830. static bool s_PortalSimulatorCollisionEntities[MAX_EDICTS] = { false };
  3831. CPSCollisionEntity::CPSCollisionEntity( void )
  3832. #ifdef GAME_DLL
  3833. : m_pOwningSimulator( NULL )
  3834. #endif
  3835. {
  3836. }
  3837. CPSCollisionEntity::~CPSCollisionEntity( void )
  3838. {
  3839. #ifdef GAME_DLL
  3840. if( m_pOwningSimulator )
  3841. {
  3842. m_pOwningSimulator->m_InternalData.Simulation.Dynamic.EntFlags[entindex()] &= ~PSEF_OWNS_PHYSICS;
  3843. m_pOwningSimulator->MarkAsReleased( this );
  3844. m_pOwningSimulator->m_InternalData.Simulation.hCollisionEntity = NULL;
  3845. m_pOwningSimulator = NULL;
  3846. }
  3847. #endif
  3848. s_PortalSimulatorCollisionEntities[entindex()] = false;
  3849. }
  3850. void CPSCollisionEntity::UpdateOnRemove( void )
  3851. {
  3852. VPhysicsSetObject( NULL );
  3853. #ifdef GAME_DLL
  3854. if( m_pOwningSimulator )
  3855. {
  3856. m_pOwningSimulator->m_InternalData.Simulation.Dynamic.EntFlags[entindex()] &= ~PSEF_OWNS_PHYSICS;
  3857. m_pOwningSimulator->MarkAsReleased( this );
  3858. m_pOwningSimulator->m_InternalData.Simulation.hCollisionEntity = NULL;
  3859. m_pOwningSimulator = NULL;
  3860. }
  3861. #endif
  3862. s_PortalSimulatorCollisionEntities[entindex()] = false;
  3863. BaseClass::UpdateOnRemove();
  3864. }
  3865. void CPSCollisionEntity::Spawn( void )
  3866. {
  3867. BaseClass::Spawn();
  3868. SetSolid( SOLID_CUSTOM );
  3869. SetMoveType( MOVETYPE_NONE );
  3870. SetCollisionGroup( COLLISION_GROUP_NONE );
  3871. s_PortalSimulatorCollisionEntities[entindex()] = true;
  3872. VPhysicsSetObject( NULL );
  3873. AddFlag( FL_WORLDBRUSH );
  3874. AddEffects( EF_NODRAW | EF_NOINTERP | EF_NOSHADOW | EF_NORECEIVESHADOW );
  3875. }
  3876. void CPSCollisionEntity::Activate( void )
  3877. {
  3878. BaseClass::Activate();
  3879. CollisionRulesChanged();
  3880. }
  3881. int CPSCollisionEntity::ObjectCaps( void )
  3882. {
  3883. return ((BaseClass::ObjectCaps() | FCAP_DONT_SAVE) & ~(FCAP_FORCE_TRANSITION | FCAP_ACROSS_TRANSITION | FCAP_MUST_SPAWN | FCAP_SAVE_NON_NETWORKABLE));
  3884. }
  3885. bool CPSCollisionEntity::ShouldCollide( int collisionGroup, int contentsMask ) const
  3886. {
  3887. #ifdef GAME_DLL
  3888. return GetWorldEntity()->ShouldCollide( collisionGroup, contentsMask );
  3889. #else
  3890. return GetClientWorldEntity()->ShouldCollide( collisionGroup, contentsMask );
  3891. #endif
  3892. }
  3893. int CPSCollisionEntity::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  3894. {
  3895. #ifdef GAME_DLL
  3896. if( m_pOwningSimulator == NULL )
  3897. return 0;
  3898. if( (pList == NULL) || (listMax == 0) )
  3899. return 0;
  3900. int iRetVal = 0;
  3901. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_pOwningSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3902. {
  3903. if( m_pOwningSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject != NULL )
  3904. {
  3905. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pPhysicsObject;
  3906. ++iRetVal;
  3907. if( iRetVal == listMax )
  3908. return iRetVal;
  3909. }
  3910. }
  3911. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  3912. {
  3913. if( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject != NULL )
  3914. {
  3915. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pPhysicsObject;
  3916. ++iRetVal;
  3917. if( iRetVal == listMax )
  3918. return iRetVal;
  3919. }
  3920. }
  3921. if( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject != NULL )
  3922. {
  3923. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pPhysicsObject;
  3924. ++iRetVal;
  3925. if( iRetVal == listMax )
  3926. return iRetVal;
  3927. }
  3928. if( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Tube.pPhysicsObject != NULL )
  3929. {
  3930. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.Local.Tube.pPhysicsObject;
  3931. ++iRetVal;
  3932. if( iRetVal == listMax )
  3933. return iRetVal;
  3934. }
  3935. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects ); ++iBrushSet )
  3936. {
  3937. if( m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet] != NULL )
  3938. {
  3939. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pPhysicsObjects[iBrushSet];
  3940. ++iRetVal;
  3941. if( iRetVal == listMax )
  3942. return iRetVal;
  3943. }
  3944. }
  3945. if( m_pOwningSimulator->GetInternalData().Simulation.Static.World.Displacements.pPhysicsObject != NULL )
  3946. {
  3947. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Static.World.Displacements.pPhysicsObject;
  3948. ++iRetVal;
  3949. if( iRetVal == listMax )
  3950. return iRetVal;
  3951. }
  3952. int iCarvedEntityCount = m_pOwningSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count();
  3953. for( int i = 0; i != iCarvedEntityCount; ++i )
  3954. {
  3955. pList[iRetVal] = m_pOwningSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pPhysicsObject;
  3956. if( pList[iRetVal] != NULL )
  3957. {
  3958. ++iRetVal;
  3959. if( iRetVal == listMax )
  3960. return iRetVal;
  3961. }
  3962. }
  3963. return iRetVal;
  3964. #else
  3965. return 0;
  3966. #endif
  3967. }
  3968. bool CPSCollisionEntity::IsPortalSimulatorCollisionEntity( const CBaseEntity *pEntity )
  3969. {
  3970. return (pEntity->entindex() < 0) ? false : s_PortalSimulatorCollisionEntities[pEntity->entindex()];
  3971. }
  3972. #ifdef CLIENT_DLL
  3973. void CPSCollisionEntity::UpdatePartitionListEntry() //make this trigger touchable on the client
  3974. {
  3975. partition->RemoveAndInsert(
  3976. PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS | PARTITION_CLIENT_TRIGGER_ENTITIES | PARTITION_CLIENT_IK_ATTACHMENT, // remove
  3977. PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_STATIC_PROPS, // add
  3978. CollisionProp()->GetPartitionHandle() );
  3979. }
  3980. #endif
  3981. #ifdef DEBUG_PORTAL_COLLISION_ENVIRONMENTS
  3982. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename );
  3983. static void PortalSimulatorDumps_DumpPlanesToGlView( float *pPlanes, int iPlaneCount, const char *pszFileName );
  3984. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName );
  3985. 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 );
  3986. void DumpActiveCollision( const CPortalSimulator *pPortalSimulator, const char *szFileName )
  3987. {
  3988. CREATEDEBUGTIMER( collisionDumpTimer );
  3989. STARTDEBUGTIMER( collisionDumpTimer );
  3990. //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
  3991. #define PSDAC_INTENSITY_LOCALBRUSH 0.5f
  3992. #define PSDAC_INTENSITY_LOCALPROP 0.75f
  3993. #define PSDAC_INTENSITY_REMOTEBRUSH 0.0625f
  3994. #define PSDAC_INTENSITY_REMOTEPROP 0.25f
  3995. #define PSDAC_INTENSITY_CARVEDENTITY 1.0f
  3996. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( pPortalSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  3997. {
  3998. if( pPortalSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable )
  3999. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  4000. }
  4001. if( pPortalSimulator->GetInternalData().Simulation.Static.World.StaticProps.bCollisionExists )
  4002. {
  4003. for( int i = pPortalSimulator->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  4004. {
  4005. Assert( pPortalSimulator->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide );
  4006. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALPROP, szFileName );
  4007. }
  4008. }
  4009. if( pPortalSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.bCollisionExists )
  4010. {
  4011. for( int i = pPortalSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations.Count(); --i >= 0; )
  4012. {
  4013. if( pPortalSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pCollide )
  4014. {
  4015. ICollideable *pProp = pPortalSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pSourceEntity->GetCollideable();
  4016. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Dynamic.CarvedEntities.CarvedRepresentations[i].pCollide, pProp->GetCollisionOrigin(), pProp->GetCollisionAngles(), PSDAC_INTENSITY_CARVEDENTITY, szFileName );
  4017. }
  4018. }
  4019. }
  4020. if ( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable )
  4021. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.World.Displacements.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  4022. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets ); ++iBrushSet )
  4023. {
  4024. if( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable )
  4025. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.BrushSets[iBrushSet].pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  4026. }
  4027. #if defined( GAME_DLL )
  4028. if( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable )
  4029. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Brushes.Carved_func_clip_vphysics.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  4030. #endif
  4031. if( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Tube.pCollideable )
  4032. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.Wall.Local.Tube.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_LOCALBRUSH, szFileName );
  4033. //if( pPortalSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable )
  4034. // PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.Brushes.pCollideable, vec3_origin, vec3_angle, PSDAC_INTENSITY_REMOTEBRUSH, szFileName );
  4035. CPortalSimulator *pLinkedPortal = pPortalSimulator->GetLinkedPortalSimulator();
  4036. if( pLinkedPortal )
  4037. {
  4038. for( int iBrushSet = 0; iBrushSet != ARRAYSIZE( pLinkedPortal->GetInternalData().Simulation.Static.World.Brushes.BrushSets ); ++iBrushSet )
  4039. {
  4040. if( pLinkedPortal->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable )
  4041. PortalSimulatorDumps_DumpCollideToGlView( pLinkedPortal->GetInternalData().Simulation.Static.World.Brushes.BrushSets[iBrushSet].pCollideable, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.ptShrinkAlignedOrigin, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.qAngleTransform, PSDAC_INTENSITY_REMOTEBRUSH, szFileName );
  4042. }
  4043. if ( pLinkedPortal->GetInternalData().Simulation.Static.World.Displacements.pCollideable )
  4044. PortalSimulatorDumps_DumpCollideToGlView( pLinkedPortal->GetInternalData().Simulation.Static.World.Displacements.pCollideable, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.ptShrinkAlignedOrigin, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.qAngleTransform, PSDAC_INTENSITY_REMOTEBRUSH, szFileName );
  4045. //for( int i = pPortalSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.Collideables.Count(); --i >= 0; )
  4046. // PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Simulation.Static.Wall.RemoteTransformedToLocal.StaticProps.Collideables[i], vec3_origin, vec3_angle, PSDAC_INTENSITY_REMOTEPROP, szFileName );
  4047. if( pLinkedPortal->GetInternalData().Simulation.Static.World.StaticProps.bCollisionExists )
  4048. {
  4049. for( int i = pLinkedPortal->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations.Count(); --i >= 0; )
  4050. {
  4051. Assert( pLinkedPortal->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide );
  4052. PortalSimulatorDumps_DumpCollideToGlView( pLinkedPortal->GetInternalData().Simulation.Static.World.StaticProps.ClippedRepresentations[i].pCollide, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.ptShrinkAlignedOrigin, pPortalSimulator->GetInternalData().Placement.ptaap_LinkedToThis.qAngleTransform, PSDAC_INTENSITY_REMOTEPROP, szFileName );
  4053. }
  4054. }
  4055. }
  4056. if( sv_dump_portalsimulator_holeshapes.GetBool() )
  4057. {
  4058. if( pPortalSimulator->GetInternalData().Placement.pHoleShapeCollideable )
  4059. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Placement.pHoleShapeCollideable, vec3_origin, vec3_angle, 0.2f, szFileName );
  4060. if( pPortalSimulator->GetInternalData().Placement.pInvHoleShapeCollideable )
  4061. PortalSimulatorDumps_DumpCollideToGlView( pPortalSimulator->GetInternalData().Placement.pInvHoleShapeCollideable, vec3_origin, vec3_angle, 0.1f, szFileName );
  4062. }
  4063. STOPDEBUGTIMER( collisionDumpTimer );
  4064. DEBUGTIMERONLY( DevMsg( 2, "[PSDT:%d] %sCPortalSimulator::DumpActiveCollision() Spent %fms generating a collision dump\n", pPortalSimulator->GetPortalSimulatorGUID(), TABSPACING, collisionDumpTimer.GetDuration().GetMillisecondsF() ); );
  4065. }
  4066. static void PortalSimulatorDumps_DumpCollideToGlView( CPhysCollide *pCollide, const Vector &origin, const QAngle &angles, float fColorScale, const char *pFilename )
  4067. {
  4068. if ( !pCollide )
  4069. return;
  4070. printf("Writing %s...\n", pFilename );
  4071. Vector *outVerts;
  4072. int vertCount = physcollision->CreateDebugMesh( pCollide, &outVerts );
  4073. FileHandle_t fp = filesystem->Open( pFilename, "ab" );
  4074. int triCount = vertCount / 3;
  4075. int vert = 0;
  4076. VMatrix tmp = SetupMatrixOrgAngles( origin, angles );
  4077. int i;
  4078. for ( i = 0; i < vertCount; i++ )
  4079. {
  4080. outVerts[i] = tmp.VMul4x3( outVerts[i] );
  4081. }
  4082. for ( i = 0; i < triCount; i++ )
  4083. {
  4084. filesystem->FPrintf( fp, "3\n" );
  4085. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f 0 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  4086. vert++;
  4087. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f 0 %.2f 0\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  4088. vert++;
  4089. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f 0 0 %.2f\n", outVerts[vert].x, outVerts[vert].y, outVerts[vert].z, fColorScale );
  4090. vert++;
  4091. }
  4092. filesystem->Close( fp );
  4093. physcollision->DestroyDebugMesh( vertCount, outVerts );
  4094. }
  4095. static void PortalSimulatorDumps_DumpPlanesToGlView( float *pPlanes, int iPlaneCount, const char *pszFileName )
  4096. {
  4097. FileHandle_t fp = filesystem->Open( pszFileName, "wb" );
  4098. for( int i = 0; i < iPlaneCount; ++i )
  4099. {
  4100. Vector vPlaneVerts[4];
  4101. float fRed, fGreen, fBlue;
  4102. fRed = rand()/32768.0f;
  4103. fGreen = rand()/32768.0f;
  4104. fBlue = rand()/32768.0f;
  4105. PolyFromPlane( vPlaneVerts, *(Vector *)(pPlanes + (i*4)), pPlanes[(i*4) + 3], 1000.0f );
  4106. filesystem->FPrintf( fp, "4\n" );
  4107. 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 );
  4108. 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 );
  4109. 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 );
  4110. 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 );
  4111. }
  4112. filesystem->Close( fp );
  4113. }
  4114. static void PortalSimulatorDumps_DumpBoxToGlView( const Vector &vMins, const Vector &vMaxs, float fRed, float fGreen, float fBlue, const char *pszFileName )
  4115. {
  4116. FileHandle_t fp = filesystem->Open( pszFileName, "ab" );
  4117. //x min side
  4118. filesystem->FPrintf( fp, "4\n" );
  4119. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4120. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4121. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4122. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4123. filesystem->FPrintf( fp, "4\n" );
  4124. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4125. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4126. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4127. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4128. //x max side
  4129. filesystem->FPrintf( fp, "4\n" );
  4130. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4131. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4132. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4133. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4134. filesystem->FPrintf( fp, "4\n" );
  4135. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4136. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4137. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4138. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4139. //y min side
  4140. filesystem->FPrintf( fp, "4\n" );
  4141. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4142. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4143. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4144. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4145. filesystem->FPrintf( fp, "4\n" );
  4146. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4147. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4148. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4149. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4150. //y max side
  4151. filesystem->FPrintf( fp, "4\n" );
  4152. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4153. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4154. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4155. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4156. filesystem->FPrintf( fp, "4\n" );
  4157. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4158. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4159. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4160. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4161. //z min side
  4162. filesystem->FPrintf( fp, "4\n" );
  4163. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4164. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4165. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4166. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4167. filesystem->FPrintf( fp, "4\n" );
  4168. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4169. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4170. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, fRed, fGreen, fBlue );
  4171. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, fRed, fGreen, fBlue );
  4172. //z max side
  4173. filesystem->FPrintf( fp, "4\n" );
  4174. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4175. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4176. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4177. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4178. filesystem->FPrintf( fp, "4\n" );
  4179. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4180. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4181. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, fRed, fGreen, fBlue );
  4182. filesystem->FPrintf( fp, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, fRed, fGreen, fBlue );
  4183. filesystem->Close( fp );
  4184. }
  4185. 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 )
  4186. {
  4187. FileHandle_t fp = filesystem->Open( pszFileName, "ab" );
  4188. Vector ptExtents[8];
  4189. int counter;
  4190. for( counter = 0; counter != 8; ++counter )
  4191. {
  4192. ptExtents[counter] = ptOrigin;
  4193. if( counter & (1<<0) ) ptExtents[counter] += vExtent1;
  4194. if( counter & (1<<1) ) ptExtents[counter] += vExtent2;
  4195. if( counter & (1<<2) ) ptExtents[counter] += vExtent3;
  4196. }
  4197. //x min side
  4198. filesystem->FPrintf( fp, "4\n" );
  4199. 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 );
  4200. 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 );
  4201. 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 );
  4202. 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 );
  4203. filesystem->FPrintf( fp, "4\n" );
  4204. 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 );
  4205. 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 );
  4206. 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 );
  4207. 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 );
  4208. //x max side
  4209. filesystem->FPrintf( fp, "4\n" );
  4210. 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 );
  4211. 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 );
  4212. 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 );
  4213. 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 );
  4214. filesystem->FPrintf( fp, "4\n" );
  4215. 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 );
  4216. 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 );
  4217. 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 );
  4218. 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 );
  4219. //y min side
  4220. filesystem->FPrintf( fp, "4\n" );
  4221. 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 );
  4222. 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 );
  4223. 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 );
  4224. 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 );
  4225. filesystem->FPrintf( fp, "4\n" );
  4226. 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 );
  4227. 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 );
  4228. 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 );
  4229. 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 );
  4230. //y max side
  4231. filesystem->FPrintf( fp, "4\n" );
  4232. 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 );
  4233. 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 );
  4234. 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 );
  4235. 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 );
  4236. filesystem->FPrintf( fp, "4\n" );
  4237. 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 );
  4238. 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 );
  4239. 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 );
  4240. 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 );
  4241. //z min side
  4242. filesystem->FPrintf( fp, "4\n" );
  4243. 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 );
  4244. 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 );
  4245. 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 );
  4246. 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 );
  4247. filesystem->FPrintf( fp, "4\n" );
  4248. 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 );
  4249. 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 );
  4250. 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 );
  4251. 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 );
  4252. //z max side
  4253. filesystem->FPrintf( fp, "4\n" );
  4254. 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 );
  4255. 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 );
  4256. 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 );
  4257. 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 );
  4258. filesystem->FPrintf( fp, "4\n" );
  4259. 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 );
  4260. 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 );
  4261. 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 );
  4262. 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 );
  4263. filesystem->Close( fp );
  4264. }
  4265. #endif