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.

402 lines
12 KiB

  1. //========= Copyright c 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Builds physics2 collision models from studio model source
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include <string.h>
  10. #include "tier1/tier1.h"
  11. #include "tier1/smartptr.h"
  12. #include "tier2/p4helpers.h"
  13. #include "datalinker.h"
  14. #include "vphysics2_interface.h"
  15. #include "vphysics2_interface_flags.h"
  16. #include "alignedarray.h"
  17. #include "studiomdl.h"
  18. #include "filesystem_tools.h"
  19. #include "collisionmodelsource.h"
  20. #include "physics2collision.h"
  21. #include "physdll.h"
  22. #include "phzfile.h"
  23. static IPhysics2Cook *g_pCook;
  24. struct bodypart_t
  25. {
  26. IPhysics2CookedMeshBase* mesh;
  27. int bone;
  28. bodypart_t(){}
  29. bodypart_t(IPhysics2CookedMeshBase* _mesh, int _bone):mesh(_mesh),bone(_bone){}
  30. };
  31. class CPhysics2CollisionBuilder: public CCollisionModelSource
  32. {
  33. public:
  34. void Init(CCollisionModelSource *pSource)
  35. {
  36. *static_cast<CCollisionModelSource*>(this) = *pSource;
  37. }
  38. void Shutdown()
  39. {
  40. Destroy(m_bodyparts);
  41. }
  42. void Destroy(CUtlVector<bodypart_t>&bodyparts)
  43. {
  44. for(int i = 0; i < bodyparts.Size(); ++i)
  45. g_pCook->Destroy(bodyparts[i].mesh);
  46. }
  47. void Build()
  48. {
  49. if(m_isJointed)
  50. BuildJointed();
  51. else
  52. BuildRigid();
  53. }
  54. void BuildRigid();
  55. void BuildJointed();
  56. void Write();
  57. void Destroy(CUtlVector<IPhysics2CookedMeshBase*> &arrPolytopes);
  58. CUtlVector<bodypart_t> m_bodyparts;
  59. };
  60. class CMeshAdaptor:public CPhysics2CustomMeshBase
  61. {
  62. public:
  63. virtual uint GetType()const {return PHYSICS2_SHAPE_TYPE_CUSTOM;}
  64. virtual uint NumVertices() const {return m_pMesh->numvertices;}
  65. virtual uint NumTriangles() const {return m_pMesh->numfaces;}
  66. virtual void GetVertices(float *pVertsOut, uint nByteStride, const fltx4 &factor = Four_Ones)
  67. {
  68. uint numVerts = m_pMesh->numvertices;
  69. byte *pOut = (byte*)pVertsOut;
  70. for(uint i =0; i< numVerts; ++i)
  71. {
  72. fltx4 vert = MulSIMD(LoadUnaligned3SIMD(&m_pVerts[i+m_pMesh->vertexoffset].x), factor);
  73. StoreUnaligned3SIMD((float*)pOut, vert);
  74. pOut += nByteStride;
  75. }
  76. }
  77. virtual void GetTriangles(int *pTrisOut, uint nByteStride)
  78. {
  79. uint numTris = m_pMesh->numfaces;
  80. byte *pOut = (byte*)pTrisOut;
  81. for(uint i = 0;i < numTris; ++i)
  82. {
  83. const s_face_t *pFace = m_pFaces + i + m_pMesh->faceoffset;
  84. Assert(pFace->a+m_pMesh->vertexoffset < (uint)m_pMesh->numvertices && pFace->b+m_pMesh->vertexoffset < (uint)m_pMesh->numvertices && pFace->c+m_pMesh->vertexoffset < (uint)m_pMesh->numvertices
  85. );
  86. ((int*)pOut)[0] = pFace->a;
  87. ((int*)pOut)[1] = pFace->b;
  88. ((int*)pOut)[2] = pFace->c;
  89. pOut += nByteStride;
  90. }
  91. }
  92. virtual uint GetSizeOf()const {return sizeof(*this);}
  93. const s_face_t *m_pFaces;// non-offset faces
  94. const Vector *m_pVerts; // non-offset verts
  95. const s_mesh_t *m_pMesh;
  96. };
  97. static CPhysics2CollisionBuilder g_builder;
  98. void Physics2Collision_Build(CCollisionModelSource *pSource)
  99. {
  100. g_pCook = g_pPhysics2->GetCook();
  101. g_builder.Init(pSource);
  102. g_builder.Build();
  103. }
  104. void Physics2Collision_Write()
  105. {
  106. g_builder.Write();
  107. }
  108. void CPhysics2CollisionBuilder::BuildJointed()
  109. {
  110. // first, go through all meshes and determine what bones they belong to
  111. //CUtlVector<CUtlVector<int> > arrMeshBones(0,m_pModel->nummeshes);
  112. // remap it : bone -> faces
  113. CUtlVector<CUtlVector<s_face_t> > arrBoneFaces;
  114. arrBoneFaces.SetSize(m_pModel->numbones);
  115. // Constructing elements of the array. This is irritating, there should be a method to do that..
  116. for(int i =0; i < m_pModel->numbones; ++i)
  117. new(&arrBoneFaces[i])CUtlVector<s_mesh_t *>(32);
  118. //for(int i = 0; i < m_pModel->nummeshes; ++i)
  119. // new(&arrMeshBones[i])CUtlVector<int>();
  120. // for each mesh, find bone(s) it belongs to and push it to that bone (those bones)
  121. for(int nMesh = 0; nMesh < m_pModel->nummeshes; ++nMesh)
  122. {
  123. s_mesh_t *pMesh = m_pModel->mesh + m_pModel->meshindex[nMesh];
  124. for(int nFace = 0; nFace < pMesh->numfaces; ++nFace)
  125. {
  126. s_face_t face = GetGlobalFace(pMesh, nFace);
  127. s_boneweight_t &boneweight = m_pModel->vertex[face.a].boneweight;
  128. if(boneweight.numbones)
  129. {
  130. int boneIndex = RemapBone(boneweight.bone[0]);
  131. if(boneIndex >= 0 && boneIndex < m_pModel->numbones)
  132. arrBoneFaces[boneIndex].AddToTail(face);
  133. }
  134. }
  135. }
  136. // for each bone, we have 0..many meshes now; compile the meshes; we don't try to share the meshes between different bones here,
  137. // the idea is that we'll have rigid binding to skeleton, possibly sometimes multiple meshes to the same bone, but not the same mesh
  138. // to multiple bones
  139. CUtlVector<Vector> bonespaceVerts;
  140. bonespaceVerts.SetCount(m_pModel->numvertices);
  141. for(int nBone = 0; nBone < m_pModel->numbones; ++nBone)
  142. {
  143. CUtlVector<IPhysics2CookedMeshBase*> arrPolytopes;
  144. bodypart_t bodypart;
  145. bodypart.bone = nBone;
  146. bodypart.mesh = NULL;
  147. CUtlVector<s_face_t> &arrFaces = arrBoneFaces[nBone];
  148. if(ShouldProcessBone(nBone) && arrFaces.Size())
  149. {
  150. // convert ALL vertices into this bone's frame (it's easier)
  151. ConvertToBoneSpace(nBone, bonespaceVerts);
  152. // cook one polytope for each s_mesh_t (out of the Mesh interface)
  153. s_mesh_t mesh;
  154. mesh.faceoffset = 0;
  155. mesh.numfaces = arrFaces.Size();
  156. mesh.vertexoffset = 0;
  157. mesh.numvertices = bonespaceVerts.Size();
  158. CMeshAdaptor adaptor;
  159. adaptor.m_pMesh = &mesh;
  160. adaptor.m_pFaces = arrFaces.Base();
  161. adaptor.m_pVerts = bonespaceVerts.Base();
  162. if(IPhysics2CookedPolytope *pCookedPolytope = g_pCook->CookPolytope(&adaptor))
  163. arrPolytopes.AddToTail(pCookedPolytope);
  164. }
  165. if(arrPolytopes.Size() > 1)
  166. {
  167. if(m_allowConcaveJoints)
  168. {
  169. bodypart.mesh = g_pCook->CookMopp(arrPolytopes.Base(), arrPolytopes.Size());
  170. }
  171. else
  172. {
  173. bodypart.mesh = g_pCook->CookPolytopeFromMeshes(arrPolytopes.Base(), arrPolytopes.Size());
  174. }
  175. Destroy(arrPolytopes);
  176. }
  177. else
  178. if(arrPolytopes.Size() == 1)
  179. {
  180. bodypart.mesh = arrPolytopes[0];
  181. }
  182. if(bodypart.mesh)
  183. m_bodyparts.AddToTail(bodypart);
  184. }
  185. }
  186. void CPhysics2CollisionBuilder::BuildRigid()
  187. {
  188. CUtlVector<Vector> worldspaceVerts;
  189. worldspaceVerts.SetCount(m_pModel->numvertices);
  190. ConvertToWorldSpace( worldspaceVerts );
  191. m_bodyparts.SetSize(0);
  192. bool bValid = true;
  193. if ( m_allowConcave )
  194. {
  195. CUtlVector<CMeshAdaptor> arrMeshes;
  196. int numMeshes = m_pModel->nummeshes;
  197. arrMeshes.SetCount(numMeshes);
  198. for ( int i = 0; i < numMeshes; i++ )
  199. {
  200. s_mesh_t *pMesh = m_pModel->mesh + m_pModel->meshindex[i];
  201. arrMeshes[i].m_pFaces = m_pModel->face;
  202. arrMeshes[i].m_pVerts = worldspaceVerts.Base();//m_pModel->vertex;
  203. arrMeshes[i].m_pMesh = pMesh;
  204. }
  205. // this is one way to do it: make one polysoup
  206. //g_pCook->CookPolysoupFromMeshes(arrMeshes.Base(), numMeshes);
  207. // another way is to create a bunch of convex polytopes
  208. for ( int i = 0; i < numMeshes; i++ )
  209. {
  210. IPhysics2CookedPolytope *polytope = g_pCook->CookPolytope(&arrMeshes[i]);
  211. if(polytope)
  212. {
  213. m_bodyparts.AddToTail(bodypart_t(polytope, -1));
  214. }
  215. }
  216. }
  217. if ( m_bodyparts.Count() > m_maxConvex )
  218. {
  219. MdlWarning("COSTLY COLLISION MODEL!!!! (%d parts - %d allowed)\n", m_bodyparts.Count(), m_maxConvex );
  220. bValid = false;
  221. }
  222. if ( !bValid && m_bodyparts.Count() )
  223. {
  224. MdlWarning("Error with convex elements of %s, building single convex!!!!\n", m_pModel->filename );
  225. Destroy(m_bodyparts);
  226. }
  227. // either we don't want concave, or there was an error building it
  228. if ( !m_bodyparts.Count() )
  229. {
  230. CUtlVector_Vector4DAligned arrVerts;
  231. arrVerts.SetSize(worldspaceVerts.Count());
  232. for(int i = 0;i < worldspaceVerts.Count(); ++i)
  233. {
  234. const Vector &v = worldspaceVerts[i];
  235. arrVerts[i].Init(v.x,v.y,v.z);
  236. }
  237. IPhysics2CookedPolytope *polytope = g_pCook->CookPolytopeFromVertices((Vector4DAligned*)arrVerts.Base(), worldspaceVerts.Count());
  238. m_bodyparts.AddToTail(bodypart_t(polytope,-1));
  239. }
  240. if(m_bodyparts.Size() > 1)
  241. {
  242. // fold it into one single neat mesh
  243. CUtlVector<IPhysics2CookedMeshBase*>arrMeshes(m_bodyparts.Size(),m_bodyparts.Size());
  244. for(int i = 0;i < m_bodyparts.Size(); ++i)
  245. arrMeshes[i] = m_bodyparts[i].mesh;
  246. IPhysics2CookedMopp *mopp = g_pCook->CookMopp(arrMeshes.Base(), m_bodyparts.Size());
  247. Destroy(m_bodyparts);
  248. if(mopp)
  249. m_bodyparts.AddToTail(bodypart_t(mopp, -1));
  250. }
  251. }
  252. void CPhysics2CollisionBuilder::Destroy(CUtlVector<IPhysics2CookedMeshBase*> &arrPolytopes)
  253. {
  254. for ( int i = 0; i < arrPolytopes.Count(); i++ )
  255. g_pCook->Destroy( arrPolytopes[i] );
  256. arrPolytopes.Purge();
  257. }
  258. void CPhysics2CollisionBuilder::Write()
  259. {
  260. char filename[512];
  261. strcpy( filename, gamedir );
  262. strcat( filename, "models/" );
  263. strcat( filename, m_pOverrideName ? m_pOverrideName : outname );
  264. Q_SetExtension( filename, ".phz", sizeof( filename ) );
  265. if(!m_bodyparts.Size())
  266. {
  267. CPlainAutoPtr< CP4File > spFile( g_p4factory->AccessFile( filename ) );
  268. unlink(filename);
  269. return;
  270. }
  271. DataLinker::Stream stream;
  272. Physics2CollisionHeader_t *pHeader = stream.Write<Physics2CollisionHeader_t>();
  273. pHeader->m_dataVersion = g_pPhysics2->GetSerializeVersion();
  274. pHeader->m_numBones = m_bodyparts.Size();
  275. //if(!m_pModel->numbones)
  276. // pHeader->m_numBones = 1; // there's still 1 pseudo-bone there
  277. Physics2RigidPolyShape_t *pRigids = stream.IStream::WriteAndLinkStrided(&pHeader->m_shapes, sizeof(Physics2RigidPolyShape_t), m_bodyparts.Count());
  278. ///
  279. // Note: I want all inertia descriptors to reside together for cache coherency in dynamics phase, so I'm writing inertia first, then the shapes
  280. ///
  281. for(int nBodyPart = 0; nBodyPart < m_bodyparts.Size(); ++nBodyPart)
  282. {
  283. int boneIndex = m_bodyparts[nBodyPart].bone;
  284. IPhysics2CookedMeshBase *pMesh = m_bodyparts[nBodyPart].mesh;
  285. const char *boneName = boneIndex < 0 ? "" : m_pModel->localBone[boneIndex].name;
  286. // we'll leave all offsets to NULL if there's no mesh for that bone
  287. if(pMesh)
  288. {
  289. IPhysics2CookedInertia *pInertia = g_pCook->CookInertia(pMesh->GetShape()); // the inertia of the model as a rigid whole
  290. if(pInertia)
  291. {
  292. stream.IStream::Link(&pRigids[nBodyPart].m_inertia, pInertia->Serialize(&stream));
  293. g_pCook->Destroy(pInertia);
  294. }
  295. else
  296. Warning("Could not cook inertia for '%s' #d\n", boneName, boneIndex);
  297. }
  298. pRigids[nBodyPart].m_localBoneIndex = boneIndex;
  299. if(boneIndex >= 0)
  300. {
  301. int globalBoneIndex = m_pModel->boneLocalToGlobal[boneIndex];
  302. pRigids[nBodyPart].m_globalBoneIndex = globalBoneIndex;
  303. }
  304. }
  305. for(int nBodyPart = 0; nBodyPart < m_bodyparts.Size(); ++nBodyPart)
  306. {
  307. bodypart_t &bp = m_bodyparts[nBodyPart];
  308. // we'll leave all offsets to NULL if there's no mesh for that bone
  309. pRigids[nBodyPart].m_shapeType = bp.mesh->GetType();
  310. stream.IStream::Link(&pRigids[nBodyPart].m_shape, bp.mesh->Serialize(&stream));
  311. }
  312. *(char*)stream.WriteBytes(1) = '\n'; // for debugging
  313. for(int nBodyPart = 0; nBodyPart < m_bodyparts.Size(); ++nBodyPart)
  314. {
  315. bodypart_t &bp = m_bodyparts[nBodyPart];
  316. if(bp.bone >= 0)
  317. {
  318. const char *name = m_pModel->localBone[bp.bone].name;
  319. if(name)
  320. {
  321. int nameLen = strlen(name);
  322. char *pNameOut = (char*)stream.WriteBytes(nameLen + 2);
  323. stream.IStream::Link(&pRigids[nBodyPart].m_name, pNameOut);
  324. memcpy(pNameOut, name, nameLen+1);
  325. pNameOut[nameLen+1] = '\n'; // for debugging
  326. }
  327. }
  328. }
  329. uint nDataSize = stream.GetTotalSize();
  330. void *pData = MemAlloc_AllocAligned(nDataSize, 16, __FILE__, __LINE__);
  331. if(stream.Compile(pData))
  332. {
  333. CPlainAutoPtr< CP4File > spFile( g_p4factory->AccessFile( filename ) );
  334. spFile->Edit();
  335. FILE *fp = fopen( filename, "wb" );
  336. if(fp)
  337. {
  338. int numWritten = fwrite(pData, nDataSize, 1, fp);
  339. fclose(fp);
  340. }
  341. else
  342. {
  343. MdlWarning("Error writing %s!!!\n", filename );
  344. }
  345. }
  346. else
  347. {
  348. MdlWarning("Cannot compile the phz data\n");
  349. }
  350. MemAlloc_FreeAligned(pData, __FILE__, __LINE__);
  351. }