#include "mainloop.h" #include "iconcomponent.h" #include "modelsplittercomponent.h" #include "motionmodel.h" #include "orthomotionmodel.h" #include "playercomponent.h" #include "roomdestructioncomponent.h" #include "textcomponent.h" #include "viewerinterfaceimpl.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BUILD_WITH_GSTREAMER #include "videocomponent.h" #endif namespace VCtrl { class MyReadFileCallback : public osgDB::Registry::ReadFileCallback { public: virtual osgDB::ReaderWriter::ReadResult readNode(const std::string &fileName, const osgDB::ReaderWriter::Options *options) { osgDB::ReaderWriter::ReadResult res = osgDB::Registry::instance()->readNodeImplementation(fileName, options); if (res.notFound() || res.notHandled() || res.error()) { LOG_DEBUG("DatabasePager could not load file, stopped trying: " << fileName); return osgDB::ReaderWriter::ReadResult(nullptr, osgDB::ReaderWriter::ReadResult::FILE_LOADED); } return res; } }; class MainLoop::Impl { public: osg::ref_ptr mViewer; CtrlImpl *mInterface = nullptr; dtEntityOSG::OSGSystemInterface *mSysIf = nullptr; dtEntityOSG::OSGInputInterface *mInputIf = nullptr; dtEntity::EntityManager *mEntityManager; osg::Timer_t mStartFrameTick = 0; dtEntity::Timer_t mSimulationClockTime = 0; bool mProfilingEnabled = false; Impl() : mEntityManager(new dtEntity::EntityManager) { dtEntity::MessageFunctor f(this, &MainLoop::Impl::onFastForward); mEntityManager->RegisterForMessages(dtEntity::SID("FastForwardMessage"), f); dtEntity::MessageFunctor s(this, &MainLoop::Impl::onEntitySelected); mEntityManager->RegisterForMessages(dtEntity::RequestEntitySelectMessage::TYPE, s); dtEntity::MessageFunctor s2(this, &MainLoop::Impl::onEntityDeselected); mEntityManager->RegisterForMessages(dtEntity::RequestEntityDeselectMessage::TYPE, s2); } ~Impl() { delete mEntityManager; delete mSysIf; delete mInputIf; delete mInterface; } void onFastForward(const dtEntity::Message &msg) { double endtime = msg.GetDouble(dtEntity::SID("EndTime")); while (mInterface->GetSimulationTime() < endtime) { constexpr auto step = 0.5; double t = mInterface->GetSimulationTime() + step; mSimulationClockTime += step / osg::Timer::instance()->getSecondsPerTick(); mInterface->SetSimulationTime(t); mSysIf->SetTimeValues(t, step, step, mSimulationClockTime); mViewer->advance(t); mViewer->eventTraversal(); mSysIf->EmitTickMessagesAndQueuedMessages(); mViewer->updateTraversal(); mSysIf->EmitPostUpdateMessage(); } } void onEntitySelected(const dtEntity::Message &m) { const dtEntity::RequestEntitySelectMessage &msg = static_cast(m); dtEntity::EntitySelectedMessage mo; mo.SetAboutEntityId(msg.GetAboutEntityId()); mEntityManager->EmitMessage(mo); } void onEntityDeselected(const dtEntity::Message &m) { const dtEntity::RequestEntityDeselectMessage &msg = static_cast(m); dtEntity::EntityDeselectedMessage mo; mo.SetAboutEntityId(msg.GetAboutEntityId()); mEntityManager->EmitMessage(mo); } }; MainLoop::MainLoop(int argc, char **argv, QWidget *parentWidget) : mImpl(new Impl) { osgDB::Registry::instance()->setReadFileCallback(new MyReadFileCallback()); assert(!mImpl->mViewer.valid()); { int argc_cpy = argc; std::vector argv_cpy; argv_cpy.reserve(argc); for (int i = 0; i < argc; ++i) argv_cpy.push_back(argv[i]); osg::ArgumentParser args(&argc_cpy, argv_cpy.data()); #ifdef _MSC_VER _putenv_s("OSG_RUN_FRAME_SCHEME", "ON_DEMAND"); #else setenv("OSG_RUN_FRAME_SCHEME", "ON_DEMAND", 1); #endif osg::DisplaySettings::instance()->setNumMultiSamples(4); osg::DisplaySettings::instance()->setDepthBuffer(true); mImpl->mViewer = new osgViewer::CompositeViewer(args); mImpl->mViewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded); mImpl->mViewer->setKeyEventSetsDone(0); #ifdef LTS_DEBUG dtEntity::LogManager::GetInstance().AddListener(new dtEntity::ConsoleLogHandler()); #endif } { mImpl->mSysIf = new dtEntityOSG::OSGSystemInterface(mImpl->mEntityManager->GetMessagePump(), argc, (const char **)argv); mImpl->mInputIf = new dtEntityOSG::OSGInputInterface(mImpl->mEntityManager->GetMessagePump()); mImpl->mSysIf->SetViewer(mImpl->mViewer); dtEntity::SetSystemInterface(mImpl->mSysIf); dtEntity::SetInputInterface(mImpl->mInputIf); dtEntity::SetWindowInterface(new dtEntityOSG::OSGWindowInterface(*mImpl->mEntityManager)); dtEntity::SetupDataPaths(argc, argv, false); } dtEntity::EntityManager &em = *mImpl->mEntityManager; { em.AddEntitySystem(*new dtEntity::MapSystem(em)); em.AddEntitySystem(*new dtEntityOSG::LayerSystem(em)); em.AddEntitySystem(*new dtEntityOSG::CameraSystem(em)); em.AddEntitySystem(*new dtEntityOSG::PositionAttitudeTransformSystem(em)); em.AddEntitySystem(*new dtEntityOSG::StaticMeshSystem(em)); em.AddEntitySystem(*new RoomDestructionSystem(em)); em.AddEntitySystem(*new MotionModelSystem(em)); em.AddEntitySystem(*new ModelSplitterSystem(em)); em.AddEntitySystem(*new OrthoMotionModelSystem(em)); em.AddEntitySystem(*new dtEntityOSG::LightSystem(em)); em.AddEntitySystem(*new PlayerSystem(em)); em.AddEntitySystem(*new IconSystem(em)); em.AddEntitySystem(*new TextSystem(em)); #ifdef BUILD_WITH_GSTREAMER em.AddEntitySystem(*new VideoSystem(em)); #endif dtEntityOSG::LayerAttachPointSystem *layerattach = new dtEntityOSG::LayerAttachPointSystem(em); em.AddEntitySystem(*layerattach); layerattach->CreateSceneGraphRootEntity(new osg::Group()); mImpl->mInterface = new CtrlImpl(em, parentWidget); dtEntity::SetDebugDrawInterface(new dtEntityOSG::OSGDebugDrawInterface(em)); } { mImpl->mStartFrameTick = osg::Timer::instance()->tick(); mImpl->mInterface->SetSimulationTime(0); time_t t; time(&t); mImpl->mSimulationClockTime = t / osg::Timer::instance()->getSecondsPerTick(); } for (int i = 1; i < argc; ++i) { std::string curArgv = argv[i]; if (!curArgv.empty() && curArgv == "--openOverview") mImpl->mInterface->OpenOverview(); } { dtEntity::StartSystemMessage msg; em.EnqueueMessage(msg); } } MainLoop::~MainLoop() { delete mImpl; } dtEntity::EntityManager *MainLoop::getEntityManager() const { return mImpl->mEntityManager; } ViewerInterface *MainLoop::getViewerInterface() const { return mImpl->mInterface; } bool MainLoop::getProfilingEnabled() const { return mImpl->mProfilingEnabled; } void MainLoop::setProfilingEnabled(bool v) { mImpl->mProfilingEnabled = v; } void MainLoop::tick() { dtEntityOSG::OSGSystemInterface *iface = dtEntityOSG::GetOSGSystemInterface(); if (!mImpl->mInterface->allViewWindowsExposed()) return; if (getViewerInterface()->GetNonRealtimeMode()) { float deltaTime = 1.0f / mImpl->mInterface->GetFrameRate(); float deltaSimTime = deltaTime; mImpl->mSimulationClockTime += deltaSimTime / osg::Timer::instance()->getSecondsPerTick(); mImpl->mInterface->SetSimulationTime(mImpl->mInterface->GetSimulationTime() + deltaSimTime); iface->SetTimeValues(mImpl->mInterface->GetSimulationTime(), deltaSimTime, deltaTime, mImpl->mSimulationClockTime); } else { float deltaTime = 0; float deltaSimTime = 0; dtEntity::Timer_t tick = osg::Timer::instance()->tick(); deltaTime = static_cast(osg::Timer::instance()->delta_s(mImpl->mStartFrameTick, tick)); deltaSimTime = deltaTime * mImpl->mInterface->GetTimeScale(); mImpl->mStartFrameTick = tick; mImpl->mSimulationClockTime += deltaSimTime / osg::Timer::instance()->getSecondsPerTick(); mImpl->mInterface->SetSimulationTime(mImpl->mInterface->GetSimulationTime() + deltaSimTime); iface->SetTimeValues(mImpl->mInterface->GetSimulationTime(), deltaSimTime, deltaTime, mImpl->mSimulationClockTime); } if (mImpl->mProfilingEnabled) { static dtEntity::StringId frameId = dtEntity::SID("Frame"); static dtEntity::StringId frameAdvanceId = dtEntity::SID("Frame_Advance"); static dtEntity::StringId frameEvTrId = dtEntity::SID("Frame_EventTraversal"); static dtEntity::StringId frameUpTrId = dtEntity::SID("Frame_UpdateTraversal"); static dtEntity::StringId frameRenderTrId = dtEntity::SID("Frame_RenderingTraversals"); static unsigned int framecount = 0; CProfileManager::Increment_Frame_Counter(); CProfileManager::Start_Profile(frameId); CProfileManager::Start_Profile(frameAdvanceId); mImpl->mViewer->advance(); CProfileManager::Stop_Profile(); CProfileManager::Start_Profile(frameEvTrId); mImpl->mViewer->eventTraversal(); iface->EmitTickMessagesAndQueuedMessages(); CProfileManager::Stop_Profile(); if (mImpl->mViewer->getNumViews() > 0 && mImpl->mViewer->checkNeedToDoFrame()) { CProfileManager::Start_Profile(frameUpTrId); mImpl->mViewer->updateTraversal(); iface->EmitPostUpdateMessage(); CProfileManager::Stop_Profile(); CProfileManager::Start_Profile(frameRenderTrId); mImpl->mViewer->renderingTraversals(); CProfileManager::Stop_Profile(); } else iface->EmitPostUpdateMessage(); CProfileManager::Stop_Profile(); if (++framecount > 99) { CProfileManager::dumpAll(); fflush(stdout); framecount = 0; CProfileManager::Reset(); } } else { static int renderagaincnt = 0; mImpl->mViewer->advance(DBL_MAX); mImpl->mViewer->eventTraversal(); iface->EmitTickMessagesAndQueuedMessages(); bool needFrame = mImpl->mViewer->checkNeedToDoFrame(); if (mImpl->mViewer->getNumViews() > 0 && (renderagaincnt != 0 || needFrame)) { if (mImpl->mViewer->getNumViews() == 1) renderagaincnt = 0; else if (needFrame) renderagaincnt = 2; else --renderagaincnt; mImpl->mViewer->updateTraversal(); iface->EmitPostUpdateMessage(); mImpl->mViewer->renderingTraversals(); } else iface->EmitPostUpdateMessage(); } if (!getViewerInterface()->GetNonRealtimeMode() && mImpl->mViewer->getRunMaxFrameRate() > 0.0) { if (mImpl->mProfilingEnabled) { static dtEntity::StringId sleepId = dtEntity::SID("Frame_Sleep"); CProfileManager::Start_Profile(sleepId); } osg::Timer_t endFrameTick = osg::Timer::instance()->tick(); double frameTime = osg::Timer::instance()->delta_s(mImpl->mStartFrameTick, endFrameTick); double minFrameTime = 1.0 / mImpl->mViewer->getRunMaxFrameRate(); if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(1000000.0 * (minFrameTime - frameTime)); if (mImpl->mProfilingEnabled) CProfileManager::Stop_Profile(); } } void MainLoop::GetCurrentPosition(Vec3d &position, Vec3d &lookAt) { position = Vec3d(); lookAt = Vec3d(); dtEntity::MapSystem *ms; mImpl->mEntityManager->GetES(ms); if (!ms) return; dtEntity::EntityId eid = ms->GetEntityIdByUniqueId("cam_overview"); dtEntityOSG::CameraComponent *camcomp; if (!mImpl->mEntityManager->GetComponent(eid, camcomp)) { LOG_ERROR("GetCurrentPosition: Error accessing camera"); return; } osg::Vec3d p = camcomp->GetPosition(); osg::Vec3d la = camcomp->GetEyeDirection() + camcomp->GetPosition(); position.x = p[0]; position.y = p[1]; position.z = p[2]; lookAt.x = la[0]; lookAt.y = la[1]; lookAt.z = la[2]; } }