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.

228 lines
6.5 KiB

  1. //========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "physlevelhavok.h"
  8. #include "alignedarray.h"
  9. #include "bsplib.h"
  10. #include "physdll.h"
  11. #include "vbsp.h"
  12. CPhysLevelHavokEmitter::CPhysLevelHavokEmitter()
  13. {
  14. m_numModels = nummodels;
  15. m_pModels = dmodels;
  16. m_pNodes = dnodes;
  17. m_numBrushes = numbrushes;
  18. m_pLeafs = dleafs;
  19. m_pLeafBrushes = dleafbrushes;
  20. m_pBrushes = dbrushes;
  21. m_pBrushSides = dbrushsides;
  22. m_pPlanes = dplanes;
  23. m_bConvertBrushesToMopp = !g_bPhysNoMopp;
  24. m_buildInertia = false;
  25. m_exportObjMopp = !!g_bPhysExportMoppObj;
  26. m_physics = NULL;
  27. CreateInterfaceFn physicsFactory = GetPhysicsFactory();
  28. if ( physicsFactory )
  29. {
  30. m_physics = (IPhysics2*)physicsFactory( VPHYSICS2_INTERFACE_VERSION, NULL );
  31. }
  32. if ( !m_physics )
  33. Warning("!!! WARNING: Can't build collision2 data!\n" );
  34. m_cook = m_physics->GetCook();
  35. }
  36. CPhysLevelHavokEmitter::~CPhysLevelHavokEmitter()
  37. {
  38. }
  39. // TODO: move this to Cook interface
  40. void CPhysLevelHavokEmitter::Emit()
  41. {
  42. CVarBitVec useBrush(m_numBrushes);
  43. for ( int i = 0; i < m_numModels; ++i )
  44. {
  45. dmodel_t *pModel = &m_pModels[i];
  46. AddBrushes(pModel->headnode, useBrush);
  47. }
  48. CUtlVector<IPhysics2CookedPolytope *> arrPolytopes;
  49. ConvertBrushesToPolytopes(useBrush, arrPolytopes);
  50. dphyslevelV0_t *pRoot = Write<dphyslevelV0_t>();
  51. pRoot->toolVersion = 2;
  52. pRoot->dataVersion = m_physics->GetSerializeVersion();
  53. pRoot->sizeofDiskPhysics2Polytope = sizeof(DiskPhysics2Polytope_t);
  54. pRoot->buildTime = (int)time(NULL);
  55. bool outputIndividualPolytopes = true;
  56. // having the number of polytopes, we need to generate MOPP
  57. if(m_bConvertBrushesToMopp)
  58. {
  59. int numPolytopes = arrPolytopes.Count();
  60. CUtlVector<IPhysics2CookedMeshBase*>arrMeshes(0,numPolytopes);
  61. for(int i = 0; i < numPolytopes; ++i)
  62. arrMeshes[i] = arrPolytopes[i]; // conver the pointers
  63. if(m_exportObjMopp)m_cook->ExportObj("d:\\mopp.obj", arrMeshes.Base(), numPolytopes);
  64. IPhysics2CookedMopp *pMopp = m_cook->CookMopp(arrMeshes.Base(), numPolytopes);
  65. if(pMopp)
  66. {
  67. Msg("Physics2Mopp cooked, mem size: %.1f\n", pMopp->GetSizeOf()/1024.);
  68. void *pSerializedMopp = m_cook->Serialize(pMopp->GetMopp(), this);
  69. IStream::Link(&pRoot->mopp, pSerializedMopp);
  70. outputIndividualPolytopes = false; // we don't need to output individual polytopes, because MOPP will contain them separately
  71. m_cook->Destroy(pMopp);
  72. }
  73. else
  74. Warning("Could not build polysoup from brushes\n");
  75. }
  76. if(false)
  77. {
  78. int numPolytopes = arrPolytopes.Count();
  79. CUtlVector<IPhysics2CookedMeshBase*>arrMeshes(0,numPolytopes);
  80. for(int i = 0; i < numPolytopes; ++i)
  81. arrMeshes[i] = arrPolytopes[i]; // conver the pointers
  82. IPhysics2CookedPolysoup *polysoup = m_cook->CookPolysoupFromMeshes(arrMeshes.Base(), numPolytopes);
  83. if(polysoup)
  84. {
  85. //polysoup->ExportObj("d:\\test.obj");
  86. m_cook->Destroy(polysoup);
  87. }
  88. }
  89. int numPolytopes = arrPolytopes.Count();
  90. DiskPhysics2Polytope_t *pDiskPolytopes = NULL;
  91. if(outputIndividualPolytopes)
  92. pDiskPolytopes = WriteAndLinkArray(&pRoot->polytopes,numPolytopes);
  93. for(int nPolytope = 0; nPolytope < numPolytopes; ++nPolytope)
  94. {
  95. IPhysics2CookedPolytope *pPolytope = arrPolytopes[nPolytope];
  96. if(outputIndividualPolytopes)
  97. {
  98. void *pSerializedPolytope = m_cook->Serialize(pPolytope->GetPolytope(), this);
  99. Link(&pDiskPolytopes[nPolytope].offsetPolytope, pSerializedPolytope);
  100. if(m_buildInertia)
  101. {
  102. IPhysics2CookedInertia *pInertia = m_cook->CookInertia(pPolytope->GetPolytope());
  103. void* pSerializedInertia = m_cook->Serialize(pInertia->GetInertia(), this);
  104. Link(&pDiskPolytopes[nPolytope].offsetInertia, pSerializedInertia);
  105. m_cook->Destroy(pInertia);
  106. }
  107. }
  108. m_cook->Destroy(pPolytope);
  109. }
  110. }
  111. void CPhysLevelHavokEmitter::ConvertBrushesToPolytopes(CVarBitVec &useBrushIn, CUtlVector<IPhysics2CookedPolytope*> &arrPolytopesOut)
  112. {
  113. uint numCouldntCreate = 0;
  114. for( int nBrush = 0; nBrush < m_numBrushes; ++nBrush )
  115. {
  116. if(useBrushIn[nBrush])
  117. {
  118. int numBrushSides = m_pBrushes[nBrush].numsides;
  119. CUtlVector_Vector4DAligned arrSides(numBrushSides);
  120. dbrushside_t *pThisBrushSides = m_pBrushSides + m_pBrushes[nBrush].firstside;
  121. for(int nSide = 0; nSide < numBrushSides; ++nSide)
  122. {
  123. dbrushside_t *pSide = pThisBrushSides + nSide;
  124. if(!pSide->bevel)
  125. {
  126. dplane_t &plane = m_pPlanes[pSide->planenum];
  127. Vector4DAligned side;
  128. side.Init(plane.normal.x,plane.normal.y,plane.normal.z, -plane.dist);
  129. arrSides.AddToTail(side);
  130. }
  131. }
  132. IPhysics2CookedPolytope *pPolytope = m_cook->CookPolytopeFromPlanes((Vector4DAligned*)arrSides.Base(), arrSides.Size());
  133. if(pPolytope)
  134. {
  135. arrPolytopesOut.AddToTail(pPolytope);
  136. }
  137. else
  138. {
  139. //Warning("Couldn't create a convex out of brush #%d\n", nBrush);
  140. ++numCouldntCreate;
  141. }
  142. }
  143. }
  144. if(numCouldntCreate)
  145. Warning("Couldn't create %u/%u brushes\n", numCouldntCreate, m_numBrushes);
  146. else
  147. Msg("Created %u brushes\n", m_numBrushes);
  148. }
  149. void CPhysLevelHavokEmitter::AddBrushes(int nNode, CVarBitVec &isBrushAdded)
  150. {
  151. if(nNode < 0)
  152. {
  153. int leafIndex = -1 - nNode;
  154. for ( int i = 0; i < m_pLeafs[leafIndex].numleafbrushes; ++i )
  155. {
  156. int brushIndex = m_pLeafBrushes[m_pLeafs[leafIndex].firstleafbrush + i];
  157. isBrushAdded.Set(brushIndex);
  158. }
  159. }
  160. else
  161. {
  162. dnode_t *pNode = m_pNodes + nNode;
  163. AddBrushes( pNode->children[0] , isBrushAdded );
  164. AddBrushes( pNode->children[1] , isBrushAdded );
  165. }
  166. }
  167. // This is the only public entry to this file.
  168. // The global data touched in the file is:
  169. // from bsplib.h:
  170. // g_pPhysLevel : This is an output from this file.
  171. // g_PhysLevelSize : This is set in this file.
  172. // g_dispinfo : This is an input to this file.
  173. // int nummodels;
  174. // dmodel_t dmodels[MAX_MAP_MODELS];
  175. // numnodewaterdata : This is an input to this file from EmitPhysCollision()
  176. // dleafwaterdata : This is an input to this file from EmitPhysCollision()
  177. // from vbsp.h:
  178. // g_SurfaceProperties : This is an input to this file.
  179. void EmitPhysLevel()
  180. {
  181. if(g_pPhysLevel)
  182. MemAlloc_FreeAligned(g_pPhysLevel);
  183. CPhysLevelHavokEmitter emitter;
  184. emitter.Emit();
  185. g_PhysLevelSize = emitter.GetTotalSize();
  186. g_pPhysLevel = (byte*)MemAlloc_AllocAligned(g_PhysLevelSize, 16);
  187. if(!emitter.Compile(g_pPhysLevel))
  188. {
  189. free(g_pPhysLevel);
  190. g_pPhysLevel = NULL;
  191. g_PhysLevelSize = 0;
  192. }
  193. else
  194. {// Msg("Compiled PhysLevel: %.1fk\n", g_PhysLevelSize / 1024.0);
  195. emitter.PrintStats();
  196. }
  197. }