mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 19:48:20 +02:00

Throwing error on member references with ".." cascade token outside invocations (ie: "ts..mA = 123") Fixed 'Thread.ModuleTLSIndex' error - which caused us TLS lookup failures in Beef DLLs Fixed some hotswap errors Made BeefPerf shut down properly Fixed an 'int literal' FixIntUnknown issue where rhs was System.Object which caused an illegal boxing Fixed COFF::LocateSymbol issues with Win32 and also with linking to static libraries - showed up with hot-linking in fmod when hot-adding a floating point mod Fixed a couple memory leaks Fixed alignment issue in COFF::ParseCompileUnit
274 lines
5.7 KiB
C++
274 lines
5.7 KiB
C++
#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;
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
/*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++;
|
|
|
|
for (int updateNum = 0; updateNum < updates; updateNum++)
|
|
{
|
|
if (!mRunning)
|
|
break;
|
|
Update(updateNum == 0);
|
|
}
|
|
|
|
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;
|
|
}
|