particleservice.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. #include "particleservice.h"
  2. #include "..\manager\particlemanager.h"
  3. #include "..\datacache\DataCache.h"
  4. #include "..\..\common_h\SetThreadName.h"
  5. INTERFACE_FUNCTION
  6. CREATE_SERVICE(ParticleService, 30)
  7. #define MAX_WAIT_TIME (500)
  8. ParticleService* PService = NULL;
  9. ParticleService::ParticleService () : CreatedManagers (_FL_),
  10. allData (_FL_, 2048)
  11. {
  12. #ifdef ENABLE_PARTICLE_THREADS
  13. pManagerToExecute = NULL;
  14. dwNeedCloseThread = 0;
  15. hCanStartUpdate = NULL;
  16. hThreadDone = NULL;
  17. hUpdateThread = NULL;
  18. #endif
  19. dwCurrentFrame = 0;
  20. #ifndef _XBOX
  21. pIBuffer = NULL;
  22. #endif
  23. PService = this;
  24. sysDelete = false;
  25. globalDataCache = NULL;
  26. bLowQuality = false;
  27. }
  28. ParticleService::~ParticleService ()
  29. {
  30. #ifdef ENABLE_PARTICLE_THREADS
  31. InterlockedIncrement(&dwNeedCloseThread);
  32. //Что бы поток отпустить...
  33. SetEvent(hCanStartUpdate);
  34. if (hUpdateThread)
  35. {
  36. for (;;)
  37. {
  38. DWORD waitResult = WaitForSingleObject(hUpdateThread, MAX_WAIT_TIME);
  39. if (waitResult != WAIT_TIMEOUT)
  40. {
  41. break;
  42. }
  43. }
  44. }
  45. if( hCanStartUpdate )
  46. {
  47. CloseHandle( hCanStartUpdate );
  48. hCanStartUpdate = NULL;
  49. }
  50. hUpdateThread = NULL;
  51. hCanStartUpdate = NULL;
  52. #endif
  53. #ifndef _XBOX
  54. if (pIBuffer)
  55. {
  56. pIBuffer->Release();
  57. pIBuffer = NULL;
  58. }
  59. #endif
  60. for (dword i = 0; i < VB_FRAMES_COUNT; i++)
  61. {
  62. vbFrames[i].Release();
  63. }
  64. sysDelete = true;
  65. if (CreatedManagers.Size () > 0)
  66. {
  67. api->Trace("Unreleased particles managers found !\n");
  68. }
  69. for (int n = 0; n < CreatedManagers; n++)
  70. {
  71. api->Trace("Manager created in %s, Line %d\n", CreatedManagers[n].FileName, CreatedManagers[n].Line);
  72. CreatedManagers[n].pManager->Release();
  73. }
  74. delete spriteProcessor;
  75. spriteProcessor = NULL;
  76. delete globalDataCache;
  77. PService = NULL;
  78. }
  79. #ifdef ENABLE_PARTICLE_THREADS
  80. void ParticleService::ThreadExecute(LPVOID lpThreadParameter)
  81. {
  82. ParticleService* srv = (ParticleService*)lpThreadParameter;
  83. while (true)
  84. {
  85. if (!srv->threadUpdate()) break;
  86. }
  87. ExitThread(0xDEAD);
  88. }
  89. #endif
  90. bool ParticleService::Init()
  91. {
  92. IFileService *storage = (IFileService *)api->GetService("FileService");
  93. Assert(storage)
  94. IRender * pRS = (IRender*)api->GetService("DX9Render");
  95. Assert(pRS)
  96. #ifdef _XBOX
  97. //во write-combined память кладем партиклы на боксе
  98. DWORD dwFlags = 0;
  99. #else
  100. DWORD dwFlags = USAGE_WRITEONLY | USAGE_DYNAMIC;
  101. #endif
  102. for (dword i = 0; i < VB_FRAMES_COUNT; i++)
  103. {
  104. vbFrames[i].Create(pRS, dwFlags);
  105. }
  106. #ifndef _XBOX
  107. pIBuffer = pRS->CreateIndexBuffer(_MAX_BILLBOARDS * 6 * sizeof(WORD), _FL_, dwFlags);
  108. WORD * pTrgs = (WORD*)pIBuffer->Lock();
  109. Assert(pTrgs != NULL);
  110. for (long i = 0; i < _MAX_BILLBOARDS; i++)
  111. {
  112. pTrgs[i * 6 + 0] = WORD(i * 4 + 0);
  113. pTrgs[i * 6 + 1] = WORD(i * 4 + 1);
  114. pTrgs[i * 6 + 2] = WORD(i * 4 + 2);
  115. pTrgs[i * 6 + 3] = WORD(i * 4 + 0);
  116. pTrgs[i * 6 + 4] = WORD(i * 4 + 2);
  117. pTrgs[i * 6 + 5] = WORD(i * 4 + 3);
  118. }
  119. pIBuffer->Unlock();
  120. #endif
  121. IIniFile *ini = storage->SystemIni();
  122. if( ini )
  123. {
  124. bLowQuality = ini->GetLong("particles", "lowquality", 0) != 0;
  125. }
  126. api->SetStartFrameLevel(this, Core_DefaultExecuteLevel);
  127. api->SetEndFrameLevel(this, Core_DefaultExecuteLevel + 0x100);
  128. spriteProcessor = NEW BillBoardProcessor;
  129. globalDataCache = NEW DataCacheGlobal();
  130. LoadAllfromDisk();
  131. #ifdef ENABLE_PARTICLE_THREADS
  132. hCanStartUpdate = CreateEvent( null, false, false, null );
  133. ResetEvent(hCanStartUpdate);
  134. hThreadDone = CreateEvent( null, true, false, null );
  135. SetEvent( hThreadDone );
  136. DWORD dwParticlesThreadID = 0;
  137. hUpdateThread = CreateThread(null, 0, (LPTHREAD_START_ROUTINE)ParticleService::ThreadExecute, this, CREATE_SUSPENDED, &dwParticlesThreadID);
  138. #ifdef _XBOX
  139. SetThreadPriority(hUpdateThread, THREAD_PRIORITY_ABOVE_NORMAL);
  140. XSetThreadProcessor( hUpdateThread, 5 );
  141. #endif
  142. XSetThreadName(dwParticlesThreadID, "Particles::Work");
  143. ResumeThread(hUpdateThread);
  144. #endif
  145. return true;
  146. }
  147. IIBuffer * ParticleService::GetCurrentIndexBuffer()
  148. {
  149. #ifndef _XBOX
  150. return pIBuffer;
  151. #else
  152. return NULL;
  153. #endif
  154. }
  155. IParticleManager* ParticleService::CreateManagerEx (const char* ProjectName, const char* File, int Line)
  156. {
  157. ParticleManager* pManager = NEW ParticleManager (this);
  158. CreatedManager manager;
  159. manager.pManager = pManager;
  160. manager.Line = Line;
  161. manager.FileName = File;
  162. CreatedManagers.Add(manager);
  163. return pManager;
  164. }
  165. void ParticleService::RemoveManagerFromList (IParticleManager* pManager)
  166. {
  167. if (sysDelete) return;
  168. for (int n = 0; n < CreatedManagers; n++)
  169. {
  170. if (CreatedManagers[n].pManager == pManager)
  171. {
  172. CreatedManagers.ExtractNoShift(n);
  173. return;
  174. }
  175. }
  176. }
  177. DWORD ParticleService::GetManagersCount ()
  178. {
  179. return CreatedManagers.Size();
  180. }
  181. IParticleManager* ParticleService::GetManagerByIndex (DWORD Index)
  182. {
  183. return CreatedManagers[Index].pManager;
  184. }
  185. ParticleVB * ParticleService::GetUpdateData()
  186. {
  187. return &vbFrames[dwCurrentFrame];
  188. }
  189. void ParticleService::StartFrame(float dltTime)
  190. {
  191. }
  192. void ParticleService::EndFrame(float dltTime)
  193. {
  194. //OutputDebugString("----------------------\n");
  195. dwCurrentFrame++;
  196. if (dwCurrentFrame >= VB_FRAMES_COUNT)
  197. {
  198. dwCurrentFrame = 0;
  199. }
  200. if (api->DebugKeyState(VK_F3, VK_SHIFT))
  201. {
  202. for (int n = 0; n < CreatedManagers; n++)
  203. {
  204. CreatedManagers[n].pManager->ReloadSystems();
  205. }
  206. }
  207. }
  208. DataCacheGlobal* ParticleService::GetDataCache()
  209. {
  210. return globalDataCache;
  211. }
  212. void ParticleService::LoadAllfromDisk()
  213. {
  214. AssertCoreThread
  215. systemFreeAllDataForGraphs();
  216. IFileService* pFS = (IFileService*)api->GetService("FileService");
  217. #ifdef USE_XML_FILE_FORMAT
  218. // загрузка из XML ресурсов
  219. IFinder * finder = pFS->Finder("*.xml", FFND_NODIRS | FFND_NODOTS);
  220. if(!finder) return;
  221. string sFileName;
  222. for(finder->Begin(".\\resource\\particles\\"); !finder->IsDone(); finder->Next())
  223. {
  224. sFileName = finder->FileName();
  225. pDataCache->CacheSystemXML(sFileName);
  226. }
  227. finder->Release();
  228. #else
  229. DWORD dwStartTime = GetTickCount();
  230. dword pTime;
  231. RDTSC_B(pTime);
  232. #ifndef _XBOX
  233. //Загрузка пак-файла если есть такой
  234. IPackFile * pack = pFS->LoadPack("resource\\particles.pkx", _FL_);
  235. #else
  236. IPackFile * pack = pFS->LoadPack("particles.pkx", _FL_);
  237. #endif
  238. // загрузка из бинарных ресурсов
  239. IFinder * finder = pFS->CreateFinder("resource\\particles\\", "*.xps", find_all_files_no_mirrors, _FL_);
  240. if(!finder) return;
  241. for(dword i = 0; i < finder->Count(); i++)
  242. {
  243. const char* sFileName = finder->Name(i);
  244. globalDataCache->CacheSystem(sFileName);
  245. }
  246. finder->Release();
  247. if(pack)
  248. {
  249. pack->Release();
  250. }
  251. RDTSC_E(pTime);
  252. DWORD dwEndTime = GetTickCount();
  253. api->Trace("%d particles loaded by %d ticks - %3.2f seconds", globalDataCache->GetCachedCount(), pTime , (dwEndTime - dwStartTime) / 1000.0f);
  254. #endif
  255. }
  256. DataGraph* ParticleService::AllocateDataGraph (FieldList* pMaster)
  257. {
  258. DataGraph* Field = DataGraphsPool.Allocate();
  259. Field->SetMasterField(pMaster);
  260. //DataGraph* Field = NEW DataGraph(pMaster);
  261. return Field;
  262. }
  263. void ParticleService::FreeDataGraph (DataGraph* dataGraph)
  264. {
  265. DataGraphsPool.Free(dataGraph);
  266. }
  267. void ParticleService::systemFreeAllDataForGraphs()
  268. {
  269. allData.DelAll();
  270. }
  271. array<GraphVertex> * ParticleService::AllocateDataForGraphs (long dwMinGraphSize, long dwMaxGraphSize,
  272. long &MinGraphDataStart, long &MinGraphDataSize,
  273. long &MaxGraphDataStart, long &MaxGraphDataSize)
  274. {
  275. if (dwMinGraphSize >= 0)
  276. {
  277. if (dwMinGraphSize == 0)
  278. {
  279. MinGraphDataStart = -1;
  280. MinGraphDataSize = 0;
  281. } else
  282. {
  283. dword dwStartIndex = allData.Size();
  284. allData.AddElements(dwMinGraphSize);
  285. allData.Add();
  286. allData.Add();
  287. allData.Add();
  288. MinGraphDataStart = dwStartIndex+3;
  289. MinGraphDataSize = dwMinGraphSize;
  290. }
  291. }
  292. if (dwMaxGraphSize >= 0)
  293. {
  294. if (dwMaxGraphSize == 0)
  295. {
  296. MaxGraphDataStart = -1;
  297. MaxGraphDataSize = 0;
  298. } else
  299. {
  300. dword dwStartIndex = allData.Size();
  301. allData.AddElements(dwMaxGraphSize);
  302. allData.Add();
  303. allData.Add();
  304. allData.Add();
  305. allData.Add();
  306. allData.Add();
  307. MaxGraphDataStart = dwStartIndex+5;
  308. MaxGraphDataSize = dwMaxGraphSize;
  309. }
  310. }
  311. return &allData;
  312. }
  313. #ifdef ENABLE_PARTICLE_THREADS
  314. void ParticleService::StartUpdateThread(ParticleManager * pManager)
  315. {
  316. AssertCoreThread
  317. //OutputDebugString("ParticleService::StartUpdateThread\n");
  318. //Ждем пока поток дообновляет, если он уже обновляет данные
  319. WaitForSingleObject(hThreadDone, INFINITE);
  320. ResetEvent(hThreadDone);
  321. //OutputDebugString("WaitForSingleObject(hThreadDone, INFINITE) - ParticleService::StartUpdateThread\n");
  322. pManagerToExecute = pManager;
  323. ParticleVB * vbToUpdate = GetUpdateData();
  324. vbToUpdate->Lock();
  325. Assert(vbToUpdate->pParticlesVerts);
  326. Assert(vbToUpdate->pParticlesXZVerts);
  327. Assert(vbToUpdate->pDistortedParticlesVerts);
  328. Assert(vbToUpdate->pDistortedParticlesXZVerts);
  329. //Можно уже обновлять...
  330. //OutputDebugString("hCanStartUpdate - fired. ParticleService::StartUpdateThread()\n");
  331. SetEvent(hCanStartUpdate);
  332. }
  333. void ParticleService::WaitUntilUpdateFinished()
  334. {
  335. AssertCoreThread
  336. //OutputDebugString("ParticleService::WaitUntilUpdateAndStartDraw\n");
  337. //Ждем пока поток дообновляет, если он уже обновляет данные
  338. WaitForSingleObject(hThreadDone, INFINITE);
  339. //OutputDebugString("WaitForSingleObject(hThreadDone, INFINITE) - ParticleService::WaitUntilUpdateAndStartDraw\n");
  340. pManagerToExecute = NULL;
  341. //Разлочить буффер - можно рисовать теперь...
  342. ParticleVB * vbToUpdate = GetUpdateData();
  343. if (vbToUpdate->pParticlesVerts != NULL)
  344. {
  345. vbToUpdate->Unlock();
  346. }
  347. }
  348. bool ParticleService::threadUpdate()
  349. {
  350. //OutputDebugString("ParticleService::threadUpdate\n");
  351. //Ждем пока не разрешат обновлять...
  352. WaitForSingleObject(hCanStartUpdate, INFINITE);
  353. //Может нужно завершить поток (закрывается движок)
  354. if (InterlockedCompareExchange(&dwNeedCloseThread, 0, 0) != 0)
  355. {
  356. //OutputDebugString("hThreadDone - fired. ParticleService::threadUpdate()\n");
  357. SetEvent(hThreadDone);
  358. return false;
  359. }
  360. //Обновляем тексущий манагер
  361. Assert(pManagerToExecute);
  362. pManagerToExecute->Update();
  363. //Может нужно завершить поток (закрывается движок)
  364. if (InterlockedCompareExchange(&dwNeedCloseThread, 0, 0) != 0)
  365. {
  366. //OutputDebugString("hThreadDone - fired. ParticleService::threadUpdate()\n");
  367. SetEvent(hThreadDone);
  368. return false;
  369. }
  370. //OutputDebugString("hThreadDone - fired. ParticleService::threadUpdate()\n");
  371. SetEvent(hThreadDone);
  372. return true;
  373. }
  374. #endif