2
0

AnimationService.cpp 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. //===========================================================================================================================
  2. // Spirenkov Maxim, 2003
  3. //===========================================================================================================================//
  4. //
  5. //===========================================================================================================================
  6. // AnimationService
  7. //============================================================================================
  8. #include "AnimationService.h"
  9. #include "..\..\Common_h\FileService.h"
  10. #include "..\..\Common_h\SetThreadName.h"
  11. //============================================================================================
  12. CREATE_SERVICE(AnimationService, 30)
  13. //#define DEBUG_THREADS
  14. //============================================================================================
  15. AnimationScene::AnimationScene(AnimationService & s, const char * _cppFile, long _cppLine) : service(s),
  16. animations(_FL_, 1024),
  17. updatingAnimations(_FL_, 1024),
  18. procedural(_FL_, 256),
  19. commands(_FL_)
  20. {
  21. isUpdateProcess = false;
  22. cppFile = _cppFile;
  23. cppLine = _cppLine;
  24. debugUsageMemory = 0;
  25. }
  26. AnimationScene::~AnimationScene()
  27. {
  28. service.ReleaseScene(this);
  29. while(animations.Size() > 0)
  30. {
  31. animations[0]->ForceRelease();
  32. }
  33. while(procedural.Size() > 0)
  34. {
  35. procedural[0]->ForceRelease();
  36. }
  37. }
  38. //Удалить сцену
  39. void AnimationScene::Release()
  40. {
  41. AssertCoreThread
  42. delete this;
  43. }
  44. //Принудительное удаление
  45. dword AnimationScene::ForceRelease()
  46. {
  47. dword count = animations.Size() + procedural.Size();
  48. Release();
  49. return count;
  50. }
  51. //Создать анимацию
  52. IAnimation * AnimationScene::Create(const char * path, const char * cppFile, long cppLine)
  53. {
  54. #ifdef DEBUG_THREADS
  55. api->Trace("AnimationScene::Create; Scene = %.8x", this);
  56. #endif
  57. AssertCoreThread
  58. AnxData * data = service.Create(path);
  59. if(!data)
  60. {
  61. return null;
  62. }
  63. Animation * ani = NEW Animation(*data, service, *this, path, cppFile, cppLine);
  64. animations.Add(ani);
  65. return ani;
  66. }
  67. //Создать пустую анимацию
  68. IAnimation * AnimationScene::CreateEmpty(const Bone * skeleton, dword count, const char * cppFile, long cppLine)
  69. {
  70. #ifdef DEBUG_THREADS
  71. api->Trace("AnimationScene::CreateEmpty; Scene = %.8x", this);
  72. #endif
  73. AssertCoreThread
  74. AnxData * data = service.CreateEmpty(skeleton, count);
  75. Assert(data);
  76. Animation * ani = NEW Animation(*data, service, *this, data->GetName(), cppFile, cppLine);
  77. animations.Add(ani);
  78. return ani;
  79. }
  80. //Создать процедурную анимацию
  81. IAnimationProcedural * AnimationScene::CreateProcedural(const Bone * skeleton, dword count, const char * cppFile, long cppLine)
  82. {
  83. AssertCoreThread
  84. AnimationProcedural * ap = NEW AnimationProcedural(*this, skeleton, count, cppFile, cppLine);
  85. procedural.Add(ap);
  86. return ap;
  87. }
  88. //Обновить состояние сцены
  89. __forceinline void AnimationScene::UpdateScene(float dltTime)
  90. {
  91. //Дополнительный поток уже гарантированно остановлен
  92. AssertCoreThread
  93. #ifdef DEBUG_THREADS
  94. api->Trace("AnimationScene::UpdateScene -> srtart update; Scene = %.8x", this);
  95. #endif
  96. //Исполняем накопленные команды
  97. for(long i = 0; i < commands; i++)
  98. {
  99. Command & cmd = commands[i];
  100. AnxAnimation * anx = cmd.ani->GetAnx();
  101. switch(cmd.id)
  102. {
  103. case cmd_pause:
  104. SetForUpdate(cmd.ani, cmd.intData == 0);
  105. break;
  106. case cmd_start:
  107. anx->Start(cmd.strData);
  108. break;
  109. case cmd_goto:
  110. anx->Goto(cmd.strData, cmd.floatData, (short)cmd.intData);
  111. break;
  112. case cmd_activate_link:
  113. {
  114. bool res = anx->ActivateLink(cmd.strData, cmd.intData != 0, false);
  115. if(!res && service.IsEnableTrace())
  116. {
  117. const char * node = anx->CurrentNode() ? anx->CurrentNode() : "<no node>";
  118. if(!cmd.strData) cmd.strData = "<none>";
  119. api->Error("Animation <%s>: link not been activated!\n Node: %s. Link: %s", cmd.ani->GetName(), node, cmd.strData);
  120. }
  121. }
  122. break;
  123. case cmd_rand_pos:
  124. anx->RandomizePosition();
  125. break;
  126. }
  127. }
  128. commands.Empty();
  129. isUpdateProcess = true;
  130. //Процессируем анимации
  131. for(long i = 0; i < updatingAnimations; i++)
  132. {
  133. updatingAnimations[i]->UpdateAnimation(dltTime);
  134. }
  135. //Процессируем стадии блендинга
  136. for(long i = 0; i < updatingAnimations; i++)
  137. {
  138. updatingAnimations[i]->UpdateStages(dltTime);
  139. }
  140. //Отсылаем сообщения
  141. for(long i = 0; i < updatingAnimations; i++)
  142. {
  143. updatingAnimations[i]->SendEvents();
  144. }
  145. isUpdateProcess = false;
  146. #ifdef DEBUG_THREADS
  147. api->Trace("AnimationScene::UpdateScene -> continue; Scene = %.8x", this);
  148. #endif
  149. }
  150. //Удалить анимацию из списка
  151. void AnimationScene::Delete(Animation * ani)
  152. {
  153. #ifdef DEBUG_THREADS
  154. api->Trace("AnimationScene::Delete(%0.8x); Scene = %.8x", ani, this);
  155. #endif
  156. AssertCoreThread
  157. service.ThreadRemoveAnimationToUpdate(ani);
  158. Assert(isUpdateProcess == 0);
  159. animations.Del(ani);
  160. updatingAnimations.Del(ani);
  161. for(long i = 0; i < commands; i++)
  162. {
  163. Command & cmd = commands[i];
  164. if(cmd.ani == ani)
  165. {
  166. cmd.id = cmd_empty;
  167. cmd.ani = null;
  168. }
  169. }
  170. }
  171. //Удалить процедурную анимацию из списка
  172. void AnimationScene::Delete(AnimationProcedural * ani)
  173. {
  174. AssertCoreThread
  175. Assert(isUpdateProcess == 0);
  176. procedural.Del(ani);
  177. }
  178. //Установить анимацию на обновление
  179. void AnimationScene::SetForUpdate(Animation * ani, bool isUpdate)
  180. {
  181. AssertCoreThread
  182. Assert(isUpdateProcess == 0);
  183. if(isUpdate)
  184. {
  185. for(dword i = 0; i < updatingAnimations.Size(); i++)
  186. {
  187. if(updatingAnimations[i] == ani)
  188. {
  189. return;
  190. }
  191. }
  192. updatingAnimations.Add(ani);
  193. }else{
  194. updatingAnimations.Del(ani);
  195. }
  196. }
  197. void AnimationScene::Command_Start(Animation * ani, const char * nameId)
  198. {
  199. Command & cmd = commands[commands.Add()];
  200. cmd.id = cmd_start;
  201. cmd.strData = nameId;
  202. cmd.ani = ani;
  203. }
  204. void AnimationScene::Command_Goto(Animation * ani, const char * nameId, float blendTime, long clipIndex)
  205. {
  206. Command & cmd = commands[commands.Add()];
  207. cmd.id = cmd_goto;
  208. cmd.intData = (word)clipIndex;
  209. cmd.strData = nameId;
  210. cmd.floatData = blendTime;
  211. cmd.ani = ani;
  212. }
  213. void AnimationScene::Command_ActivateLink(Animation * ani, const char * nameId, bool forceApply)
  214. {
  215. Command & cmd = commands[commands.Add()];
  216. cmd.id = cmd_activate_link;
  217. cmd.strData = nameId;
  218. cmd.intData = forceApply ? 1 : 0;
  219. cmd.ani = ani;
  220. }
  221. void AnimationScene::Command_Pause(Animation * ani, bool isPause)
  222. {
  223. Command & cmd = commands[commands.Add()];
  224. cmd.id = cmd_pause;
  225. cmd.intData = isPause ? 1 : 0;
  226. cmd.ani = ani;
  227. }
  228. void AnimationScene::Command_RandomizePosition(Animation * ani)
  229. {
  230. Command & cmd = commands[commands.Add()];
  231. cmd.id = cmd_rand_pos;
  232. }
  233. void AnimationScene::Command_ClearQueue(const Animation * ani)
  234. {
  235. if(!ani)
  236. {
  237. commands.Empty();
  238. }
  239. for(dword i = 0; i < commands.Size(); )
  240. {
  241. if(commands[i].ani == ani && commands[i].id != cmd_pause)
  242. {
  243. commands.DelIndex(i);
  244. }else{
  245. i++;
  246. }
  247. }
  248. }
  249. #ifndef STOP_DEBUG
  250. //Проверить не отписанный блендер и листенер
  251. __forceinline void AnimationScene::UnregistryCheck(IAniBlendStage * bs, IAnimationListener * lis)
  252. {
  253. for(dword i = 0; i < animations.Size(); i++)
  254. {
  255. animations[i]->UnregistryCheck(bs, lis);
  256. }
  257. }
  258. #endif
  259. #ifndef NO_TOOLS
  260. //Создать анимацию основываясь на данных редактора
  261. Animation * AnimationScene::Editor_Create(const void * data, dword size)
  262. {
  263. AnxData * adata = NEW AnxData();
  264. adata->SetData(data);
  265. adata->SetUserData(-1);
  266. Animation * ani = NEW Animation(*adata, service, *this, "*Editor animation*", _FL_);
  267. animations.Add(ani);
  268. return ani;
  269. }
  270. #endif
  271. //============================================================================================
  272. AnimationService::AnimationService() : scenes(_FL_, 32),
  273. anxData(_FL_, 256),
  274. threadAnimationsQueue(_FL_, 256),
  275. newThreadAnimationsQueue(_FL_, 256)
  276. {
  277. //Создание, удаление сцен и анимаций
  278. firstFreeData = -1;
  279. for(long i = 0; i < ARRSIZE(entryData); i++)
  280. {
  281. entryData[i] = -1;
  282. }
  283. //Управление дополнительным потоком
  284. threadUpdater = null;
  285. eventProcess = null;
  286. eventReady = null;
  287. threadWork = false;
  288. threadPause = false;
  289. threadAnimationIndex = 0;
  290. //Общее
  291. fs = (IFileService *)api->GetService("FileService");
  292. Assert(fs);
  293. IIniFile * pIni = fs->SystemIni();
  294. if(pIni)
  295. {
  296. enableTrace = pIni->GetLong("Animation", "Trace", 0) != 0;
  297. }else{
  298. enableTrace = false;
  299. }
  300. #ifndef STOP_DEBUG
  301. //Оптимизация, отладка
  302. missGetBoneMatricesCounter = 0;
  303. missGetSingleBoneMatrixCounter = 0;
  304. threadUpdateBoneMatricesCounter = 0;
  305. bonesCounter = null;
  306. #endif
  307. debugUsageMemory = 0;
  308. //Если нужно запускаем дополнительный поток
  309. if(api->GetThreadingInfo() != ICore::mt_none)
  310. {
  311. ThreadStart();
  312. }
  313. }
  314. AnimationService::~AnimationService()
  315. {
  316. ThreadStop();
  317. long count = 0;
  318. while(scenes.Size() > 0)
  319. {
  320. count += scenes[0]->ForceRelease();
  321. }
  322. for(long i = 0; i < anxData; i++)
  323. {
  324. AnimationData & d = anxData[i];
  325. if(d.data)
  326. {
  327. delete d.data;
  328. d.data = null;
  329. }
  330. }
  331. if(count)
  332. {
  333. api->Trace("AnimationService: total leaks = %i.", count);
  334. }else{
  335. api->Trace("AnimationService released successfully.");
  336. }
  337. threadUpdater = null;
  338. eventProcess = null;
  339. eventReady = null;
  340. #ifndef STOP_DEBUG
  341. RELEASE(bonesCounter);
  342. #endif
  343. }
  344. bool AnimationService::Init()
  345. {
  346. api->SetEndFrameLevel(this, Core_DefaultExecuteLevel + 0x1);
  347. #ifndef STOP_DEBUG
  348. bonesCounter = api->Storage().GetItemLong("statistics.totalBonesCount", _FL_);
  349. #endif
  350. return true;
  351. }
  352. //Вызываеться перед удалением сервисов
  353. void AnimationService::PreRelease()
  354. {
  355. ThreadStop();
  356. }
  357. //============================================================================================
  358. //Создание, удаление сцен и анимаций
  359. //============================================================================================
  360. //Создать анимацию
  361. AnxData * AnimationService::Create(const char * path)
  362. {
  363. //Корректность имени
  364. if(!path || !path[0]) return null;
  365. //Переводим путь в имя
  366. buffer.Empty();
  367. long lastChar = string::Len(path);
  368. for(long startName = lastChar; startName >= 0; startName--)
  369. {
  370. if(path[startName] == '\\' || path[startName] == '/')
  371. {
  372. break;
  373. }
  374. }
  375. startName++;
  376. for(long endName = lastChar; endName >= 0; endName--)
  377. {
  378. if(path[endName] == '.')
  379. {
  380. break;
  381. }
  382. }
  383. if(endName < 0)
  384. {
  385. endName = lastChar;
  386. }
  387. buffer.Reserve(endName - startName + 1);
  388. for(long i = startName; i < endName; i++)
  389. {
  390. buffer += path[i];
  391. }
  392. buffer.Lower();
  393. //Ищем среди загруженных
  394. dword len = 0;
  395. dword hash = string::Hash(buffer.c_str(), len);
  396. dword index = hash & (ARRSIZE(entryData) - 1);
  397. for(long i = entryData[index]; i >= 0; )
  398. {
  399. AnimationData & d = anxData[i];
  400. if(d.hash == hash)
  401. {
  402. if(d.len == len)
  403. {
  404. if(buffer == d.data->GetName())
  405. {
  406. d.refCounter++;
  407. return d.data;
  408. }
  409. }
  410. }
  411. i = d.next;
  412. }
  413. //Надо загрузить новую анимацию
  414. AnxData * anx = NEW AnxData();
  415. anx->SetName(buffer.c_str());
  416. buffer = "Resource\\Animation\\";
  417. buffer += path;
  418. buffer.CheckPath().Lower().AddExtention(".anx");
  419. IDataFile * df = fs->OpenDataFile(buffer.c_str(), file_open_default, _FL_);
  420. if(!df)
  421. {
  422. if(enableTrace)
  423. {
  424. api->Trace("Animation -> Can't open animation file: %s", buffer.c_str());
  425. }
  426. delete anx;
  427. return null;
  428. }
  429. if(!anx->LoadData(df))
  430. {
  431. df->Release();
  432. if(enableTrace)
  433. {
  434. api->Trace("Animation -> Damaged animation file: %s", buffer.c_str());
  435. }
  436. delete anx;
  437. return null;
  438. }
  439. df->Release();
  440. //Добавляем запись в таблицу
  441. if(firstFreeData >= 0)
  442. {
  443. i = firstFreeData;
  444. firstFreeData = anxData[i].next;
  445. }else{
  446. i = anxData.Add();
  447. }
  448. AnimationData & d = anxData[i];
  449. d.hash = hash;
  450. d.len = len;
  451. d.next = entryData[index];
  452. if(d.next >= 0)
  453. {
  454. anxData[d.next].prev = i;
  455. }
  456. entryData[index] = i;
  457. d.prev = -1;
  458. d.refCounter = 1;
  459. d.data = anx;
  460. anx->SetUserData(i);
  461. if(d.next >= 0)
  462. {
  463. Assert(d.prev != d.next);
  464. }
  465. debugUsageMemory += anx->GetDataSize();
  466. return anx;
  467. }
  468. //Создать пустую анимацию
  469. AnxData * AnimationService::CreateEmpty(const IAnimationScene::Bone * skeleton, dword count)
  470. {
  471. FixMe
  472. return null;
  473. }
  474. //Освободить анимационные данные
  475. void AnimationService::ReleaseData(AnxData * data)
  476. {
  477. //Получаем запись
  478. long i = (long)data->GetUserData();
  479. if(i < 0)
  480. {
  481. //Это анимация редактора
  482. delete data;
  483. return;
  484. }
  485. AnimationData & d = anxData[i];
  486. d.refCounter--;
  487. if(d.refCounter > 0)
  488. {
  489. return;
  490. }
  491. //Удаляем данные
  492. debugUsageMemory -= d.data->GetDataSize();
  493. d.refCounter = 0;
  494. delete d.data;
  495. d.data = null;
  496. //Переносим из именной цепочки в список свободных
  497. if(d.next >= 0)
  498. {
  499. anxData[d.next].prev = d.prev;
  500. }
  501. if(d.prev >= 0)
  502. {
  503. anxData[d.prev].next = d.next;
  504. }else{
  505. Assert(entryData[(d.hash & (ARRSIZE(entryData) - 1))] == i);
  506. entryData[d.hash & (ARRSIZE(entryData) - 1)] = d.next;
  507. }
  508. d.prev = -1;
  509. d.next = firstFreeData;
  510. firstFreeData = i;
  511. }
  512. //Создать сцену с анимациями
  513. IAnimationScene * AnimationService::CreateScene(const char * cppFile, long cppLine)
  514. {
  515. AnimationScene * scene = NEW AnimationScene(*this, cppFile, cppLine);
  516. scenes.Add(scene);
  517. return scene;
  518. }
  519. //Удалить анимационную сцену из списка
  520. void AnimationService::ReleaseScene(AnimationScene * scene)
  521. {
  522. scenes.Del(scene);
  523. }
  524. //============================================================================================
  525. //Управление дополнительным потоком
  526. //============================================================================================
  527. //Добавить анимацию для обсчёта в потоке на следующем кадре
  528. void AnimationService::ThreadAddAnimationToUpdate(Animation * ani)
  529. {
  530. #ifdef DEBUG_THREADS
  531. api->Trace("AnimationService::ThreadAddAnimationToUpdate, ani = %.8x", ani);
  532. #endif
  533. for(long i = 0; i < newThreadAnimationsQueue; i++)
  534. {
  535. if(newThreadAnimationsQueue[i] == ani)
  536. {
  537. return;
  538. }
  539. }
  540. newThreadAnimationsQueue.Add(ani);
  541. }
  542. //Извлечь анимацию из очереди обновления, если невозможно то остановить поток
  543. void AnimationService::ThreadRemoveAnimationToUpdate(Animation * ani)
  544. {
  545. #ifdef DEBUG_PIX_ENABLE
  546. PIXBeginNamedEvent(0, "Ani-remove");
  547. #endif
  548. newThreadAnimationsQueue.Del(ani);
  549. for(long i = 0; i < threadAnimationsQueue; i++)
  550. {
  551. if(threadAnimationsQueue[i] == ani)
  552. {
  553. bool isNeedPause = false;
  554. changeIndex.Enter();
  555. #ifdef DEBUG_THREADS
  556. api->Trace("changeIndex.Enter()");
  557. #endif
  558. if(threadAnimationIndex != i)
  559. {
  560. threadAnimationsQueue[i] = null;
  561. }else{
  562. isNeedPause = true;
  563. }
  564. #ifdef DEBUG_THREADS
  565. api->Trace("changeIndex.Leave()");
  566. #endif
  567. changeIndex.Leave();
  568. if(isNeedPause)
  569. {
  570. #ifdef DEBUG_THREADS
  571. api->Trace("AnimationService::ThreadRemoveAnimationToUpdate; Cant remove ani from queue, pause thread, ani = %.8x", ani);
  572. #endif
  573. ThreadPause();
  574. }else{
  575. #ifdef DEBUG_THREADS
  576. api->Trace("AnimationService::ThreadRemoveAnimationToUpdate; Sucsesful remove ani from queue, ani = %.8x", ani);
  577. #endif
  578. }
  579. #ifdef DEBUG_PIX_ENABLE
  580. PIXEndNamedEvent();
  581. #endif
  582. return;
  583. }
  584. }
  585. #ifdef DEBUG_THREADS
  586. api->Trace("AnimationService::ThreadRemoveAnimationToUpdate; Can't find ani in queue, ani = %.8x", ani);
  587. #endif
  588. #ifdef DEBUG_PIX_ENABLE
  589. PIXEndNamedEvent();
  590. #endif
  591. }
  592. //Запустить поток обсчёта матриц
  593. void AnimationService::ThreadStart()
  594. {
  595. AssertCoreThread
  596. #ifdef DEBUG_THREADS
  597. api->Trace("AnimationService::ThreadStart() -> Start");
  598. #endif
  599. if(threadUpdater)
  600. {
  601. return;
  602. }
  603. threadPause = false;
  604. //Создаём эвенты
  605. eventProcess = ::CreateEvent(null, false, false, null);
  606. if(!eventProcess)
  607. {
  608. return;
  609. }
  610. eventReady = ::CreateEvent(null, true, false, null);
  611. if(!eventReady)
  612. {
  613. ::CloseHandle(eventProcess);
  614. return;
  615. }
  616. //Создаём поток апдейта матриц
  617. threadAnimationIndex = 0;
  618. DWORD dwAnimThreadID = 0;
  619. threadUpdater = ::CreateThread(null, 0, ThreadMatricesUpdater, this, CREATE_SUSPENDED, &dwAnimThreadID);
  620. if(!threadUpdater)
  621. {
  622. ::CloseHandle(eventProcess);
  623. ::CloseHandle(eventReady);
  624. #ifdef DEBUG_THREADS
  625. api->Trace("AnimationService::ThreadStart() -> Error");
  626. #endif
  627. return;
  628. }
  629. #ifdef _XBOX
  630. ::SetThreadPriority(threadUpdater, THREAD_PRIORITY_TIME_CRITICAL);
  631. ::XSetThreadProcessor(threadUpdater, 1);
  632. #endif
  633. XSetThreadName(dwAnimThreadID, "Animation::MatricesUpdater");
  634. ::ResumeThread(threadUpdater);
  635. //Переводим поток в паузу
  636. ThreadPause();
  637. #ifdef DEBUG_THREADS
  638. api->Trace("AnimationService::ThreadStart() -> Ready");
  639. #endif
  640. };
  641. //Завершить поток обсчёта матриц
  642. void AnimationService::ThreadStop()
  643. {
  644. AssertCoreThread
  645. #ifdef DEBUG_THREADS
  646. api->Trace("AnimationService::ThreadStop() -> Start");
  647. #endif
  648. if(!threadUpdater)
  649. {
  650. #ifdef DEBUG_THREADS
  651. api->Trace("AnimationService::ThreadStop() -> Already stoped");
  652. #endif
  653. return;
  654. }
  655. Sleep(1);
  656. //Сообщаем что среду пора остановится
  657. threadWork = false;
  658. threadPause = false;
  659. //Ждём пока поток не закончил работу
  660. do{
  661. ::SetEvent(eventProcess);
  662. }while(::WaitForSingleObject(eventReady, 1) == WAIT_TIMEOUT);
  663. threadUpdater = null;
  664. if(eventProcess)
  665. {
  666. ::CloseHandle(eventProcess);
  667. eventProcess = null;
  668. }
  669. if(eventReady)
  670. {
  671. ::CloseHandle(eventReady);
  672. eventReady = null;
  673. }
  674. #ifdef DEBUG_THREADS
  675. api->Trace("AnimationService::ThreadStop() -> Stop");
  676. #endif
  677. };
  678. //Приостановить цикл обсчёта матриц
  679. void AnimationService::ThreadPause()
  680. {
  681. if(!threadUpdater) return;
  682. AssertCoreThread
  683. if(threadPause)
  684. {
  685. #ifdef DEBUG_THREADS
  686. if(threadUpdater)
  687. {
  688. api->Trace("AnimationService::ThreadPause() -> Already paused");
  689. }else{
  690. api->Trace("AnimationService::ThreadPause() -> Can't pause, thread is stoped");
  691. }
  692. #endif
  693. return;
  694. }
  695. #ifdef DEBUG_PIX_ENABLE
  696. PIXBeginNamedEvent(0, "Ani-pause");
  697. #endif
  698. //Укажем потоку что нужна пауза
  699. threadPause = true;
  700. //Ждём пока поток перейдёт в режим ожидания
  701. while(::WaitForSingleObject(eventReady, 0) == WAIT_TIMEOUT)
  702. {
  703. Sleep(0);
  704. }
  705. threadAnimationsQueue.Empty();
  706. #ifdef DEBUG_THREADS
  707. api->Trace("AnimationService::ThreadPause() -> Pause");
  708. #endif
  709. #ifdef DEBUG_PIX_ENABLE
  710. PIXEndNamedEvent();
  711. #endif
  712. }
  713. //Возобновить цикл обсчёта матриц
  714. void AnimationService::ThreadResume()
  715. {
  716. if(!threadUpdater) return;
  717. AssertCoreThread
  718. //Сначала ставим поток на паузу для достижения точки синхронизации
  719. ThreadPause();
  720. #ifdef DEBUG_PIX_ENABLE
  721. PIXBeginNamedEvent(0, "Ani-resume");
  722. #endif
  723. //Укажем что пауза больше не нужна
  724. threadPause = false;
  725. //Снимаем сигнал паузы
  726. ::ResetEvent(eventReady);
  727. //Запускаем поток
  728. ::SetEvent(eventProcess);
  729. #ifdef DEBUG_THREADS
  730. api->Trace("AnimationService::ThreadResume() -> Resume thread");
  731. #endif
  732. #ifdef DEBUG_PIX_ENABLE
  733. PIXEndNamedEvent();
  734. #endif
  735. }
  736. //Извлечь анимацию из очереди обновления, если невозможно то остановить поток
  737. void AnimationService::ThreadPrepareQueue()
  738. {
  739. ThreadPause();
  740. #ifdef DEBUG_THREADS
  741. api->Trace("AnimationService --============= Prepare thread queue =============--");
  742. #endif
  743. threadAnimationsQueue.Empty();
  744. threadAnimationsQueue.AddElements(newThreadAnimationsQueue.Size());
  745. for(long i = 0; i < newThreadAnimationsQueue; i++)
  746. {
  747. threadAnimationsQueue[i] = newThreadAnimationsQueue[i];
  748. }
  749. newThreadAnimationsQueue.Empty();
  750. threadAnimationIndex = 0;
  751. #ifdef DEBUG_THREADS
  752. api->Trace("AnimationService --============= Second frame =============--");
  753. #endif
  754. ThreadResume();
  755. }
  756. //Поток обновления матриц
  757. DWORD WINAPI AnimationService::ThreadMatricesUpdater(LPVOID lpParameter)
  758. {
  759. AnimationService * service = (AnimationService *)lpParameter;
  760. service->threadWork = true;
  761. while(service->threadWork)
  762. {
  763. //Проходим по всем сценам и по всем анимациям обновляя их
  764. if(!service->threadPause && service->threadAnimationIndex < service->threadAnimationsQueue.Size())
  765. {
  766. Animation * ani = service->threadAnimationsQueue[service->threadAnimationIndex];
  767. if(ani)
  768. {
  769. #ifdef DEBUG_THREADS
  770. api->Trace("Thread update matrices for ani = %.8x", ani);
  771. #endif
  772. ani->ThreadUpdateBones();
  773. }
  774. #ifdef DEBUG_PIX_ENABLE
  775. PIXBeginNamedEvent(0, "Ani-threadAnimationIndex++");
  776. #endif
  777. service->changeIndex.Enter();
  778. #ifdef DEBUG_THREADS
  779. api->Trace("service->changeIndex.Enter()");
  780. #endif
  781. service->threadAnimationIndex++;
  782. #ifdef DEBUG_THREADS
  783. api->Trace("service->changeIndex.Leave()");
  784. #endif
  785. service->changeIndex.Leave();
  786. #ifdef DEBUG_PIX_ENABLE
  787. PIXEndNamedEvent();
  788. #endif
  789. }else{
  790. #ifdef DEBUG_THREADS
  791. api->Trace("AnimationService::ThreadMatricesUpdater() -> Activate pause");
  792. #endif
  793. //Ждём паузу
  794. #ifdef DEBUG_PIX_ENABLE
  795. PIXBeginNamedEvent(0, "Ani-wait new work");
  796. #endif
  797. ::SignalObjectAndWait(service->eventReady, service->eventProcess, INFINITE, false);
  798. #ifdef DEBUG_PIX_ENABLE
  799. PIXEndNamedEvent();
  800. #endif
  801. #ifdef DEBUG_THREADS
  802. api->Trace("AnimationService::ThreadMatricesUpdater() -> Resume from pause, queue size = %u", service->threadAnimationsQueue.Size());
  803. #endif
  804. }
  805. }
  806. //Сообщим что сред более не опасен
  807. ::SetEvent(service->eventReady);
  808. return 0;
  809. }
  810. //============================================================================================
  811. //Общее
  812. //============================================================================================
  813. //Исполнение
  814. void AnimationService::EndFrame(float dltTime)
  815. {
  816. //Прекращаем работу потока, если он досих пор активен
  817. ThreadPause();
  818. //Обновляем очередь исполняемой анимации
  819. #ifndef STOP_PROFILES
  820. //dword queuesize = newThreadAnimationsQueue.Size();
  821. //dword tubmc = threadUpdateBoneMatricesCounter;
  822. //threadUpdateBoneMatricesCounter = 0;
  823. #endif
  824. ThreadPrepareQueue();
  825. #ifndef STOP_PROFILES
  826. //const char * bonesCount = "Bones count";
  827. //api->SetPerformanceCounter(bonesCount, float(manager.bonesCounter));
  828. //bonesCounter->Set(manager.bonesCounter);
  829. //manager.bonesCounter = 0;
  830. // PIXAddNamedCounter(float(queuesize), "Ani - queue");
  831. // PIXAddNamedCounter(float(missGetBoneMatricesCounter), "Ani - all cals in main thread");
  832. // PIXAddNamedCounter(float(missGetSingleBoneMatrixCounter), "Ani - bone cals in main thread");
  833. // PIXAddNamedCounter(float(tubmc), "Ani - all calc in add thread");
  834. //missGetBoneMatricesCounter = 0;
  835. //missGetSingleBoneMatrixCounter = 0;
  836. #endif
  837. }
  838. //Обновить анимационную сцену
  839. void AnimationService::Update(IAnimationScene * scene, float dltTime)
  840. {
  841. if(!scene) return;
  842. ThreadPause();
  843. ((AnimationScene *)scene)->UpdateScene(dltTime);
  844. }
  845. //Получить занимаемую анимацией память
  846. dword AnimationService::GetUsageMemory()
  847. {
  848. return debugUsageMemory;
  849. }
  850. //============================================================================================
  851. //Функции для редактора
  852. //============================================================================================
  853. #ifndef NO_TOOLS
  854. //В редакторе может быть только однопоточный режим
  855. void AnimationService::Editor_NoThread()
  856. {
  857. ThreadStop();
  858. }
  859. /*
  860. Animation * AnimationService::FindAnimation(const char * fileName)
  861. {
  862. Assert(fileName);
  863. for(long i = 0; i < animations; i++)
  864. {
  865. if(animations[i]->deleted) continue;
  866. if(crt_stricmp(animations[i]->GetAnx()->GetName(), fileName) == 0) return (Animation *)animations[i];
  867. }
  868. return null;
  869. }
  870. bool AnimationService::ForceSetAnxFile(AnxFile * forceFile)
  871. {
  872. this->forceFile = forceFile;
  873. bool cr = creationResult;
  874. creationResult = true;
  875. return cr;
  876. }
  877. void AnimationService::DisableCreate(bool isDisable)
  878. {
  879. this->isDisable = isDisable;
  880. }
  881. */
  882. #endif
  883. //============================================================================================
  884. //Оптимизация, отладка
  885. //============================================================================================
  886. #ifndef STOP_DEBUG
  887. //Добавить счётчик промахнувшегося вычисления
  888. void AnimationService::AddMissGetBoneMatrices()
  889. {
  890. missGetBoneMatricesCounter++;
  891. }
  892. //Добавить счётчик промахнувшегося вычисления отдельной кости
  893. void AnimationService::AddMissGetSingleBoneMatrix()
  894. {
  895. missGetSingleBoneMatrixCounter++;
  896. }
  897. //Добавить счётчик вычисления на дополнительном потоке
  898. void AnimationService::AddThreadUpdateBoneMatricesCounter()
  899. {
  900. threadUpdateBoneMatricesCounter++;
  901. }
  902. //Проверить не отписанный блендер и листенер
  903. void AnimationService::UnregistryCheck(IAniBlendStage * bs, IAnimationListener * lis)
  904. {
  905. //Проверяем в сценах
  906. for(dword i = 0; i < scenes.Size(); i++)
  907. {
  908. scenes[i]->UnregistryCheck(bs, lis);
  909. }
  910. }
  911. #endif
  912. #ifndef NO_TOOLS
  913. CREATE_SERVICE(AnxEditorServiceAccess, 1000)
  914. //Запретить потоки
  915. void AnxEditorServiceAccess::DisableThreads()
  916. {
  917. AnimationService * serv = (AnimationService *)api->GetService("AnimationScene");
  918. if(serv)
  919. {
  920. serv->Editor_NoThread();
  921. }
  922. }
  923. //Создать анимацию из памяти
  924. IAnimation * AnxEditorServiceAccess::CreateAnimation(IAnimationScene * scene, const void * data, unsigned long size)
  925. {
  926. return ((AnimationScene *)scene)->Editor_Create(data, size);
  927. }
  928. #endif