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

275 lines
5.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();
mFrameTimeAcc = 0;
mDrawEnabled = true;
mUpdateFunc = NULL;
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;
}
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();
}
void BFApp::Draw()
{
gPerfManager->ZoneStart("BFApp::Draw");
mDrawFunc();
gPerfManager->ZoneEnd();
}
//#define PERIODIC_PERF_TIMING
void BFApp::Process()
{
//Beefy::DebugTimeGuard suspendTimeGuard(30, "BFApp::Process");
if (mInProcess)
return; // No reentry
mInProcess = true;
int updates;
uint32 tickNow = BFTickCount();
const int vSyncTestingPeriod = 250;
if (mRefreshRate != 0)
{
float ticksPerFrame = 1000.0f / mRefreshRate;
int ticksSinceLastProcess = tickNow - mLastProcessTick;
mUpdateSampleCount++;
mUpdateSampleTimes += ticksSinceLastProcess;
//TODO: Turn off mVSynched based on error calculations - (?)
// 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)
{
if (!mVSynched)
mVSyncFailed = true;
mVSynched = false;
}
else
if (!mVSyncFailed)
mVSynched = true;
mUpdateSampleCount = 0;
mUpdateSampleTimes = 0;
}
mFrameTimeAcc += tickNow - mLastProcessTick;
bool vSynched = mVSynched;
if (vSynched)
{
// For the startup, try not to go hyper during those first samplings
if (mUpdateSampleTimes <= vSyncTestingPeriod)
{
if (ticksSinceLastProcess < ticksPerFrame / 1.5)
vSynched = false;
}
}
if (vSynched)
{
updates = std::max(1, (int)(mFrameTimeAcc / ticksPerFrame + 0.5f));
mFrameTimeAcc = std::max(0.0f, mFrameTimeAcc - ticksPerFrame * updates);
}
else
{
updates = std::max(0, (int)(mFrameTimeAcc / ticksPerFrame));
mFrameTimeAcc = mFrameTimeAcc - ticksPerFrame * updates;
}
if (updates > mRefreshRate)
{
// If more than 1 second of updates is queued, just re-sync
updates = 1;
mFrameTimeAcc = 0;
}
// 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);
updates = BF_MIN(updates, maxUpdates);
2019-08-23 11:56:54 -07:00
/*if (updates > 2)
OutputDebugStrF("Updates: %d TickDelta: %d\n", updates, tickNow - mLastProcessTick);*/
}
else
updates = 1; // RefreshRate of 0 means to update as fast as possible
if (updates == 0)
{
// Yield
BfpThread_Sleep(1);
}
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
if (updates > 0)
mNumPhysUpdates++;
2019-08-23 11:56:54 -07:00
for (int updateNum = 0; updateNum < updates; updateNum++)
{
if (!mRunning)
break;
2019-08-23 11:56:54 -07:00
Update(updateNum == 0);
}
2019-08-23 11:56:54 -07:00
if ((mRunning) && (updates > 0))
Draw();
#ifdef PERIODIC_PERF_TIMING
if (perfTime)
{
gPerfManager->StopRecording();
gPerfManager->DbgPrint();
}
#endif
mLastProcessTick = tickNow;
mInProcess = false;
}
void BFApp::RemoveWindow(BFWindow* window)
{
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;
}