BFApp.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "BFApp.h"
  2. #include "BFWindow.h"
  3. #include "gfx/RenderDevice.h"
  4. #include "FileStream.h"
  5. #include "util/BSpline.h"
  6. #include "util/PerfTimer.h"
  7. #include "sound/WwiseSound.h"
  8. #include "util/AllocDebug.h"
  9. #pragma warning(disable:4996)
  10. USING_NS_BF;
  11. BFApp* Beefy::gBFApp = NULL;
  12. BFApp::BFApp()
  13. {
  14. mTitle = "Beefy Application";
  15. mRefreshRate = 60;
  16. mLastProcessTick = BFTickCount();
  17. mFrameTimeAcc = 0;
  18. mDrawEnabled = true;
  19. mUpdateFunc = NULL;
  20. mDrawFunc = NULL;
  21. gBFApp = this;
  22. mSysDialogCnt = 0;
  23. mCursor = CURSOR_POINTER;
  24. mInProcess = false;
  25. mUpdateCnt = 0;
  26. mNumPhysUpdates = 0;
  27. mVSynched = true;
  28. mMaxUpdatesPerDraw = 60; // 8?
  29. mUpdateSampleCount = 0;
  30. mUpdateSampleTimes = 0;
  31. if (gPerfManager == NULL)
  32. gPerfManager = new PerfManager();
  33. mRunning = false;
  34. mRenderDevice = NULL;
  35. mVSynched = false;
  36. }
  37. BFApp::~BFApp()
  38. {
  39. gBFApp = NULL;
  40. delete gPerfManager;
  41. for (auto window : mPendingWindowDeleteList)
  42. delete window;
  43. }
  44. void BFApp::Init()
  45. {
  46. }
  47. void BFApp::Run()
  48. {
  49. }
  50. void BFApp::Shutdown()
  51. {
  52. mRunning = false;
  53. }
  54. void BFApp::SetCursor(int cursor)
  55. {
  56. mCursor = cursor;
  57. PhysSetCursor();
  58. }
  59. void BFApp::Update(bool batchStart)
  60. {
  61. //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Update");
  62. #ifdef BF_WWISE_ENABLED
  63. WWiseUpdate();
  64. #endif
  65. mUpdateCnt++;
  66. gPerfManager->NextFrame();
  67. gPerfManager->ZoneStart("BFApp::Update");
  68. mUpdateFunc(batchStart);
  69. gPerfManager->ZoneEnd();
  70. for (auto window : mPendingWindowDeleteList)
  71. delete window;
  72. mPendingWindowDeleteList.clear();
  73. }
  74. void BFApp::Draw()
  75. {
  76. gPerfManager->ZoneStart("BFApp::Draw");
  77. mDrawFunc();
  78. gPerfManager->ZoneEnd();
  79. }
  80. //#define PERIODIC_PERF_TIMING
  81. void BFApp::Process()
  82. {
  83. //Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Process");
  84. if (mInProcess)
  85. return; // No reentry
  86. mInProcess = true;
  87. int updates;
  88. uint32 tickNow = BFTickCount();
  89. const int vSyncTestingPeriod = 250;
  90. if (mRefreshRate != 0)
  91. {
  92. float ticksPerFrame = 1000.0f / mRefreshRate;
  93. int ticksSinceLastProcess = tickNow - mLastProcessTick;
  94. mUpdateSampleCount++;
  95. mUpdateSampleTimes += ticksSinceLastProcess;
  96. //TODO: Turn off mVSynched based on error calculations - (?)
  97. // Two VSync failures in a row means we set mVSyncFailed and permanently disable it
  98. if (mUpdateSampleTimes >= vSyncTestingPeriod)
  99. {
  100. int expectedFrames = (int)(mUpdateSampleTimes / ticksPerFrame);
  101. if (mUpdateSampleCount > expectedFrames * 1.5)
  102. {
  103. if (!mVSynched)
  104. mVSyncFailed = true;
  105. mVSynched = false;
  106. }
  107. else
  108. if (!mVSyncFailed)
  109. mVSynched = true;
  110. mUpdateSampleCount = 0;
  111. mUpdateSampleTimes = 0;
  112. }
  113. mFrameTimeAcc += tickNow - mLastProcessTick;
  114. bool vSynched = mVSynched;
  115. if (vSynched)
  116. {
  117. // For the startup, try not to go hyper during those first samplings
  118. if (mUpdateSampleTimes <= vSyncTestingPeriod)
  119. {
  120. if (ticksSinceLastProcess < ticksPerFrame / 1.5)
  121. vSynched = false;
  122. }
  123. }
  124. if (vSynched)
  125. {
  126. updates = std::max(1, (int)(mFrameTimeAcc / ticksPerFrame + 0.5f));
  127. mFrameTimeAcc = std::max(0.0f, mFrameTimeAcc - ticksPerFrame * updates);
  128. }
  129. else
  130. {
  131. updates = std::max(0, (int)(mFrameTimeAcc / ticksPerFrame));
  132. mFrameTimeAcc = mFrameTimeAcc - ticksPerFrame * updates;
  133. }
  134. if (updates > mRefreshRate)
  135. {
  136. // If more than 1 second of updates is queued, just re-sync
  137. updates = 1;
  138. mFrameTimeAcc = 0;
  139. }
  140. // Compensate for "slow start" by limiting the number of catchup-updates we can do when starting the app
  141. int maxUpdates = BF_MIN(mNumPhysUpdates + 1, mMaxUpdatesPerDraw);
  142. updates = BF_MIN(updates, maxUpdates);
  143. /*if (updates > 2)
  144. OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/
  145. }
  146. else
  147. updates = 1; // RefreshRate of 0 means to update as fast as possible
  148. if (updates == 0)
  149. {
  150. // Yield
  151. BfpThread_Sleep(1);
  152. }
  153. static uint32 lastUpdate = BFTickCount();
  154. #ifdef PERIODIC_PERF_TIMING
  155. bool perfTime = (tickNow - lastUpdate >= 5000) && (updates > 0);
  156. if (perfTime)
  157. {
  158. updates = 1;
  159. lastUpdate = tickNow;
  160. if (perfTime)
  161. gPerfManager->StartRecording();
  162. }
  163. #endif
  164. if (updates > 0)
  165. mNumPhysUpdates++;
  166. for (int updateNum = 0; updateNum < updates; updateNum++)
  167. {
  168. if (!mRunning)
  169. break;
  170. Update(updateNum == 0);
  171. }
  172. if ((mRunning) && (updates > 0))
  173. Draw();
  174. #ifdef PERIODIC_PERF_TIMING
  175. if (perfTime)
  176. {
  177. gPerfManager->StopRecording();
  178. gPerfManager->DbgPrint();
  179. }
  180. #endif
  181. mLastProcessTick = tickNow;
  182. mInProcess = false;
  183. }
  184. void BFApp::RemoveWindow(BFWindow* window)
  185. {
  186. auto itr = std::find(mWindowList.begin(), mWindowList.end(), window);
  187. if (itr == mWindowList.end()) // Allow benign failure (double removal)
  188. return;
  189. mWindowList.erase(itr);
  190. while (window->mChildren.size() > 0)
  191. RemoveWindow(window->mChildren.front());
  192. if (window->mParent != NULL)
  193. {
  194. window->mParent->mChildren.erase(std::find(window->mParent->mChildren.begin(), window->mParent->mChildren.end(), window));
  195. if (window->mFlags & BFWINDOW_MODAL)
  196. {
  197. bool hasModal = false;
  198. for (auto childWindow : window->mParent->mChildren)
  199. {
  200. if (childWindow->mFlags & BFWINDOW_MODAL)
  201. hasModal = true;
  202. }
  203. if (!hasModal)
  204. window->mParent->ModalsRemoved();
  205. }
  206. }
  207. window->mClosedFunc(window);
  208. mRenderDevice->RemoveRenderWindow(window->mRenderWindow);
  209. window->Destroy();
  210. mPendingWindowDeleteList.push_back(window);
  211. }
  212. FileStream* BFApp::OpenBinaryFile(const StringImpl& fileName)
  213. {
  214. FILE* fP = fopen(fileName.c_str(), "rb");
  215. if (fP == NULL)
  216. return NULL;
  217. FileStream* fileStream = new FileStream();
  218. fileStream->mFP = fP;
  219. return fileStream;
  220. }