PhysicsService.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. #include "PhysicsService.h"
  2. #include "PhysicsScene.h"
  3. #include "..\Common_h\Render.h"
  4. #include "..\Common_h\FileService.h"
  5. #include "..\Common_h\LocStrings.h"
  6. #include "..\Common_h\SetThreadName.h"
  7. #include "PhysCharacter.h"
  8. #include "PhysRigidBody.h"
  9. #include "PhysCloth.h"
  10. #include "PhysTriangleMesh.h"
  11. #include "PhysRagdoll.h"
  12. #include "NxCooking.h"
  13. #include "ClothMeshBuilderProxy.h"
  14. #include "IProxy.h"
  15. #include "Deferrer.h"
  16. //#define NOMINMAX //suppress windows' global min,max macros.
  17. //============================================================================================
  18. INTERFACE_FUNCTION
  19. CREATE_SERVICE(PhysicsService, 19)
  20. #ifndef _XBOX
  21. #pragma comment(lib, "PhysXLoader.lib")
  22. #endif
  23. #pragma comment(lib, "NxCharacter.lib")
  24. #pragma comment(lib, "NxCooking.lib")
  25. #ifndef STOP_DEBUG
  26. bool PhysicsService::m_gShowColliders = false;
  27. bool PhysicsService::m_gShowPhysBoxes = false;
  28. long PhysicsService::m_gMaterialIndex = -1;
  29. bool PhysicsService::m_gShowWorldPoint = false;
  30. Vector PhysicsService::m_gWorldPoint = 0.0f;
  31. #endif
  32. //============================================================================================
  33. PhysicsService::PhysicsService() : scenes(_FL_),
  34. meshes(_FL_),
  35. builders(_FL_),
  36. m_scenes2Execute(_FL_, 16)
  37. {
  38. physicsSDK = null;
  39. console = null;
  40. m_ctrManager = null;
  41. isHardware = false;
  42. isEnableDebug = false;
  43. isStop = false;
  44. isMultiThreading = false;
  45. m_hThread = null;
  46. m_hSimulateStartEvent = null;
  47. m_hExitEvent = null;
  48. MemPool::ptr = NEW MemPool(); Assert(MemPool::ptr);
  49. }
  50. PhysicsService::~PhysicsService()
  51. {
  52. if (isMultiThreading)
  53. {
  54. SetEvent(m_hExitEvent);
  55. for (int i=0; i<5; i++)
  56. {
  57. if ( WaitForSingleObject(m_hThread, 2000) == WAIT_OBJECT_0 )
  58. break;
  59. api->Trace("PhysicsService: Killing thread problem!");
  60. }
  61. CloseHandle(m_hThread);
  62. CloseHandle(m_hSimulateStartEvent);
  63. CloseHandle(m_hExitEvent);
  64. }
  65. if (m_ctrManager)
  66. NxReleaseControllerManager(m_ctrManager);
  67. while(scenes)
  68. {
  69. scenes[0]->Release();
  70. }
  71. while(meshes)
  72. {
  73. meshes[0]->Release();
  74. }
  75. if(physicsSDK)
  76. {
  77. physicsSDK->release();
  78. }
  79. physicsSDK = null;
  80. DELETE(MemPool::ptr);
  81. }
  82. //Создать сцену
  83. IPhysicsScene * PhysicsService::CreateScene()
  84. {
  85. return NEW PhysicsScene(this);
  86. }
  87. //Текущий режим работы
  88. bool PhysicsService::IsHardware()
  89. {
  90. return isHardware;
  91. }
  92. //Использование мультипоточности
  93. bool PhysicsService::IsMultiThreading()
  94. {
  95. return isMultiThreading;
  96. }
  97. //Текущий режим дебаг инфы
  98. bool PhysicsService::IsEnableDebug()
  99. {
  100. return isEnableDebug;
  101. }
  102. //Создать сетку, основываясь на бинарных данных
  103. IPhysTriangleMesh * PhysicsService::CreateTriangleMesh(const void * meshData, dword meshDataSize, const void * pMapData, dword pMapDataSize)
  104. {
  105. MemoryReadStream memoryStream(meshData, meshDataSize);
  106. // останавливаем отдельный поток с физикой
  107. csSimulate.Enter();
  108. NxTriangleMesh * trgMesh = physicsSDK->createTriangleMesh(memoryStream);
  109. csSimulate.Leave();
  110. if(!trgMesh)
  111. return null;
  112. /*if(pMapData && pMapDataSize)
  113. {
  114. NxPMap pmap;
  115. pmap.data = (void *)pMapData;
  116. pmap.dataSize = pMapDataSize;
  117. trgMesh->loadPMap(pmap);
  118. }*/
  119. PhysTriangleMesh * mesh = NEW PhysTriangleMesh(trgMesh, this);
  120. meshes.Add(mesh);
  121. return mesh;
  122. }
  123. //Создать построитель сеток ткани
  124. IClothMeshBuilder* PhysicsService::CreateClothMeshBuilder()
  125. {
  126. /*#ifdef USE_THREADING
  127. ClothMeshBuilderProxy* pBuilder = NEW ClothMeshBuilderProxy(physicsSDK);
  128. #else*/
  129. ClothMeshBuilder* pBuilder = NEW ClothMeshBuilder(physicsSDK);
  130. /*#endif*/
  131. Assert(pBuilder);
  132. builders.Add(pBuilder);
  133. return pBuilder;
  134. }
  135. //Удаление сетки из списка
  136. void PhysicsService::UnregistryPhysTriangleMesh(IPhysTriangleMesh * obj)
  137. {
  138. NxTriangleMesh * msh = ((PhysTriangleMesh *)obj)->triangleMesh;
  139. NxU32 refcnt = msh->getReferenceCount();
  140. Assert(msh);
  141. physicsSDK->releaseTriangleMesh(*msh);
  142. meshes.Del(obj);
  143. }
  144. //Удаление сетки из списка
  145. void PhysicsService::UnregistryClothMeshBuilder(IClothMeshBuilder * obj)
  146. {
  147. builders.Del(obj);
  148. }
  149. #ifndef STOP_DEBUG
  150. IProxy * FindProxyObject(NxActor * actor)
  151. {
  152. PhysicsService * srv = (PhysicsService*)api->GetService("PhysicsService");
  153. return srv->FindProxyObject(actor);
  154. }
  155. //Ищем прокси объект во всех сценах с данным актером
  156. IProxy * PhysicsService::FindProxyObject(NxActor * actor)
  157. {
  158. for (long i=0; i<scenes; i++)
  159. {
  160. IProxy * object = scenes[i]->FindProxyObject(actor);
  161. if (object)
  162. return object;
  163. }
  164. return null;
  165. }
  166. #endif
  167. //Инициализация
  168. bool PhysicsService::Init()
  169. {
  170. IFileService * fs = (IFileService *)api->GetService("FileService");
  171. IIniFile * pIni = fs->SystemIni();
  172. NxReal enableDebug = (NxReal)0;
  173. isEnableDebug = false;
  174. isHardware = false;
  175. bool isEnabledWarnings = false;
  176. string debugHost;
  177. if (pIni)
  178. {
  179. #ifndef STOP_DEBUG
  180. isEnableDebug = pIni->GetLong("Physics", "debug", 0) != 0;
  181. enableDebug = (isEnableDebug) ? (NxReal)1 : (NxReal)0;
  182. debugHost = pIni->GetString("Physics", "debughost", "");
  183. #endif
  184. isHardware = pIni->GetLong("Physics", "hw", 0) != 0;
  185. isStop = pIni->GetLong("Physics", "stop", 0) != 0;
  186. isMultiThreading = (api->GetThreadingInfo() != ICore::mt_none);
  187. isEnabledWarnings = pIni->GetLong("Physics", "warnings", 0) != 0;
  188. RELEASE(pIni);
  189. }
  190. errorStream.EnableWarnings(isEnabledWarnings);
  191. //Создаём объект
  192. physicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION, &allocator, &errorStream);
  193. dword version = NX_PHYSICS_SDK_VERSION;
  194. if (!physicsSDK)
  195. {
  196. Error(1000200, "PhysicsService: Can't init PhysX SDK");
  197. return false;
  198. }
  199. m_ctrManager = NxCreateControllerManager(&allocator);
  200. NxInitCooking();
  201. #ifndef STOP_DEBUG
  202. if(!debugHost.IsEmpty())
  203. {
  204. physicsSDK->getFoundationSDK().getRemoteDebugger()->connect(debugHost);
  205. }
  206. #endif
  207. physicsSDK->setParameter(NX_SKIN_WIDTH, 0.01f);
  208. physicsSDK->setParameter(NX_DEFAULT_SLEEP_LIN_VEL_SQUARED, 0.2f*0.2f);
  209. physicsSDK->setParameter(NX_DEFAULT_SLEEP_ANG_VEL_SQUARED, 0.15f*0.15f);
  210. physicsSDK->setParameter(NX_VISUALIZATION_SCALE, 0.25f * enableDebug);
  211. physicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, enableDebug);
  212. physicsSDK->setParameter(NX_VISUALIZE_JOINT_LIMITS, enableDebug);
  213. physicsSDK->setParameter(NX_VISUALIZE_JOINT_LOCAL_AXES, enableDebug);
  214. physicsSDK->setParameter(NX_STA_FRICT_SCALING, 1.0f);
  215. physicsSDK->setParameter(NX_DYN_FRICT_SCALING, 1.0f);
  216. // Set the physics parameters
  217. // Set the debug visualization parameters
  218. //physicsSDK->setParameter(NX_VISUALIZATION_SCALE, 1);
  219. //physicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES, 1);
  220. //physicsSDK->setParameter(NX_VISUALIZE_JOINT_LOCAL_AXES, 1);
  221. //physicsSDK->setParameter(NX_VISUALIZE_JOINT_FORCE, enableDebug);
  222. //physicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES, enableDebug);
  223. //physicsSDK->setParameter(NX_VISUALIZE_JOINT_WORLD_AXES, enableDebug);
  224. //physicsSDK->setParameter(NX_VISUALIZE_JOINT_LOCAL_AXES, enableDebug);
  225. //physicsSDK->setParameter( NX_VISUALIZE_JOINT_LOCAL_AXES, 1);
  226. //physicsSDK->setParameter(NX_VISUALIZE_JOINT_LIMITS, 1);
  227. //physicsSDK->setParameter(NX_VISUALIZE_COLLISION_EDGES, enableDebug);
  228. //physicsSDK->setParameter(NX_CONTINUOUS_CD, 1.0f);
  229. api->SetStartFrameLevel(this, Core_DefaultExecuteLevel);
  230. api->SetEndFrameLevel(this, Core_DefaultExecuteLevel+0x1000);
  231. if (isMultiThreading)
  232. {
  233. m_hSimulateStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL); Assert(m_hSimulateStartEvent);
  234. m_hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); Assert(m_hExitEvent);
  235. // стартуем аццкий поток
  236. DWORD dwPhysicsThreadID = 0;
  237. m_hThread = CreateThread(NULL, 512 * 1024, (LPTHREAD_START_ROUTINE)&SimulationThread, this, CREATE_SUSPENDED, &dwPhysicsThreadID);
  238. Assert(m_hThread);
  239. #ifdef _XBOX
  240. ::XSetThreadProcessor(m_hThread, 2);
  241. ::SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST);
  242. #endif
  243. XSetThreadName(dwPhysicsThreadID, "Physics::Simulate");
  244. ResumeThread(m_hThread);
  245. }
  246. api->Trace("Physics started in %s mode", (isMultiThreading) ? "multithread" : "singlethread");
  247. return true;
  248. }
  249. void PhysicsService::Error(long id, const char * errorEnglish)
  250. {
  251. ILocStrings * locStrings = (ILocStrings*)api->GetService("LocStrings");
  252. ICoreStorageString * storage = api->Storage().GetItemString("system.error", _FL_);
  253. const char * errorString = (locStrings) ? locStrings->GetString(id) : null;
  254. storage->Set((errorString) ? errorString : errorEnglish);
  255. storage->Release();
  256. }
  257. //Исполнение в начале кадра
  258. void PhysicsService::StartFrame(float dltTime)
  259. {
  260. #if !defined(STOP_DEBUG) && !defined(_XBOX)
  261. if (!console)
  262. {
  263. console = (IConsole *)api->GetService("Console");
  264. if(console)
  265. {
  266. console->Register_PureC_Command("sc", "sc [mat index, -1 for all mats] Show/hide all colliders", &Console_ShowColliders);
  267. console->Register_PureC_Command("spb", "Show/hide all phys objects boxes", &Console_ShowPhysBoxes);
  268. console->Register_PureC_Command("null", "null [x,y,z] Show/hide pointer to world point(no parameters = 0, 0, 0)", &Console_ShowNull);
  269. }
  270. }
  271. #endif
  272. // Очищаем очередь на выполнение в начале кадра
  273. csArrayUpdate.Enter();
  274. m_scenes2Execute.Empty();
  275. csArrayUpdate.Leave();
  276. }
  277. #ifndef STOP_DEBUG
  278. void _cdecl PhysicsService::Console_ShowNull(const ConsoleStack & params)
  279. {
  280. if (!params.GetSize())
  281. {
  282. m_gShowWorldPoint ^= 1;
  283. m_gWorldPoint = 0.0f;
  284. }
  285. else
  286. {
  287. if (params.GetSize() == 1)
  288. {
  289. m_gShowWorldPoint = true;
  290. m_gWorldPoint = float(atof(params.GetParam(0)));
  291. }
  292. else
  293. {
  294. m_gShowWorldPoint = true;
  295. m_gWorldPoint.x = float(atof(params.GetParam(0)));
  296. m_gWorldPoint.y = float(atof(params.GetParam(1)));
  297. m_gWorldPoint.z = float(atof(params.GetParam(2)));
  298. }
  299. }
  300. }
  301. void _cdecl PhysicsService::Console_ShowColliders(const ConsoleStack & params)
  302. {
  303. if (!params.GetSize())
  304. {
  305. m_gShowColliders ^= 1;
  306. m_gMaterialIndex = -1;
  307. }
  308. else
  309. {
  310. m_gShowColliders = true;
  311. m_gMaterialIndex = atol(params.GetParam(0));
  312. }
  313. }
  314. void _cdecl PhysicsService::Console_ShowPhysBoxes(const ConsoleStack & params)
  315. {
  316. m_gShowPhysBoxes ^= 1;
  317. }
  318. void PhysicsService::DrawSceneStat(unsigned int index)
  319. {
  320. if (scenes.Size() <= index)
  321. return;
  322. /*IRender * rs = (IRender *)api->GetService("DX9Render");
  323. scenes[index]->DebugDraw(*rs);
  324. return;*/
  325. api->Trace("");
  326. api->Trace("-----------------------------------------------------");
  327. api->Trace("Physics statistics. Scene #%d", index);
  328. api->Trace("Name = Current, Max");
  329. const NxSceneStats2 * stats = scenes[index]->Scene().getStats2();
  330. unsigned int count = 0;
  331. for (unsigned int i = 0; i < stats->numStats; ++i)
  332. {
  333. if (stats->stats[i].parent == 0xFFFFFFFF )
  334. api->Trace("%s = %d, %d", stats->stats[i].name, stats->stats[i].curValue, stats->stats[i].maxValue);
  335. else
  336. api->Trace(" %s = %d, %d", stats->stats[i].name, stats->stats[i].curValue, stats->stats[i].maxValue);
  337. ++count;
  338. }
  339. api->Trace("-----------------------------------------------------");
  340. api->Trace("");
  341. }
  342. #endif
  343. //Исполнение в конце кадра
  344. void PhysicsService::EndFrame(float dltTime)
  345. {
  346. #ifndef STOP_DEBUG
  347. if ( api->DebugKeyState(VK_MENU, VK_F5) )
  348. for (unsigned int i = 0; i < scenes.Size(); ++i)
  349. DrawSceneStat(i);
  350. #endif
  351. }
  352. void PhysicsService::AddScene2Execute(PhysicsScene * scene)
  353. {
  354. csArrayUpdate.Enter();
  355. m_scenes2Execute.Add(scene);
  356. csArrayUpdate.Leave();
  357. SetEvent(m_hSimulateStartEvent);
  358. }
  359. // ВНИМАНИЕ! функция рабочего потока
  360. dword __stdcall PhysicsService::SimulationThread(void * ptr)
  361. {
  362. PhysicsService * svc = (PhysicsService *)ptr;
  363. HANDLE waits[] = {svc->m_hSimulateStartEvent, svc->m_hExitEvent};
  364. while (true)
  365. {
  366. DWORD waitResult = WaitForMultipleObjects(ARRSIZE(waits), waits, FALSE, INFINITE );
  367. if (waitResult == (WAIT_OBJECT_0 + 1))
  368. break;
  369. svc->csSimulate.Enter();
  370. while (true)
  371. {
  372. svc->csArrayUpdate.Enter();
  373. PhysicsScene * scene = null;
  374. if (svc->m_scenes2Execute.Len())
  375. {
  376. scene = svc->m_scenes2Execute[ svc->m_scenes2Execute.Last() ];
  377. svc->m_scenes2Execute.Extract(svc->m_scenes2Execute.Last());
  378. }
  379. svc->csArrayUpdate.Leave();
  380. if (!scene)
  381. break;
  382. scene->Scene().simulate( scene->GetLastDeltaTime() );
  383. scene->Scene().flushStream();
  384. scene->SimulationDone();
  385. }
  386. svc->csSimulate.Leave();
  387. }
  388. return 0;
  389. }
  390. //============================================================================================
  391. //PhysicsService::Allocator
  392. //============================================================================================
  393. void * PhysicsService::Allocator::malloc(NxU32 size)
  394. {
  395. return api->Reallocate(null, size, _FL_);
  396. }
  397. void * PhysicsService::Allocator::mallocDEBUG(NxU32 size,const char * fileName, int line)
  398. {
  399. return api->Reallocate(null, size, fileName, line);
  400. }
  401. void * PhysicsService::Allocator::realloc(void * memory, NxU32 size)
  402. {
  403. return api->Reallocate(memory, size, _FL_);
  404. }
  405. void PhysicsService::Allocator::free(void * memory)
  406. {
  407. api->Free(memory, _FL_);
  408. }