#include "viewerinterfaceimpl.h" #include "viewermainwindow.h" #include "buildingmanager.h" #include "iconcomponent.h" #include "messages.h" #include "modelsplittercomponent.h" #include "playercomponent.h" #include "roomdestructioncomponent.h" #include "textcomponent.h" #include "viewwidget.h" #include "orthomotionmodel.h" #include "visitors.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "buildingmanager.h" #include "viewwidget.h" #include #include #include #include #ifdef BUILD_WITH_GSTREAMER #include "videocomponent.h" #endif #include #include #include #include namespace VCtrl { class LogHandler final : public dtEntity::LogListener { public: explicit LogHandler(ViewerCallback *cb) : mCallback(cb) {} void LogMessage(dtEntity::LogLevel::e level, const std::string &filename, const std::string &methodname, int linenumber, const std::string &msg) override { ViewerCallback::Severity severity = ViewerCallback::Severity::Fatal; switch (level) { case dtEntity::LogLevel::e::LVL_ALWAYS: severity = ViewerCallback::Severity::Always; break; case dtEntity::LogLevel::e::LVL_DEBUG: severity = ViewerCallback::Severity::Debug; break; case dtEntity::LogLevel::e::LVL_INFO: severity = ViewerCallback::Severity::Info; break; case dtEntity::LogLevel::e::LVL_WARNING: severity = ViewerCallback::Severity::Warning; break; case dtEntity::LogLevel::e::LVL_ERROR: severity = ViewerCallback::Severity::Error; break; } mCallback->LogMessage(severity, filename, methodname, linenumber, msg); } private: ViewerCallback *mCallback; }; ViewWidget *addViewWidget(osg::Camera *camera, unsigned int &contextid, dtEntity::EntityId bid = 0, const std::string &strFeatureID = std::string(), bool exactPos = false) { osgViewer::CompositeViewer *cv = static_cast(dtEntityOSG::GetOSGSystemInterface()->GetViewer()); cv->stopThreading(); cv->setDone(false); osgViewer::View *view = new osgViewer::View; view->setCamera(camera); cv->addView(view); view->requestContinuousUpdate(false); osgQt::GraphicsWindowQt *gw = dynamic_cast(camera->getGraphicsContext()); contextid = gw->getState()->getContextID(); if (!gw->isRealized()) gw->realize(); ViewWidget *wv = new ViewWidget(contextid, bid, strFeatureID, exactPos); wv->setView(gw->getGLWidget()); cv->startThreading(); return wv; } osg::Camera *createCamera(int screennum, bool fullscreen, int x, int y, int w, int h, const std::string &name, bool windowDecoration) { const auto screens = QGuiApplication::screens(); const QRect rect = screens.size() > screennum ? screens.at(screennum)->geometry() : QRect(); if (fullscreen) { x = rect.x(); y = rect.y(); w = rect.width(); h = rect.height(); } else { x += rect.x(); y += rect.y(); } osg::DisplaySettings *ds = osg::DisplaySettings::instance().get(); osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->windowName = name; traits->windowDecoration = windowDecoration; traits->x = x; traits->y = y; traits->width = w; traits->height = h; traits->doubleBuffer = true; traits->alpha = ds->getMinimumNumAlphaBits(); traits->stencil = ds->getMinimumNumStencilBits(); traits->sampleBuffers = ds->getMultiSamples(); traits->samples = ds->getNumMultiSamples(); traits->screenNum = screennum; traits->vsync = false; osg::ref_ptr camera = new osg::Camera; camera->setGraphicsContext(new osgQt::GraphicsWindowQt(traits.get())); camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); camera->setProjectionMatrixAsPerspective( 30.0f, static_cast(traits->width) / static_cast(traits->height), 1.0f, 10000.0f); return camera.release(); } osg::Camera *createCamera(const std::string &name) { return createCamera(0, false, 0, 0, 10, 10, name, false); } CtrlImpl::CtrlImpl(dtEntity::EntityManager &em, QWidget *parentWidget) : mEntityManager(&em) , mViewerCallback(nullptr) , mMapSystem(nullptr) , mPlayerSystem(nullptr) , mBuildingManager(new BuildingManager(em)) , mTimeScale(1) , mSimTime(0) , mPaused(false) , mNonRealtimeMode(false) , mFrameRate(30) { if (!mEntityManager->GetES(mMapSystem) || !mEntityManager->GetES(mPlayerSystem)) { assert(false); } dtEntity::MessageFunctor f1(this, &CtrlImpl::OnTransformSend); em.RegisterForMessages(TransformSendMessage::TYPE, f1); dtEntity::MessageFunctor f2(this, &CtrlImpl::OnNavMeshGroupChanged); em.RegisterForMessages(NavMeshGroupChangedMessage::TYPE, f2); dtEntity::MessageFunctor f3(this, &CtrlImpl::OnPlayerPicked); em.RegisterForMessages(PlayerPickedMessage::TYPE, f3); dtEntity::MessageFunctor f4(this, &CtrlImpl::OnHideSelection); em.RegisterForMessages(HideSelectionMessage::TYPE, f4); dtEntity::MessageFunctor f5(this, &CtrlImpl::OnShoot); em.RegisterForMessages(ShootMessage::TYPE, f5); dtEntity::MessageFunctor f6(this, &CtrlImpl::OnShowHidePlayer); em.RegisterForMessages(ShowHidePlayerMessage::TYPE, f6); dtEntity::MessageFunctor f7(this, &CtrlImpl::OnDisplayNameClicked); em.RegisterForMessages(DisplayNameClickedMessage::TYPE, f7); m_pMainWindow = new CtrlMainWindow(parentWidget); mBuildingManager->setCallbackCamPosChanged( [this](unsigned int contextId, const BuildingViewer::CameraViewPosition &viewPos) { if (mViewerCallback) { auto vw = m_openedViewWidgets.getViewWidget(contextId); if (vw) mViewerCallback->ViewZoomChanged(vw->featureID(), viewPos.m_top, viewPos.m_left, viewPos.m_bottom, viewPos.m_right); } }); } CtrlImpl::~CtrlImpl() { RemoveViewerCallback(); delete m_pMainWindow; } QWidget* CtrlImpl::getMainWindow() { return m_pMainWindow; } void CtrlImpl::openViews(const std::vector &bldIds, bool exactPos) { if (bldIds.size() == 1 && bldIds.front() == "all") { openAll(exactPos); return; } if (bldIds.size()) open(bldIds, exactPos); } bool CtrlImpl::isViewOpen(const std::string &strBldId) const { return m_openedViewWidgets.exist(strBldId); } void CtrlImpl::closeViews(const std::vector &vecFeatureIDs) { if (vecFeatureIDs.size() == 1 && vecFeatureIDs.front() == "all") { closeAllViews(); return; } m_pMainWindow->clearGridLayout(); for (const auto &strFeatureID : vecFeatureIDs) { ViewWidget *pWidget = m_openedViewWidgets.getViewWidget(strFeatureID); if (pWidget) { if (pWidget->isMaximized()) m_isInFullscreenMode = false; CloseView(pWidget); m_openedViewWidgets.remove(pWidget->featureID()); } } if (m_isInFullscreenMode) { for (const auto &pWidget : m_openedViewWidgets.getViewWidgets()) { if (pWidget->isMaximized()) { m_pMainWindow->openView(pWidget); break; } } } else m_pMainWindow->openViews(m_openedViewWidgets.getViewWidgets()); } void CtrlImpl::closeAllViews() { if(!m_openedViewWidgets.size() || !m_pMainWindow) return; m_pMainWindow->clearGridLayout(); const auto viewWidgets = m_openedViewWidgets.getViewWidgets(); for (auto pWidget : viewWidgets) CloseView(pWidget); m_openedViewWidgets.clear(); } void CtrlImpl::setTransparency(double percent) { m_desiredTransparencyValue = percent; std::vector m_vecShownViews = m_openedViewWidgets.getViewWidgets(); for (const auto &e : m_vecShownViews) SetWallTransparency(e->contextID(), m_desiredTransparencyValue); } void CtrlImpl::setViewMode(ViewMode m) { m_desiredViewMode = m; std::vector m_vecShownViews = m_openedViewWidgets.getViewWidgets(); for (const auto &e : m_vecShownViews) ChangeViewMode(e->contextID(), m_desiredViewMode); } void CtrlImpl::setDisplayMode(PlayerDisplayMode m) { m_desiredPlayerDisplayMode = m; std::vector m_vecShownViews = m_openedViewWidgets.getViewWidgets(); for (const auto &e : m_vecShownViews) SetPlayerDisplayMode(e->contextID(), m_desiredPlayerDisplayMode); } std::vector CtrlImpl::getBuildingState() const { std::vector ret; std::vector vecEntityIDs; mMapSystem->GetEntitiesInMap("buildings", vecEntityIDs); ret.reserve(vecEntityIDs.size()); VCtrl::ViewerInterface::BuildingState bs; for (const auto id : vecEntityIDs) { bs.buildingId = mMapSystem->GetComponent(id)->GetUniqueId(); bs.description = mMapSystem->GetComponent(id)->GetDescription(); bs.entityId = id; bs.isShown = m_openedViewWidgets.exist(bs.buildingId); ret.push_back(bs); } return ret; } void CtrlImpl::restoreViewWidgetStateDeferred(ViewWidget *pViewWidget) { disconnect(pViewWidget, &ViewWidget::signal_ViewIsShown, this, &CtrlImpl::restoreViewWidgetStateDeferred); auto it = m_deferredViewStates.find(pViewWidget->featureID()); if (it == m_deferredViewStates.end()) { LOG_DEBUG("restoreViewWidgetStateDeferred... default values"); mBuildingManager->setDefaultCameraPosition(pViewWidget->contextID()); return; } const BuildingViewer::ViewWidgetState &state = it->second; LOG_DEBUG("restore view state for " << QString::fromStdString(pViewWidget->featureID()) << ": " << "top=" << state.m_posCamera.m_top << "/ Left=" << state.m_posCamera.m_left << " - " << " bottom=" << state.m_posCamera.m_bottom << "/ right=" << state.m_posCamera.m_right << ", save size: " << state.m_windowWidth << "/" << state.m_windowHeight << ", cur size: " << pViewWidget->accessView()->width() << "/" << pViewWidget->accessView()->height() << ", is visible: " << pViewWidget->accessView()->isVisible() ); const double ratio = ((1.0*pViewWidget->accessView()->width())/pViewWidget->accessView()->height()) / ((1.0*state.m_windowWidth)/state.m_windowHeight); const double oldWidth = state.m_posCamera.m_right - state.m_posCamera.m_left; const double addWidth = oldWidth - (oldWidth / ratio); const BuildingViewer::CameraViewPosition adjustedPos(state.m_posCamera.m_left - addWidth / 2, state.m_posCamera.m_right + addWidth / 2, state.m_posCamera.m_bottom, state.m_posCamera.m_top); const double Oldratio = (pViewWidget->accessView()->height() / double(state.m_windowHeight)) * (pViewWidget->accessView()->width() / double(state.m_windowWidth)); LOG_DEBUG("restore view calculated for " << QString::fromStdString(pViewWidget->featureID()) << ": top=" << adjustedPos.m_top << "/ left=" << adjustedPos.m_left << " - bottom=" << adjustedPos.m_bottom << "/ right:" << adjustedPos.m_right << ", " << "new ratio= " <setDefaultCameraPosition(pViewWidget->contextID()); m_deferredViewStates.erase(it); return; } mBuildingManager->setCameraPosition(pViewWidget->contextID(), adjustedPos); m_deferredViewStates.erase(it); } void CtrlImpl::restoreViewWidgetStates(const std::vector &vecStates) { bool allAlreadyOpened = vecStates.size() == m_openedViewWidgets.size(); for (size_t i = 0; i < vecStates.size() && i < m_openedViewWidgets.getViewWidgets().size() && allAlreadyOpened; ++i) { if (vecStates.at(i).m_featureID != m_openedViewWidgets.getViewWidgets().at(i)->featureID()) allAlreadyOpened = false; } if (allAlreadyOpened) { LOG_DEBUG("ALL OPEN"); } bool useExact = vecStates.empty() ? true : vecStates.front().m_usesExactPos; std::vector vecFeatureIDs; vecFeatureIDs.reserve(vecStates.size()); for (const auto &s : vecStates) vecFeatureIDs.push_back(s.m_featureID); if(!allAlreadyOpened) { closeAllViews(); LOG_DEBUG("Close all and Reopen everything!"); open(vecFeatureIDs, useExact); } for (const auto &savedState : vecStates) { ViewWidget *pViewWidget = m_openedViewWidgets.getViewWidget(savedState.m_featureID); if (!pViewWidget) { Q_ASSERT(false); continue; } LockViewRotationToMapRotation(pViewWidget->contextID(), savedState.m_lockActive); SetPlayerDisplayMode(pViewWidget->contextID(), savedState.m_dotsActive ? PlayerDisplayMode::Dots : PlayerDisplayMode::Icons); SetWallTransparency(pViewWidget->contextID(), savedState.m_usedTransparencyValue); if (savedState.m_isMaximized) onViewWidget_MaximizeRequest(pViewWidget); ChangeViewMode(pViewWidget->contextID(), savedState.m_usesOrtho ? ViewMode::ORTHOGRAPHIC : ViewMode::ISOMETRIC); ChangeNameMode(pViewWidget->contextID(), savedState.m_namesActive); m_deferredViewStates.insert(std::make_pair(savedState.m_featureID, savedState)); if (pViewWidget->accessView()->isVisible()) restoreViewWidgetStateDeferred(pViewWidget); else connect(pViewWidget, &ViewWidget::signal_ViewIsShown, this, &CtrlImpl::restoreViewWidgetStateDeferred); } } static QString strAssetImagePath_IndoorCamera() { return QDir::tempPath() + QStringLiteral("/bgviewer_asset_indoorcamera.png"); } static QString strAssetImagePath_IndoorCameraWithSpeaker() { return QDir::tempPath() + QStringLiteral("/bgviewer_asset_indoorcamera_with_speaker.png"); } static QString strAssetImagePath_AnnouncementUnit() { return QDir::tempPath() + QStringLiteral("/bgviewer_asset_announcement_unit.png"); } static QString strAssetImagePath_EffectGenerationUnit() { return QDir::tempPath() + QStringLiteral("/bgviewer_asset_effect_generation_unit.png"); } void CtrlImpl::convertAssetsToPngFiles() { static bool isUpToDate{false}; if (isUpToDate) return; QImage img(QStringLiteral("icon:bgv_camera.svg")); img.save(strAssetImagePath_IndoorCamera()); img.load(QStringLiteral("icon:bgv_camera_with_speaker.svg")); img.save(strAssetImagePath_IndoorCameraWithSpeaker()); img.load(QStringLiteral("icon:bgv_announcement.svg")); img.save(strAssetImagePath_AnnouncementUnit()); img.load(QStringLiteral("icon:bgv_effect_generation_unit_white_bg.svg")); img.save(strAssetImagePath_EffectGenerationUnit()); isUpToDate = true; } void CtrlImpl::setMountingPointAsset(const MountingPointDescription &asset) { QString strAssetImagePath; switch (asset.assetType) { case BuildingViewer::AssetTypes::IndoorCamera: strAssetImagePath = strAssetImagePath_IndoorCamera(); break; case BuildingViewer::AssetTypes::IndoorCameraWithSpeaker: strAssetImagePath = strAssetImagePath_IndoorCameraWithSpeaker(); break; case BuildingViewer::AssetTypes::AnnouncementUnit: strAssetImagePath = strAssetImagePath_AnnouncementUnit(); break; case BuildingViewer::AssetTypes::EffectGenerationUnit: strAssetImagePath = strAssetImagePath_EffectGenerationUnit(); break; } if (!strAssetImagePath.size()) return; convertAssetsToPngFiles(); ShowDeviceIcon(asset.mountingPointId, asset.buildingId, asset.position, strAssetImagePath.toStdString()); } QJsonValue CtrlImpl::getViewState() const { QJsonArray arr; for (const auto &pView : m_openedViewWidgets.getViewWidgets()) { BuildingViewer::ViewWidgetState state(pView); bool success = mBuildingManager->getCameraPosition(pView->contextID(), state.m_posCamera); LOG_DEBUG("save view state for " << pView->featureID() << ": " << state.m_posCamera.m_top << "/" << state.m_posCamera.m_left << " - " << state.m_posCamera.m_bottom << "/" << state.m_posCamera.m_right << ", save size: " << state.m_windowWidth << "/" << state.m_windowHeight); assert(success); if (success) arr += state.toJson(); } return arr; } void CtrlImpl::setViewState(const QJsonValue &val) { const QJsonArray arr = val.toArray(); std::vector vecStates; vecStates.reserve(arr.size()); for (const auto &ele : arr) vecStates.push_back(BuildingViewer::ViewWidgetState(ele.toObject())); restoreViewWidgetStates(vecStates); } void CtrlImpl::highlightView(const std::string &buildingId) { for (auto pWidget : m_openedViewWidgets.getViewWidgets()) pWidget->setSelected(false); ViewWidget *pWidget = m_openedViewWidgets.getViewWidget(buildingId); if (pWidget) pWidget->setSelected(true); } void CtrlImpl::setBuildingDisplayName(const std::string &buildingId, const std::string &displayName) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingId); if (bid) { if (m_openedViewWidgets.getViewWidget(buildingId)) m_openedViewWidgets.getViewWidget(buildingId)->setText(QString::fromStdString(displayName)); mMapSystem->GetComponent(bid)->SetDescription(displayName); } } ViewWidget *CtrlImpl::GetViewWidget(unsigned int contextid) { auto it = mViewWidgets.find(contextid); return it == mViewWidgets.end() ? nullptr : it->second; } void CtrlImpl::OnTransformSend(const dtEntity::Message &m) { const TransformSendMessage &msg = static_cast(m); if (mViewerCallback != nullptr) { dtEntity::MapComponent *mc = mMapSystem->GetComponent(msg.GetAboutEntity()); assert(mc); if (mc) { const osg::Vec3d p = msg.GetPosition(); const osg::Quat a = msg.GetAttitude(); mViewerCallback->TransformChanged(mc->GetUniqueId(), Vec3d(p[0], p[1], p[2]), Quat(a[0], a[1], a[2], a[3])); } } PlayerComponent *pc; mEntityManager->GetComponent(msg.GetAboutEntity(), pc); assert(pc); if (!pc) return; std::string cellgrp = dtEntity::GetStringFromSID(pc->GetCurrentCellGroup()); mBuildingManager->updatePlayerPosition(cellgrp, msg.GetAboutEntity(), msg.GetPosition(), msg.GetRoomNumber()); } void CtrlImpl::OnNavMeshGroupChanged(const dtEntity::Message &m) { const NavMeshGroupChangedMessage &msg = static_cast(m); if (mViewerCallback != nullptr) { dtEntity::MapComponent *mc = mMapSystem->GetComponent(msg.GetAboutEntityId()); assert(mc); if (mc) mViewerCallback->NavMeshGroupChanged(mc->GetUniqueId(), msg.GetGroupName()); } std::string gn = msg.GetGroupName(); std::string pgn = msg.GetPreviousGroupName(); PlayerComponent *pc; mEntityManager->GetComponent(msg.GetAboutEntityId(), pc); assert(pc); if (!pc) return; std::string roomname = dtEntity::GetStringFromSID(pc->GetCurrentRoom()); if (!pgn.empty()) mBuildingManager->removePlayerFromBuilding(pgn, msg.GetAboutEntityId(), roomname); if (!gn.empty()) { IconComponent *ic; mEntityManager->GetComponent(msg.GetAboutEntityId(), ic); assert(ic); if (ic) mBuildingManager->addPlayerToBuildings(gn, msg.GetAboutEntityId(), pc->GetColor(), ic->GetPath(), ic->GetTranslation(), ic->GetVisible()); } } void CtrlImpl::OnPlayerPicked(const dtEntity::Message &m) { if (mViewerCallback != nullptr) { const PlayerPickedMessage &msg = static_cast(m); dtEntity::EntityId worldid = mBuildingManager->getWorldPlayerIdFromLocalPlayer(msg.GetAboutEntityId()); if (worldid == 0) { LOG_ERROR("Could not resolve proxy player to world player!"); } else { dtEntity::MapComponent *mc = mMapSystem->GetComponent(worldid); assert(mc); if (mc) mViewerCallback->PlayerPicked(mc->GetUniqueId()); } } } void CtrlImpl::OnHideSelection(const dtEntity::Message& m) { const HideSelectionMessage& msg = static_cast(m); if (msg.GetNameFlagId() == false) { mBuildingManager->setShowPlayerSelection(msg.GetAboutEntityId(), false); } else { mBuildingManager->setShowDisplayNamesSelection(msg.GetAboutEntityId(), false); } } void CtrlImpl::OnShoot(const dtEntity::Message &m) { const ShootMessage &msg = static_cast(m); mBuildingManager->showShoot(msg.GetId(), msg.GetShooter(), msg.GetTarget(), msg.GetShooterPos(), msg.GetTargetPos(), msg.GetBuildingIdSrc(), msg.GetRoomNumberSrc(), msg.GetBuildingIdDst(), msg.GetRoomNumberDst(), msg.GetLineType(), msg.GetDuration(), msg.GetSimTimeCreated()); } void CtrlImpl::OnShowHidePlayer(const dtEntity::Message &m) { const ShowHidePlayerMessage &msg = static_cast(m); mBuildingManager->setShowHidePlayer(msg.GetAboutEntityId(), msg.GetShow()); } void CtrlImpl::OnDisplayNameClicked(const dtEntity::Message& m) { if(mViewerCallback != nullptr) { const DisplayNameClickedMessage& msg = static_cast(m); std::string building; std::string room; dtEntity::EntityId worldid = mBuildingManager->getWorldNameIdFromLocalName(msg.GetAboutEntityId(), building, room); if(worldid == 0) { LOG_ERROR("Could not resolve name to world name!"); } else { mViewerCallback->DisplayNamePicked( building, room ); mViewerCallback->HandleViewerEvent(BuildingViewer::BgViewerEvents::RoomNameClicked, {building, room}); } } } void CtrlImpl::SetViewerCallback(ViewerCallback *vc) { assert(mViewerCallback == nullptr); assert(vc != nullptr); mViewerCallback = vc; mLogHandler = new LogHandler(mViewerCallback); dtEntity::LogManager::GetInstance().AddListener(mLogHandler); } void CtrlImpl::RemoveViewerCallback() { dtEntity::LogManager::GetInstance().RemoveListener(mLogHandler); mViewerCallback = nullptr; mLogHandler = nullptr; } bool CtrlImpl::SpawnBuilding(const BuildingData &b, bool useStaticMeshesFolder) { dtEntity::EntityManager &em = *mEntityManager; std::ostringstream meshpath; if(useStaticMeshesFolder) { assert(osgDB::getFileExtension(b.mFileName) == "flt"); meshpath << b.mFileName << ".ive"; } else { meshpath << b.mFileName; } if (osgDB::findDataFile(meshpath.str()).empty()) { osgDB::FilePathList filePathList = osgDB::getDataFilePathList(); LOG_ERROR("Cannot find building mesh file " << meshpath.str() << " Path=" << meshpath.str() << " xmlPath=" << b.mBuildingXMLPath << " osgDB=" << osgDB::getCurrentWorkingDirectory() << " getPathRoot=" << osgDB::getPathRoot(meshpath.str()) << " useStaticMeshesFolder=" << useStaticMeshesFolder << " b.mFileName=" << b.mFileName << " b.mDescription" << b.mDescription << " b.mDisplayName" << b.mDisplayName << " filePathList.size=" << filePathList.size()); for ( unsigned int i = 0; i < filePathList.size(); i++) { LOG_ERROR(" filePathList[" << i << "]=" << filePathList[i]); } return false; } dtEntity::Entity *entity; em.CreateEntity(entity); dtEntity::MapComponent *mapcomp; if (!entity->CreateComponent(mapcomp)) return false; mapcomp->SetUniqueId(b.mFeatureId); mapcomp->SetDescription(b.mDescription); mapcomp->SetSaveWithMap(false); mapcomp->SetMapName("buildings"); mapcomp->SetEntityName(b.mFileName + "_" + b.mFeatureId); dtEntityOSG::StaticMeshComponent *smc; if (!entity->CreateComponent(smc)) return false; smc->SetMesh(meshpath.str()); smc->Finished(); dtEntityOSG::PositionAttitudeTransformComponent *pat; if (!entity->CreateComponent(pat)) return false; pat->SetPosition(osg::Vec3d(b.mX, b.mY, b.mZ)); osg::Quat q; q.makeRotate(-b.mOrientation / 180.0 * osg::PI, osg::Vec3(0, 0, 1)); pat->SetAttitude(q); pat->AddChildComponent(dtEntityOSG::StaticMeshComponent::TYPE); pat->Finished(); dtEntityOSG::LayerComponent *layer; if (!entity->CreateComponent(layer)) return false; layer->SetAttachedComponent(dtEntityOSG::PositionAttitudeTransformComponent::TYPE); layer->SetLayer(dtEntity::SID("default")); layer->Finished(); ModelSplitterComponent *msc; if (!entity->CreateComponent(msc)) return false; msc->SetBuildingId(dtEntity::SID(b.mFeatureId)); RoomDestructionComponent *btc; if (!entity->CreateComponent(btc)) return false; mMapSystem->AddToScene(entity->GetId()); mBuildingManager->addBuilding(entity->GetId(), b.mFeatureId); return true; } void CtrlImpl::LoadBuilding(BuildingData& bd, bool useStaticMeshesFolder) { if (m_loadedBuildings.find(bd.mFeatureId) == m_loadedBuildings.end()) { bd.properlySpawned = SpawnBuilding(bd, useStaticMeshesFolder); bd.roomBBoxedLoaded = mBuildingManager->AddRoomOBBs(bd); m_loadedBuildings[bd.mFeatureId] = bd; } } void CtrlImpl::deleteAllBuildings() { closeAllViews(); m_openedViewWidgets.clear(); m_loadedBuildings.clear(); mBuildingManager->deleteAllBuildings(); std::vector vecEntityIDs; mMapSystem->GetEntitiesInMap("buildings", vecEntityIDs); for (const auto &id : vecEntityIDs) { mMapSystem->DeleteComponent(id); } } void CtrlImpl::LoadAllBuildings() { osgDB::FilePathList l = osgDB::getDataFilePathList(); QFileInfo fileInfo; for (const std::string &path : l) { QDirIterator it(QString::fromStdString(path), {QLatin1String("*.ive")}, QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) { QString pathToFile = it.next(); fileInfo.setFile(pathToFile); BuildingData bd; bd.mFileName = pathToFile.toStdString(); bd.mDescription = fileInfo.absoluteFilePath().toStdString(); bd.mFeatureId = fileInfo.fileName().toStdString(); bd.mOrientation = 70.0; bd.mX = 5063.9998768380610; bd.mY = 3331.0000427849591; bd.mZ = 0.0; LoadBuilding(bd, false); } } } bool CtrlImpl::LoadBuildingPositionMap(const std::string &path, bool loadAllAvailableBuildings) { if (path.empty()) { deleteAllBuildings(); return true; } if(loadAllAvailableBuildings) { LoadAllBuildings(); } else { std::vector buildings; if (!mBuildingManager->LoadBuildings(path, buildings)) return false; for (BuildingData &b : buildings) LoadBuilding(b, true); } if (mViewerCallback) mViewerCallback->SystemReady(); return true; } void CtrlImpl::CreatePlayer(const std::string &id, const std::string &iconpath, const Color &color) { dtEntity::Entity *e; mEntityManager->CreateEntity(e); dtEntity::MapComponent *mc; if (!e->CreateComponent(mc)) return; mc->SetEntityName(id); mc->SetUniqueId(id); mc->SetMapName("player"); IconComponent *bc; if (!e->CreateComponent(bc)) return; bc->SetPath(iconpath); bc->SetColor(osg::Vec4(color.x, color.y, color.z, color.w)); bc->SetOriginAtBottom(true); bc->Finished(); dtEntityOSG::LayerComponent *layer; if (!e->CreateComponent(layer)) return; layer->SetAttachedComponent(IconComponent::TYPE); layer->Finished(); PlayerComponent *pc; if (!e->CreateComponent(pc)) return; pc->SetColor(osg::Vec4(color.x, color.y, color.z, color.w)); pc->Finished(); mMapSystem->AddToScene(e->GetId()); } void CtrlImpl::DeletePlayer(const std::string &id, float seconds) { dtEntity::DeleteEntityMessage msg; msg.SetUniqueId(id); if (qFuzzyIsNull(seconds)) mEntityManager->EmitMessage(msg); else mEntityManager->EnqueueMessage(msg, seconds + GetSimulationTime()); } size_t CtrlImpl::GetNumPlayers() const { return mPlayerSystem->GetNumComponents(); } void CtrlImpl::GetPlayerIds(std::vector &toFill) { for (const auto &i : *mPlayerSystem) { dtEntity::EntityId eid = i.first; dtEntity::MapComponent *mc = mMapSystem->GetComponent(eid); if (mc) toFill.push_back(mc->GetUniqueId()); } } size_t CtrlImpl::GetNumBuildings() const { return mBuildingManager->getNumBuildings(); } void CtrlImpl::GetBuildingIds(std::vector &toFill) const { std::vector eids; mBuildingManager->getBuildingIds(eids); toFill.reserve(eids.size()); for (const dtEntity::EntityId &eid : eids) { const dtEntity::MapComponent *mc = mMapSystem->GetComponent(eid); toFill.push_back(mc->GetUniqueId()); } } void CtrlImpl::SetShowSelectionBox(const std::string &id, bool show, float duration) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); if (eid == 0) { LOG_ERROR("SetShowSelectionBox: Could not find entity with unique id " << id); return; } IconComponent *ic; if (mEntityManager->GetComponent(eid, ic)) { ic->SetShowSelection(show); } else { LOG_ERROR("Cannot set player selection, player entity not found!"); return; } mBuildingManager->setShowPlayerSelection(eid, show); if (show && duration > 0) { HideSelectionMessage msg; msg.SetAboutEntityId(eid); mEntityManager->EnqueueMessage(msg, GetSimulationTime() + duration); } } void CtrlImpl::SetPlayerShown(const std::string &id, bool show, double when) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); mPlayerSystem->ShowHidePlayer(eid, show, when); if (when <= 0) mBuildingManager->setShowHidePlayer(eid, show); } void CtrlImpl::GetRoomNames(const std::string &id, std::vector &names) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); if (eid == 0) { LOG_ERROR("Could not get room names, building does not exist: " << id); return; } RoomDestructionComponent *btc; if (mEntityManager->GetComponent(eid, btc)) { const RoomDestructionComponent::RoomDestructions &rc = btc->GetRoomDestructions(); RoomDestructionComponent::RoomDestructions::const_iterator i; for (i = rc.begin(); i != rc.end(); ++i) names.push_back(i->first); } } bool CtrlImpl::SetRoomDestructionValue(const std::string &id, const std::string &roomname, float value) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); mBuildingManager->setRoomDestructionValue(eid, roomname, value); RoomDestructionComponent *btc; if (mEntityManager->GetComponent(eid, btc)) { bool success = btc->SetRoomDestructionValue(roomname, value); btc->Finished(); return success; } return false; } bool CtrlImpl::SetBuildingDestructionValue(const std::string &id, float value) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); mBuildingManager->setBuildingDestructionValue(eid, value); RoomDestructionComponent *btc; if (mEntityManager->GetComponent(eid, btc)) { btc->SetBuildingDestructionValue(value); btc->Finished(); return true; } return false; } float CtrlImpl::GetTimeScale() const { return mPaused ? 0 : mTimeScale; } void CtrlImpl::SetTimeScale(float scale) { mTimeScale = scale; } double CtrlImpl::GetSimulationTime() const { return mSimTime; } void CtrlImpl::SetSimulationTime(double t) { mSimTime = t; } static inline void MovePointIntoOBBIfZero(const VCtrl::OBB &obb, osg::Vec3d &v) { if (obb.mBB.valid() && qFuzzyIsNull(v[0]) && qFuzzyIsNull(v[1])) { v[0] = obb.mBB._min[0] + ( (obb.mBB._max[0] - obb.mBB._min[0]) /3 ); v[1] = obb.mBB._min[1] + ( (obb.mBB._max[1] - obb.mBB._min[1]) /3 ); v[2] = obb.mBB._min[2] + 0.5; v = v * obb.mMatrix; } } void CtrlImpl::Teleport(const std::string& id, double when, const Vec3d& target, const std::string& bldgname, int roomNumber, const std::string& roomname, ZValue zval) { LOG_DEBUG("CtrlImpl::Teleport: " << "id='"<< id << "'" << ", when="<< when << ", target: x=" << target.x << " y=" << target.y << " z=" << target.z << ", bldgname='"<< bldgname << "'" << ", roomNumber="<< roomNumber << ", roomname='"<< roomname << "'" << ", zval=" << ((zval==ZValue::AboveMsl) ? "ZValue::AboveMsl" : "ZValue::RelativeBuildings")); osg::Vec3d t(target.x, target.y, target.z); VCtrl::OBB obb; const auto fixupZVal = [&] (const std::string &bldgname) { if (zval == ZValue::RelativeBuildings) { auto it = m_loadedBuildings.find(bldgname); if (it != m_loadedBuildings.end()) { const BuildingData &bd = it->second; t[2] += bd.mZ; obb.mBB._min[2] += bd.mZ; obb.mBB._max[2] += bd.mZ; } } }; if (!bldgname.empty() && !roomname.empty()) { fixupZVal(bldgname); bool success = mBuildingManager->getRoomBounds(bldgname, roomname, obb); if (!success) { LOG_ERROR("Room not found: " << bldgname << ", " << roomname); } else { MovePointIntoOBBIfZero(obb, t); } dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); if (mBuildingManager->GetExactPos() == false) { VCtrl::PlayerPosition playPos; osg::Vec2d target2d(t.x(), t.y()); playPos.mPosition = target2d; playPos.mWorldPlayerId = eid; PlayerComponent* pc; success = mEntityManager->GetComponent(eid, pc); assert(success); if (success) { std::string currentRoom = dtEntity::GetStringFromSID(pc->GetCurrentRoom()); if (!currentRoom.empty() && roomname != currentRoom) { mBuildingManager->deleteRoomUsagePlayer(bldgname, currentRoom, eid); } target2d = mBuildingManager->AddRoomUsages(bldgname, roomname, playPos); t[0] = target2d[0]; t[1] = target2d[1]; } } mPlayerSystem->TeleportToTarget(eid, when, t, obb, roomNumber, roomname); } else { dtEntity::EntityId nBEid = 0; float distance; std::string strFeatureId; const Building bld = mBuildingManager->getBuildingFromFeatureId(bldgname); if (bld.mWorldBuildingId > 0) { nBEid = bld.mWorldBuildingId; distance = 1; strFeatureId = bld.mFeatureId; } if (nBEid <= 0) { nBEid = mBuildingManager->getNextBuilding(t, distance, strFeatureId); } if (distance < 125.0f) { fixupZVal(strFeatureId); const dtEntity::MapComponent* mc = mMapSystem->GetComponent(nBEid); std::string bName = mc->GetUniqueId(); RoomDestructionComponent* btc; if (mEntityManager->GetComponent(nBEid, btc)) { const RoomDestructionComponent::RoomDestructions& rc = btc->GetRoomDestructions(); if (rc.empty()) { LOG_ERROR("empty room destruction for building: " << bName); Q_ASSERT(false); } else { const std::string rName = rc.begin()->first; if (mBuildingManager->getRoomBounds(bName, rName, obb)) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); mPlayerSystem->TeleportToTarget(eid, when, t, obb, -1, std::string()); } else { LOG_ERROR("Room (next Building) not found: " << bName << ", " << rName << " Distance: " << distance ); } } } } else { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); mPlayerSystem->TeleportToTarget(eid, when, t, VCtrl::OBB(), -1, std::string()); } } dtEntity::GetDebugDrawInterface()->AddCross(t, osg::Vec4(1,0,0,1), 1, 20, false); } void CtrlImpl::Shoot(const int32_t id, const std::string &shooter, const std::string &target, const Vec3d &shooterPos, const Vec3d &targetPos, int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst, int lineType, double when) { if (!m_showHitLines || (m_hitlineDuration_s == 0)) { LOG_DEBUG("Global setting set to not showing hit lines."); return; } if (shooter == target) { return; } dtEntity::EntityId shooterId = mMapSystem->GetEntityIdByUniqueId(shooter); dtEntity::EntityId targetId = mMapSystem->GetEntityIdByUniqueId(target); mPlayerSystem->PlayerShoot(id, shooterId, targetId, shooterPos, targetPos, buildingIdSrc, roomNumberSrc, buildingIdDst, roomNumberDst, lineType, when, m_hitlineDuration_s); } void CtrlImpl::Shoot(const int32_t id, const std::string &shooter, const std::string &targetBuildingId, const std::string &targetRoomId, const Vec3d &shooterPos, int lineType, double when) { if (!m_showHitLines || (m_hitlineDuration_s == 0)) { LOG_DEBUG("Global setting set to not showing hit lines."); return; } const dtEntity::EntityId targetId = mMapSystem->GetEntityIdByUniqueId(targetBuildingId); if (targetId == 0) { LOG_ERROR("Cannot Set Display name, no building found with ID " << targetBuildingId); return; } const dtEntity::EntityId shooterId = mMapSystem->GetEntityIdByUniqueId(shooter); const std::map &rooms = mBuildingManager->GetRoomOBBs(); const std::string key(targetBuildingId + " " + targetRoomId); auto itRoom = rooms.find(key); if (itRoom == rooms.end()) { LOG_WARNING("Could not find room '" << key << "' which should be hit"); return; } const VCtrl::OBB &room(itRoom->second); const auto center = room.mBB.center() * room.mMatrix; const Vec3d targetPos(center.x(), center.y(), center.z()); const int invalidBuildingRoomId = -1; mPlayerSystem->PlayerShoot(id, shooterId, targetId, shooterPos, targetPos, invalidBuildingRoomId, invalidBuildingRoomId, invalidBuildingRoomId, invalidBuildingRoomId, lineType, when, m_hitlineDuration_s); } void CtrlImpl::removeShoot(const int32_t id) { mBuildingManager->removeShoot(id); LOG_WARNING("CtrlImpl::removeShoot '" << id << " "); } void CtrlImpl::ChangeLineMode(unsigned int contextId, bool line) { Q_UNUSED(contextId); m_showHitLines = line; } void CtrlImpl::ChangeNameMode(unsigned int contextId, bool name) { mBuildingManager->changeNameMode(contextId, name); ViewWidget* vw = GetViewWidget(contextId) ; if(vw) vw->setNameModeCheckbox(name); if(mViewerCallback) { mViewerCallback->ViewNameModeChanged(contextId, name); } } bool CtrlImpl::SetDisplayName(const std::string& buildingid, const std::string& roomname, const std::string& strDisplayName) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingid); if (bid == 0) { LOG_ERROR("Cannot Set Display name, no building found with ID " << buildingid); return false; } mBuildingManager->setRoomDisplayName(buildingid, bid, roomname, strDisplayName); return true; } void CtrlImpl::ShowDisplayNames(const std::string& buildingid, bool show) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingid); if(bid == 0) { LOG_ERROR("Cannot Show Display names, no building found with ID " << buildingid); } mBuildingManager->setShowHideDisplayNames(bid, 9999, show); } void CtrlImpl::SetShowDisplayNamesSelectionBox(const std::string& buildingid, const std::string& id, bool show, float duration) { std::ostringstream en; en << "bd_" << buildingid << "_rm_" << id; dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(en.str()); if(eid == 0) { LOG_ERROR("SetShowSelectionBox: Could not find entity with unique ids " << buildingid << ", "<< id); return; } mBuildingManager->setShowDisplayNamesSelection(eid, show); if(show && duration > 0) { HideSelectionMessage msg; msg.SetAboutEntityId(eid); msg.SetNameFlagId(true); mEntityManager->EnqueueMessage(msg, GetSimulationTime() + duration); } } void CtrlImpl::setHitLineDuration(uint32_t durationSec) { m_hitlineDuration_s = durationSec; mBuildingManager->updateShotDuration(m_hitlineDuration_s); } void CtrlImpl::SetPaused(bool v) { mPaused = v; } bool CtrlImpl::GetPaused() const { return mPaused; } void CtrlImpl::SetPlayerColor(const std::string &id, const Color &color) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); osg::Vec4 col(color.x, color.y, color.z, color.w); PlayerComponent *pc; if (mEntityManager->GetComponent(eid, pc)) { pc->SetColor(col); mBuildingManager->setPlayerColor(eid, col); } } void CtrlImpl::SetPlayerIcon(const std::string &id, const std::string &path) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); IconComponent *ic; if (mEntityManager->GetComponent(eid, ic)) { ic->SetPath(path); mBuildingManager->setPlayerIcon(eid, path); } } void CtrlImpl::reloadPlayerIcons() { mBuildingManager->reloadPlayerIcons(); } void CtrlImpl::UpdatePlayerPartyColors(const std::map& mapPlayerColors) { for (const auto& player : mapPlayerColors) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(player.first); mBuildingManager->updatePlayerPartyColor(eid, player.second); } } void CtrlImpl::SetProjectDataPaths(const std::vector &paths) { osgDB::FilePathList l = osgDB::getDataFilePathList(); osgDB::FilePathList newl = l; for (const std::string &newpath : paths) { bool bFound = false; for (const std::string &path : l) { if (path == newpath) { bFound = true; break; } } if (!bFound) newl.push_front(newpath); } osgDB::setDataFilePathList(newl); } void CtrlImpl::onViewWidget_MaximizeRequest(ViewWidget *pWidget) { m_isInFullscreenMode = true; if (mViewerCallback) mViewerCallback->HandleViewerEvent(BuildingViewer::BgViewerEvents::WidgetMaximized, {pWidget->featureID()}); m_pMainWindow->clearGridLayout(); m_pMainWindow->openView(pWidget); pWidget->setMaximized(true); highlightView(pWidget->featureID()); } void CtrlImpl::onViewWidget_MinimizeRequest(ViewWidget *pWidget) { if (mViewerCallback) mViewerCallback->HandleViewerEvent(BuildingViewer::BgViewerEvents::WidgetMinimized, {pWidget->featureID()}); m_pMainWindow->clearGridLayout(); m_pMainWindow->openViews(m_openedViewWidgets.getViewWidgets()); pWidget->setMaximized(false); m_isInFullscreenMode = false; } void CtrlImpl::onViewWidget_CloseRequest(ViewWidget *pWidget) { if (mViewerCallback) mViewerCallback->HandleViewerEvent(BuildingViewer::BgViewerEvents::WidgetClosed, {pWidget->featureID()}); m_openedViewWidgets.remove(pWidget->featureID()); m_pMainWindow->closeView(pWidget); } void CtrlImpl::onViewWidget_FocusRequest(ViewWidget *pWidget) { if (mViewerCallback) mViewerCallback->HandleViewerEvent(BuildingViewer::BgViewerEvents::WidgetGotFocus, {pWidget->featureID()}); for (const auto &pViewWidget : m_openedViewWidgets.getViewWidgets()) pViewWidget->setSelected(false); pWidget->setSelected(true); } void CtrlImpl::onViewWidget_Zoom(ViewWidget *pWidget, bool zoomIn) { BuildingDisplay *pDisplay = mBuildingManager->getBuildingDisplay(pWidget->contextID()); pDisplay->pMotion->performZoom(zoomIn ? 1 : -1, osg::Vec2(0.5f, 0.5f)); } bool CtrlImpl::open(const std::string& strFeatureID, bool exactPos) { std::vector vecFeatureID = {strFeatureID}; return open(vecFeatureID, exactPos); } bool CtrlImpl::open(const std::vector &vecFeatureIDs, bool exactPos) { if (vecFeatureIDs.empty()) return true; if (!m_pMainWindow) return false; for (const std::string &strFeatureID : vecFeatureIDs) { if (m_openedViewWidgets.exist(strFeatureID)) { m_pMainWindow->updateHighlightThreads(m_openedViewWidgets.getViewWidget(strFeatureID)); } } std::vector m_vecNewViewWidgets; for (const std::string &strFeatureID : vecFeatureIDs) { if (m_openedViewWidgets.size() >= m_maxParallelViewWidgets) { LOG_WARNING("Trying to open more than " << m_maxParallelViewWidgets << " ViewWidgets!"); break; } if (!m_openedViewWidgets.exist(strFeatureID)) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(strFeatureID); if (bid > 0) { unsigned int contextid; ViewWidget *pSubView = CreateMainWindowView(bid, strFeatureID, contextid, exactPos); if(!pSubView) { LOG_ERROR("Could not open desired window with feature id " << strFeatureID); continue; } pSubView->setSelected(true); QString desc = QString::fromStdString(mMapSystem->GetComponent(bid)->GetDescription()); pSubView->setText(desc); QObject::connect(pSubView, &ViewWidget::signal_MaximizeRequest, this, &CtrlImpl::onViewWidget_MaximizeRequest); QObject::connect(pSubView, &ViewWidget::signal_MinimizeRequest, this, &CtrlImpl::onViewWidget_MinimizeRequest); QObject::connect(pSubView, &ViewWidget::signal_CloseRequest, this, &CtrlImpl::onViewWidget_CloseRequest); QObject::connect(pSubView, &ViewWidget::signal_FocusRequest, this, &CtrlImpl::onViewWidget_FocusRequest); QObject::connect(pSubView, &ViewWidget::signal_Zoom, this, &CtrlImpl::onViewWidget_Zoom); storeWidget(pSubView, strFeatureID, contextid, m_desiredViewMode, m_desiredPlayerDisplayMode); m_openedViewWidgets.add(pSubView); m_vecNewViewWidgets.push_back(pSubView); } else LOG_WARNING("Requested building was not contained in loaded xml file: " << strFeatureID); } } if (!m_isInFullscreenMode && m_openedViewWidgets.size()) m_pMainWindow->openViews(m_vecNewViewWidgets); return true; } quintptr CtrlImpl::requestMainWindowHandle() { assert(m_pMainWindow); return m_pMainWindow->winId(); } bool CtrlImpl::openAll(bool exactPos) { std::vector vecEntityIDs; mMapSystem->GetEntitiesInMap("buildings", vecEntityIDs); std::vector vecFeatureIDs; for (const auto &id : vecEntityIDs) { QString featureId = QString::fromStdString(mMapSystem->GetComponent(id)->GetUniqueId()); vecFeatureIDs.push_back(featureId.toStdString()); } return open(vecFeatureIDs, exactPos); } bool CtrlImpl::getBuildingString(const std::string &strFeatureID, std::string *strBuildingNameID) { std::size_t posSeparator = strFeatureID.find_last_of('_'); if (posSeparator != std::string::npos) { if (strBuildingNameID) *strBuildingNameID = "Building " + strFeatureID.substr(posSeparator + 1); return true; } return false; } void CtrlImpl::storeWidget(ViewWidget *pWidget, const std::string &strBuildingNameID, unsigned int contextid, VCtrl::ViewMode vmode, PlayerDisplayMode displayMode) { if (mViewerCallback) mViewerCallback->ViewCreated(contextid, vmode); pWidget->setWindowTitle(QString::fromStdString(strBuildingNameID)); pWidget->setViewerInterface(this); mViewWidgets[contextid] = pWidget; pWidget->setDisplayedViewMode(vmode); pWidget->setDotModeCheckbox((displayMode == PlayerDisplayMode::Dots)); mBuildingManager->changeLineMode(contextid, true); ChangeViewMode(contextid, vmode); SetPlayerDisplayMode(contextid, displayMode); SetWallTransparency(contextid, m_desiredTransparencyValue); } void CtrlImpl::OnShowMsgBox(const std::string &strText) { QMessageBox msgBox; msgBox.setText(QString::fromStdString(strText)); msgBox.exec(); } ViewWidget *CtrlImpl::CreateMainWindowView(dtEntity::EntityId bid, const std::string &featureId, unsigned int &contextid, bool exactPos) { osg::Camera* pCamera = createCamera(featureId); ViewWidget *pWidget = addViewWidget(pCamera, contextid, bid, featureId, exactPos); connect(pWidget, &ViewWidget::signal_ViewIsShown, this, &CtrlImpl::restoreViewWidgetStateDeferred); Color col; mBuildingManager->displayBuilding(featureId, contextid, bid, osg::Vec4(col.x, col.y, col.z, col.w), ViewMode::ISOMETRIC, exactPos); return pWidget; } bool CtrlImpl::CreateView(dtEntity::EntityId bid, const std::string &windowtitle, const Color &col, ViewMode viewmode, int screennum, bool fullscreen, int x, int y, int w, int h, unsigned int &contextid, bool exactPos) { const std::string name = "Building " + windowtitle; ViewWidget *pWidget = addViewWidget(createCamera(screennum, fullscreen, x, y, w, h, name, true), contextid, bid, windowtitle); connect(pWidget, &ViewWidget::signal_ViewIsShown, this, &CtrlImpl::restoreViewWidgetStateDeferred); mBuildingManager->displayBuilding(contextid, bid, osg::Vec4(col.x, col.y, col.z, col.w), viewmode, exactPos); storeWidget(pWidget, windowtitle, contextid, viewmode, m_desiredPlayerDisplayMode); return true; } void CtrlImpl::UseExactPositioning(bool exactPos) { LOG_ALWAYS("CtrlImpl: UseExactPositioning=" << ((exactPos) ? "ON" : "OFF")); mBuildingManager->SetExactPos(exactPos); } bool CtrlImpl::OpenView(unsigned int contextId) { auto it = mViewWidgets.find(contextId); if (it == mViewWidgets.end() || it->second == nullptr) return false; return true; } bool CtrlImpl::OpenView(const std::string &buildingid, const std::string &windowtitle, const Color &col, ViewMode viewmode, int screennum, bool fullscreen, int x, int y, int w, int h, unsigned int &contextid, bool exactPos) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingid); if (bid == 0) { LOG_ERROR("Cannot open view, no building found with ID " << buildingid); return false; } if (CreateView(bid, windowtitle, col, viewmode, screennum, fullscreen, x, y, w, h, contextid, exactPos)) { return true; } return false; } void CtrlImpl::CloseView(ViewWidget *pWidget) { if (pWidget->isMaximized()) m_isInFullscreenMode = false; CloseView(pWidget->contextID()); } void CtrlImpl::CloseView(unsigned int contextid) { mBuildingManager->closeBuildingDisplay(contextid); ViewWidget *vw = GetViewWidget(contextid); if (vw) { vw->closeByAPI(); mViewWidgets.erase(contextid); delete vw; vw = nullptr; } if (mViewerCallback) mViewerCallback->ViewClosed(contextid); } void CtrlImpl::ChangeViewMode(unsigned int contextId, ViewMode viewmode) { ViewWidget *vw = GetViewWidget(contextId); if (vw) { bool comingFromOrtho = (viewmode == ViewMode::ISOMETRIC); if(comingFromOrtho && vw->lockedRotation()) { mBuildingManager->lockViewRotationToMapRotation(contextId, false); mBuildingManager->changeViewMode(contextId, viewmode, false); mBuildingManager->lockViewRotationToMapRotation(contextId, true); } else { mBuildingManager->changeViewMode(contextId, viewmode, false); } vw->setDisplayedViewMode(viewmode); if (mViewerCallback) mViewerCallback->ViewModeChanged(contextId, viewmode); } } void CtrlImpl::LockViewRotationToMapRotation(unsigned int contextId, bool lock) { mBuildingManager->lockViewRotationToMapRotation(contextId, lock); ViewWidget *vw = GetViewWidget(contextId) ; if (vw) vw->setLockRotationCheckbox(lock); if (mViewerCallback) mViewerCallback->ViewLockRotationChanged(contextId, lock); } void CtrlImpl::SetPlayerDisplayMode(unsigned int contextId, PlayerDisplayMode mode) { mBuildingManager->setPlayerDisplayMode(contextId, mode); ViewWidget *vw = GetViewWidget(contextId) ; if (vw) vw->setDotModeCheckbox(mode == PlayerDisplayMode::Dots); if (mViewerCallback) mViewerCallback->PlayerDisplayModeChanged(contextId, mode); } void CtrlImpl::SetWallTransparency(unsigned int contextId, float transparency) { mBuildingManager->setWallTransparency(contextId, 1.0 - transparency); ViewWidget *vw = GetViewWidget(contextId) ; if (vw) vw->setTransparency(transparency); if (mViewerCallback) mViewerCallback->ViewTransparencyChanged(); } float CtrlImpl::GetMapRotation() const { return mBuildingManager->getMapRotation(); } void CtrlImpl::SetMapRotation(float angle) { mBuildingManager->setMapRotation(angle); } void CtrlImpl::OpenOverview() { unsigned int contextid; ViewWidget *pWidget = addViewWidget(createCamera(0, false, 100, 100, 800, 600, "Overview", true), contextid); connect(pWidget, &ViewWidget::signal_ViewIsShown, this, &CtrlImpl::restoreViewWidgetStateDeferred); pWidget->show(); mBuildingManager->openOverview(contextid); dtEntity::GetDebugDrawInterface()->SetEnabled(true); const std::map &rooms = mBuildingManager->GetRoomOBBs(); for (const auto &it : rooms) { const VCtrl::OBB &room = it.second; dtEntity::GetDebugDrawInterface()->AddOBB(room.mMatrix, room.mBB._min, room.mBB._max, osg::Vec4(1, 0, 1, 1), 1, FLT_MAX, false); const osg::Vec3 pos = room.mBB.center() * room.mMatrix; dtEntity::GetDebugDrawInterface()->AddString(pos, it.first, osg::Vec4(0, 1, 0, 1), FLT_MAX, false); } dtEntity::MoveCameraToPositionMessage msg; msg.SetPosition(dtEntity::Vec3d(72850.0, 13000.0, 0.0)); mEntityManager->EmitMessage(msg); } void CtrlImpl::FastForwardSimulationTo(double t) { FastForwardMessage msg; msg.SetEndTime(t); mEntityManager->EmitMessage(msg); } void CtrlImpl::DeleteQueuedCommands() { mPlayerSystem->DeleteQueuedCommands(); } void CtrlImpl::GetDeviceNames(const std::string &buildingId, std::vector &names) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingId); if (bid == 0) { LOG_ERROR("Cannot get device names, no building found with ID " << buildingId); return; } dtEntityOSG::StaticMeshComponent *smc; if (!mEntityManager->GetComponent(bid, smc)) { LOG_ERROR("Cannot get device names, building has no static mesh?!?"); return; } FindByNameVisitor v(QStringLiteral("window")); smc->GetNode()->accept(v); for (const auto &node : v.mNodes) { const std::string &n = node->getName(); if (!n.empty()) names.push_back(n); } } bool CtrlImpl::ShowDeviceIcon(const std::string &id, const std::string &buildingid, const std::string &devicename, const std::string &iconpath) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingid); if (bid == 0) { LOG_ERROR("Cannot get device names, no building found with ID " << id); return false; } dtEntityOSG::StaticMeshComponent *smc; if (!mEntityManager->GetComponent(bid, smc)) { LOG_ERROR("Cannot get device names, building has no static mesh?!?"); return false; } FindByNameVisitor v(QString::fromStdString(devicename)); smc->GetNode()->accept(v); if (v.mNodes.empty()) { LOG_ERROR("Cannot get device names,not found in static mesh!"); return false; } dtEntityOSG::PositionAttitudeTransformComponent *pat; if (!mEntityManager->GetComponent(bid, pat)) { LOG_ERROR("Cannot position transform component!"); return false; } osg::Matrix mat; mat.setTrans(pat->GetTranslation()); mat.setRotate(pat->GetAttitude()); for (const auto &node : v.mNodes) { osg::ComputeBoundsVisitor cv; node->accept(cv); if (!cv.getBoundingBox().valid()) { LOG_ERROR("Could not place device icon, has no valid geometry!"); continue; } osg::Vec3d pos = cv.getBoundingBox().center() * mat; dtEntity::Entity *e; mEntityManager->CreateEntity(e); dtEntity::MapComponent *mc; if (!e->CreateComponent(mc)) return false; mc->SetEntityName(id); mc->SetUniqueId(id); mc->SetMapName("device"); IconComponent *bc; if (!e->CreateComponent(bc)) return false; bc->SetPath(iconpath); bc->SetColor(osg::Vec4(1, 1, 1, 1)); bc->SetOriginAtBottom(false); bc->SetTranslation(pos); bc->Finished(); dtEntityOSG::LayerComponent *layer; if (!e->CreateComponent(layer)) return false; layer->SetAttachedComponent(IconComponent::TYPE); layer->Finished(); mMapSystem->AddToScene(e->GetId()); mBuildingManager->addDeviceToBuilding(e->GetId(), bid, pos, iconpath); } return true; } bool CtrlImpl::ShowDeviceIcon(const std::string &id, const std::string &buildingid, const Vec3d &position, const std::string &iconpath) { dtEntity::EntityId bid = mMapSystem->GetEntityIdByUniqueId(buildingid); if (bid == 0) { LOG_ERROR("Cannot get device names, no building found with ID " << buildingid); return false; } dtEntityOSG::PositionAttitudeTransformComponent *pat; if (!mEntityManager->GetComponent(bid, pat)) { LOG_ERROR("Cannot get device names, building has no position node?!?"); return false; } osg::Matrix mat; mat.setTrans(pat->GetTranslation()); mat.setRotate(pat->GetAttitude()); osg::Vec3d pos(position.x, position.y, position.z); pos = pos * mat; dtEntity::Entity *e; mEntityManager->CreateEntity(e); dtEntity::MapComponent *mc; if (!e->CreateComponent(mc)) return false; mc->SetEntityName(id); mc->SetUniqueId(id); mc->SetMapName("device"); IconComponent *bc; if (!e->CreateComponent(bc)) return false; bc->SetPath(iconpath); bc->SetColor(osg::Vec4(1, 1, 1, 1)); bc->SetOriginAtBottom(false); bc->SetTranslation(pos); bc->Finished(); dtEntityOSG::LayerComponent *layer; if (!e->CreateComponent(layer)) return false; layer->SetAttachedComponent(IconComponent::TYPE); layer->Finished(); mMapSystem->AddToScene(e->GetId()); mBuildingManager->addDeviceToBuilding(e->GetId(), bid, pos, iconpath); return true; } bool CtrlImpl::HideDeviceIcon(const std::string &id) { dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(id); if (eid != 0) { mMapSystem->RemoveFromScene(eid); mBuildingManager->removeDeviceFromBuilding(eid); mEntityManager->KillEntity(eid); return true; } return false; } void CtrlImpl::SetNonRealtimeMode(bool on) { mNonRealtimeMode = on; } bool CtrlImpl::GetNonRealtimeMode() const { return mNonRealtimeMode; } bool CtrlImpl::StartVideoRecording(unsigned int contextid, const std::string &path, int w, int h, int framerate, int quality) { mFrameRate = framerate; #ifdef BUILD_WITH_GSTREAMER VideoSystem *vsys; if (!mEntityManager->GetES(vsys)) return false; return vsys->StartVideoRecording(contextid, path, w, h, framerate, quality); #else LOG_ERROR("Not built with GStreamer, video recording not possible!"); return false; #endif } bool CtrlImpl::StartVideoRecording(const std::string &buildingId, const std::string &path, int w, int h, int framerate, int quality) { if (buildingId == "all") { for (const auto &pWidget : m_openedViewWidgets.getViewWidgets()) StartVideoRecording(pWidget->contextID(), path + pWidget->description() + ".mpg", w, h, framerate, quality); } else { ViewWidget *pWidget = m_openedViewWidgets.getViewWidget(buildingId); if (pWidget) StartVideoRecording(pWidget->contextID(), path + pWidget->description() + ".mpg", w, h, framerate, quality); } return true; } bool CtrlImpl::StopVideoRecording(unsigned int contextid) { #ifdef BUILD_WITH_GSTREAMER VideoSystem *vsys; if (!mEntityManager->GetES(vsys)) return false; return vsys->StopVideoRecording(contextid); #else LOG_ERROR("Not built with GStreamer, video recording not possible!"); return false; #endif } bool CtrlImpl::StopVideoRecording(const std::string &buildingId) { if (buildingId == "all") { for (const auto &pWidget : m_openedViewWidgets.getViewWidgets()) StopVideoRecording(pWidget->contextID()); } else { ViewWidget *pWidget = m_openedViewWidgets.getViewWidget(buildingId); if (pWidget) StopVideoRecording(pWidget->contextID()); } return true; } }