1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00
Beef/BeefySysLib/BFApp.cpp

317 lines
6.7 KiB
C++
Raw Normal View History

2019-08-23 11:56:54 -07:00
#include "BFApp.h"
#include "BFWindow.h"
#include "gfx/RenderDevice.h"
#include "FileStream.h"
#include "util/BSpline.h"
#include "util/PerfTimer.h"
#include "sound/WwiseSound.h"
#include "util/AllocDebug.h"
#pragma warning(disable:4996)
USING_NS_BF;
BFApp* Beefy::gBFApp = NULL;
BFApp::BFApp()
{
mTitle = "Beefy Application";
mRefreshRate = 60;
mLastProcessTick = BFTickCount();
2022-05-15 08:00:55 -07:00
mPhysFrameTimeAcc = 0;
2019-08-23 11:56:54 -07:00
mDrawEnabled = true;
mUpdateFunc = NULL;
2022-05-15 08:00:55 -07:00
mUpdateFFunc = NULL;
2019-08-23 11:56:54 -07:00
mDrawFunc = NULL;
gBFApp = this;
mSysDialogCnt = 0;
mCursor = CURSOR_POINTER;
mInProcess = false;
mUpdateCnt = 0;
mNumPhysUpdates = 0;
2019-08-23 11:56:54 -07:00
mVSynched = true;
mMaxUpdatesPerDraw = 60; // 8?
mUpdateSampleCount = 0;
mUpdateSampleTimes = 0;
if (gPerfManager == NULL)
gPerfManager = new PerfManager();
mRunning = false;
mRenderDevice = NULL;
mVSynched = false;
2022-05-15 08:00:55 -07:00
mVSyncActive = false;
mForceNextDraw = false;
mUpdateCnt = 0;
mUpdateCntF = 0;
mClientUpdateCntF = 0;
2019-08-23 11:56:54 -07:00
}
BFApp::~BFApp()
{
gBFApp = NULL;
delete gPerfManager;
for (auto window : mPendingWindowDeleteList)
delete window;
2019-08-23 11:56:54 -07:00
}
void BFApp::Init()
{
}
void BFApp::Run()
{
}
void BFApp::Shutdown()
{
mRunning = false;
}
void BFApp::SetCursor(int cursor)
{
mCursor = cursor;
PhysSetCursor();
}
void BFApp::Update(bool batchStart)
{
//Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Update");
#ifdef BF_WWISE_ENABLED
WWiseUpdate();
#endif
mUpdateCnt++;
gPerfManager->NextFrame();
gPerfManager->ZoneStart("BFApp::Update");
mUpdateFunc(batchStart);
gPerfManager->ZoneEnd();
for (auto window : mPendingWindowDeleteList)
delete window;
mPendingWindowDeleteList.clear();
}
2022-05-15 08:00:55 -07:00
void BFApp::UpdateF(float updatePct)
{
mUpdateFFunc(updatePct);
}
2019-08-23 11:56:54 -07:00
void BFApp::Draw()
{
gPerfManager->ZoneStart("BFApp::Draw");
2022-05-15 08:00:55 -07:00
mDrawFunc(mForceNextDraw);
mForceNextDraw = false;
2019-08-23 11:56:54 -07:00
gPerfManager->ZoneEnd();
}
//#define PERIODIC_PERF_TIMING
void BFApp::Process()
{
//Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Process");
2022-05-15 08:00:55 -07:00
RenderWindow* headRenderWindow = NULL;
float physRefreshRate = 0;
2022-05-16 10:34:42 -07:00
if ((mRenderDevice != NULL) && (!mRenderDevice->mRenderWindowList.IsEmpty()))
2022-05-15 08:00:55 -07:00
{
headRenderWindow = mRenderDevice->mRenderWindowList[0];
physRefreshRate = headRenderWindow->GetRefreshRate();
}
if (physRefreshRate <= 0)
physRefreshRate = 60.0f;
float ticksPerFrame = 1;
float physTicksPerFrame = 1000.0f / physRefreshRate;
2019-08-23 11:56:54 -07:00
if (mInProcess)
return; // No reentry
mInProcess = true;
uint32 tickNow = BFTickCount();
const int vSyncTestingPeriod = 250;
2022-05-15 08:00:55 -07:00
bool didVBlankWait = false;
if (mVSyncActive)
{
// Have a time limit in the cases we miss the vblank
if (mVSyncEvent.WaitFor((int)(physTicksPerFrame + 1)))
didVBlankWait = true;
}
2019-08-23 11:56:54 -07:00
2022-05-15 08:00:55 -07:00
if (mRefreshRate > 0)
ticksPerFrame = 1000.0f / mRefreshRate;
int ticksSinceLastProcess = tickNow - mLastProcessTick;
2019-08-23 11:56:54 -07:00
2022-05-15 08:00:55 -07:00
mUpdateSampleCount++;
mUpdateSampleTimes += ticksSinceLastProcess;
//TODO: Turn off mVSynched based on error calculations - (?)
2019-08-23 11:56:54 -07:00
2022-05-15 08:00:55 -07:00
// Two VSync failures in a row means we set mVSyncFailed and permanently disable it
if (mUpdateSampleTimes >= vSyncTestingPeriod)
{
int expectedFrames = (int)(mUpdateSampleTimes / ticksPerFrame);
if (mUpdateSampleCount > expectedFrames * 1.5)
2019-08-23 11:56:54 -07:00
{
2022-05-15 08:00:55 -07:00
if (!mVSynched)
mVSyncFailed = true;
mVSynched = false;
2019-08-23 11:56:54 -07:00
}
2022-05-15 08:00:55 -07:00
else
2019-08-23 11:56:54 -07:00
{
2022-05-15 08:00:55 -07:00
if (!mVSyncFailed)
mVSynched = true;
2019-08-23 11:56:54 -07:00
}
2022-05-15 08:00:55 -07:00
mUpdateSampleCount = 0;
mUpdateSampleTimes = 0;
}
mPhysFrameTimeAcc += tickNow - mLastProcessTick;
if (didVBlankWait)
{
// Try to keep time synced with vblank
if (mPhysFrameTimeAcc < physTicksPerFrame * 2)
2019-08-23 11:56:54 -07:00
{
2022-05-15 08:00:55 -07:00
float timeAdjust = physTicksPerFrame - mPhysFrameTimeAcc + 0.001f;
mPhysFrameTimeAcc += timeAdjust;
2019-08-23 11:56:54 -07:00
}
2022-05-15 08:00:55 -07:00
}
2019-08-23 11:56:54 -07:00
2022-05-15 08:00:55 -07:00
/*if (updates > 2)
OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/
// Compensate for "slow start" by limiting the number of catchup-updates we can do when starting the app
int maxUpdates = BF_MIN(mNumPhysUpdates + 1, mMaxUpdatesPerDraw);
2022-05-15 08:00:55 -07:00
while (mPhysFrameTimeAcc >= physTicksPerFrame)
{
mPhysFrameTimeAcc -= physTicksPerFrame;
mUpdateCntF += physTicksPerFrame / ticksPerFrame;
2019-08-23 11:56:54 -07:00
}
static uint32 lastUpdate = BFTickCount();
#ifdef PERIODIC_PERF_TIMING
bool perfTime = (tickNow - lastUpdate >= 5000) && (updates > 0);
if (perfTime)
{
updates = 1;
lastUpdate = tickNow;
if (perfTime)
gPerfManager->StartRecording();
}
#endif
2022-05-15 08:00:55 -07:00
int didUpdateCnt = 0;
2022-05-30 18:07:29 -07:00
if (mUpdateCntF - mClientUpdateCntF > physRefreshRate / 2)
2022-05-15 08:00:55 -07:00
{
// Too large of a difference, just sync
mClientUpdateCntF = mUpdateCntF - 1;
}
2022-06-21 11:31:51 -07:00
while ((mRunning) && ((int)mClientUpdateCntF < (int)mUpdateCntF))
{
2022-05-15 08:00:55 -07:00
Update(didUpdateCnt == 0);
didUpdateCnt++;
mClientUpdateCntF = (int)mClientUpdateCntF + 1.000001;
if (didUpdateCnt >= maxUpdates)
break;
2022-05-15 08:00:55 -07:00
}
2022-05-30 18:07:29 -07:00
// Only attempt UpdateF updates if our rates aren't nearly the same
2022-06-21 11:31:51 -07:00
if ((mRunning) && (mRefreshRate != 0) && (fabs(physRefreshRate - mRefreshRate) / (float)mRefreshRate > 0.1f))
2022-05-15 08:00:55 -07:00
{
float updateFAmt = (float)(mUpdateCntF - mClientUpdateCntF);
if ((updateFAmt > 0.05f) && (updateFAmt < 1.0f) && (didUpdateCnt < maxUpdates))
{
UpdateF(updateFAmt);
didUpdateCnt++;
mClientUpdateCntF = mUpdateCntF;
}
}
if (didUpdateCnt > 0)
mNumPhysUpdates++;
if ((mRunning) && (didUpdateCnt == 0))
{
BfpThread_Sleep(1);
}
2019-08-23 11:56:54 -07:00
2022-05-15 08:00:55 -07:00
if ((mRunning) &&
((didUpdateCnt != 0) || (mForceNextDraw)))
2019-08-23 11:56:54 -07:00
Draw();
#ifdef PERIODIC_PERF_TIMING
if (perfTime)
{
gPerfManager->StopRecording();
gPerfManager->DbgPrint();
}
#endif
mLastProcessTick = tickNow;
mInProcess = false;
}
void BFApp::RemoveWindow(BFWindow* window)
{
2022-05-15 08:00:55 -07:00
AutoCrit autoCrit(mCritSect);
2019-08-23 11:56:54 -07:00
auto itr = std::find(mWindowList.begin(), mWindowList.end(), window);
if (itr == mWindowList.end()) // Allow benign failure (double removal)
return;
mWindowList.erase(itr);
while (window->mChildren.size() > 0)
RemoveWindow(window->mChildren.front());
if (window->mParent != NULL)
{
window->mParent->mChildren.erase(std::find(window->mParent->mChildren.begin(), window->mParent->mChildren.end(), window));
if (window->mFlags & BFWINDOW_MODAL)
{
bool hasModal = false;
for (auto childWindow : window->mParent->mChildren)
{
if (childWindow->mFlags & BFWINDOW_MODAL)
hasModal = true;
}
if (!hasModal)
window->mParent->ModalsRemoved();
}
}
window->mClosedFunc(window);
mRenderDevice->RemoveRenderWindow(window->mRenderWindow);
window->Destroy();
mPendingWindowDeleteList.push_back(window);
}
FileStream* BFApp::OpenBinaryFile(const StringImpl& fileName)
{
FILE* fP = fopen(fileName.c_str(), "rb");
if (fP == NULL)
return NULL;
FileStream* fileStream = new FileStream();
fileStream->mFP = fP;
return fileStream;
}