1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 13:19:56 +00:00
openmw-tes3mp/components/misc/callbackmanager.cpp
2021-03-03 13:46:08 +01:00

122 lines
3.9 KiB
C++

#include "callbackmanager.hpp"
namespace Misc
{
static CallbackManager* sInstance = nullptr;
CallbackManager& CallbackManager::instance()
{
return *sInstance;
}
struct InternalDrawCallback : public osg::Camera::DrawCallback
{
public:
InternalDrawCallback(CallbackManager* manager, CallbackManager::DrawStage stage)
: mManager(manager)
, mStage(stage)
{}
void operator()(osg::RenderInfo& info) const override { mManager->callback(mStage, info); };
private:
CallbackManager* mManager;
CallbackManager::DrawStage mStage;
};
CallbackManager::CallbackManager(osg::ref_ptr<osgViewer::Viewer> viewer)
: mInternalCallbacks{ }
, mUserCallbacks{ }
, mViewer{ viewer }
{
if (sInstance)
throw std::logic_error("Double instance og StereoView");
sInstance = this;
mInternalCallbacks[DrawStage::Initial] = new InternalDrawCallback(this, DrawStage::Initial);
mInternalCallbacks[DrawStage::PreDraw] = new InternalDrawCallback(this, DrawStage::PreDraw);
mInternalCallbacks[DrawStage::PostDraw] = new InternalDrawCallback(this, DrawStage::PostDraw);
mInternalCallbacks[DrawStage::Final] = new InternalDrawCallback(this, DrawStage::Final);
auto* camera = mViewer->getCamera();
camera->setInitialDrawCallback(mInternalCallbacks[DrawStage::Initial]);
camera->setPreDrawCallback(mInternalCallbacks[DrawStage::PreDraw]);
camera->setPostDrawCallback(mInternalCallbacks[DrawStage::PostDraw]);
camera->setFinalDrawCallback(mInternalCallbacks[DrawStage::Final]);
}
void CallbackManager::callback(DrawStage stage, osg::RenderInfo& info)
{
std::unique_lock<std::mutex> lock(mMutex);
auto frameNo = info.getState()->getFrameStamp()->getFrameNumber();
auto& callbacks = mUserCallbacks[stage];
for (int i = 0; static_cast<unsigned int>(i) < callbacks.size(); i++)
{
auto& callbackInfo = callbacks[i];
if (frameNo >= callbackInfo.frame)
{
callbackInfo.callback->run(info);
if (callbackInfo.oneshot)
{
callbacks.erase(callbacks.begin() + 1);
i--;
}
}
}
mCondition.notify_all();
}
void CallbackManager::addCallback(DrawStage stage, DrawCallback* cb)
{
std::unique_lock<std::mutex> lock(mMutex);
CallbackInfo callbackInfo;
callbackInfo.callback = cb;
callbackInfo.frame = mViewer->getFrameStamp()->getFrameNumber();
callbackInfo.oneshot = false;
mUserCallbacks[stage].push_back(callbackInfo);
}
void CallbackManager::removeCallback(DrawStage stage, DrawCallback* cb)
{
std::unique_lock<std::mutex> lock(mMutex);
auto& cbs = mUserCallbacks[stage];
for (uint32_t i = 0; i < cbs.size(); i++)
if (cbs[i].callback == cb)
cbs.erase(cbs.begin() + i);
}
void CallbackManager::addCallbackOneshot(DrawStage stage, DrawCallback* cb)
{
std::unique_lock<std::mutex> lock(mMutex);
CallbackInfo callbackInfo;
callbackInfo.callback = cb;
callbackInfo.frame = mViewer->getFrameStamp()->getFrameNumber();
callbackInfo.oneshot = true;
mUserCallbacks[stage].push_back(callbackInfo);
}
void CallbackManager::waitCallbackOneshot(DrawStage stage, DrawCallback* cb)
{
std::unique_lock<std::mutex> lock(mMutex);
while (hasOneshot(stage, cb))
mCondition.wait(lock);
}
void CallbackManager::beginFrame()
{
}
bool CallbackManager::hasOneshot(DrawStage stage, DrawCallback* cb)
{
for (auto& callbackInfo : mUserCallbacks[stage])
if (callbackInfo.callback == cb)
return true;
return false;
}
}