Files
qt5-legatus-legacy/Lts/Plugins/BuildingViewer/Common/BgViewer/viewerCtrl/viewerinterfaceimpl.cpp
T
2026-08-13 18:33:10 +02:00

2345 lines
73 KiB
C++
Executable File

#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 <dtEntity/mapcomponent.h>
#include <dtEntity/core.h>
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/cameracomponent.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <dtEntityOSG/osgsysteminterface.h>
#include <dtEntityOSG/staticmeshcomponent.h>
#include <osg/io_utils>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osg/ComputeBoundsVisitor>
#include <osgViewer/CompositeViewer>
#include <osgQt/GraphicsWindowQt>
#include <QDesktopWidget>
#include <QApplication>
#include "buildingmanager.h"
#include "viewwidget.h"
#include <QJsonArray>
#include <QMessageBox>
#include <QDirIterator>
#include <QScreen>
#ifdef BUILD_WITH_GSTREAMER
#include "videocomponent.h"
#endif
#include <algorithm>
#include <memory>
#include <cassert>
#include <iostream>
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<osgViewer::CompositeViewer *>(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<osgQt::GraphicsWindowQt *>(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<osg::GraphicsContext::Traits> 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<osg::Camera> 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<double>(traits->width) / static_cast<double>(traits->height), 1.0f, 10000.0f);
return camera.release();
}
// Wrapper which provides dummy parameters
osg::Camera *createCamera(const std::string &name)
{
return createCamera(0, false, 0, 0, 10, 10, name, false);
}
////////////////////////////////////////////////////////////////////////////////
/// \brief CtrlImpl::CtrlImpl
/// \param em
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);
}
// register for messages with callbacks
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<std::string> &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); // strBldId == strFeatureID
}
void CtrlImpl::closeViews(const std::vector<std::string> &vecFeatureIDs)
{
if (vecFeatureIDs.size() == 1 && vecFeatureIDs.front() == "all")
{
closeAllViews();
return;
}
m_pMainWindow->clearGridLayout();
// Close requested widgets (not necessarily all widgets)
for (const auto &strFeatureID : vecFeatureIDs)
{
ViewWidget *pWidget = m_openedViewWidgets.getViewWidget(strFeatureID);
if (pWidget)
{
// User may even remotely close the currently maximized widget
if (pWidget->isMaximized())
m_isInFullscreenMode = false;
CloseView(pWidget);
m_openedViewWidgets.remove(pWidget->featureID());
}
}
// Is there still a maximized widget? If yes, show it. Otherwise show all widgets
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();
// copy, CloseView modifes m_openedViewWidgets
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<ViewWidget *> 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<ViewWidget *> 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<ViewWidget *> m_vecShownViews = m_openedViewWidgets.getViewWidgets();
for (const auto &e : m_vecShownViews)
SetPlayerDisplayMode(e->contextID(), m_desiredPlayerDisplayMode);
}
std::vector<VCtrl::ViewerInterface::BuildingState> CtrlImpl::getBuildingState() const
{
std::vector<VCtrl::ViewerInterface::BuildingState> ret;
std::vector<dtEntity::EntityId> 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");
// workaround - sometimes the osg::Camera position gets lost during
// creation and show - therefore refresh the values here
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()
);
// top and bottom do not change when the window size changes / when zooming is performed
// only left and right, they both get the half of the new available space
// the ratio is calculated from the height and width... don't know exactly why
// const double ratio = (pViewWidget->accessView()->height() / double(state.m_windowHeight)) *
// (pViewWidget->accessView()->width() / double(state.m_windowWidth));
// const double oldWidth = state.m_posCamera.m_right - state.m_posCamera.m_left;
// const double addWidth = oldWidth - (oldWidth / ratio);
// strange ctor - left,right,bottom,top
// 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);
// new ratio (oldW/oldH) / (/)newW/newH)
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));
// if (ratio < 0.55 || ratio > 3)
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= " <<ratio << ", old withd= " << oldWidth << " , addWIdth= " << addWidth << " OLD Ratio= " << Oldratio);
if (adjustedPos.m_left > adjustedPos.m_right )
{
LOG_DEBUG("SET DEFAULT CONTEXT!");
mBuildingManager->setDefaultCameraPosition(pViewWidget->contextID());
m_deferredViewStates.erase(it);
return;
}
mBuildingManager->setCameraPosition(pViewWidget->contextID(), adjustedPos);
m_deferredViewStates.erase(it);
}
void CtrlImpl::restoreViewWidgetStates(const std::vector<BuildingViewer::ViewWidgetState> &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)
{
// return;
LOG_DEBUG("ALL OPEN");
}
//closeAllViews();
/*
* Open all ViewWidgets of this state first.
* This step is important to restore the right aspect ratio of the building since the
* aspect ratio depends on the ViewWidget dimensions. The ViewWidget dimensions itself depend
* on the amount of opened ViewWidgets since the layout is adjusted accordingly.
*/
bool useExact = vecStates.empty() ? true : vecStates.front().m_usesExactPos;
std::vector<std::string> 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);
}
// Set state properties
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");
}
/*
* OpenSceneGraph requires *.png files with absolute paths. Hence, we
* create png files from the required *.svg images located within
* our qrc file in /tmp/.
*/
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();
// if (!QFile::exists(strAssetImagePath))
// 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<BuildingViewer::ViewWidgetState> 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)
{
// If applicable, remove last selection drawing
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;
}
////////////////////////////////////////////////////////////////////////////////
// when player in world space changed its position through teleport
void CtrlImpl::OnTransformSend(const dtEntity::Message &m)
{
const TransformSendMessage &msg = static_cast<const TransformSendMessage &>(m);
// forward to simulator callback
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]));
}
}
// now update icons of player in the various building views
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());
}
////////////////////////////////////////////////////////////////////////////////
// when player enters or exits a building
void CtrlImpl::OnNavMeshGroupChanged(const dtEntity::Message &m)
{
const NavMeshGroupChangedMessage &msg = static_cast<const NavMeshGroupChangedMessage &>(m);
// forward to simulator callback
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());
// remove from previous building
if (!pgn.empty())
mBuildingManager->removePlayerFromBuilding(pgn, msg.GetAboutEntityId(), roomname);
// add to current building
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());
}
}
////////////////////////////////////////////////////////////////////////////////
// user clicked on player icon in building view
void CtrlImpl::OnPlayerPicked(const dtEntity::Message &m)
{
// forward to simulator
if (mViewerCallback != nullptr)
{
const PlayerPickedMessage &msg = static_cast<const PlayerPickedMessage &>(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());
}
}
}
////////////////////////////////////////////////////////////////////////////////
// This message is sent by the showSelection code to hide the selection after a
// defined time interval.
void CtrlImpl::OnHideSelection(const dtEntity::Message& m)
{
const HideSelectionMessage& msg = static_cast<const HideSelectionMessage&>(m);
if (msg.GetNameFlagId() == false)
{
mBuildingManager->setShowPlayerSelection(msg.GetAboutEntityId(), false);
}
else
{
mBuildingManager->setShowDisplayNamesSelection(msg.GetAboutEntityId(), false);
}
}
////////////////////////////////////////////////////////////////////////////////
// this message is sent from player component. We can't call showShoot directly
// from viewer interface call because shots may be displayed in future sim time.
// Shots are handled as a player command.
void CtrlImpl::OnShoot(const dtEntity::Message &m)
{
const ShootMessage &msg = static_cast<const ShootMessage &>(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());
}
////////////////////////////////////////////////////////////////////////////////
// this message is sent from player component. We can't call showHidePlayer directly
// from viewer interface call because hide events may be displayed in future sim time.
// Hide events are handled as a player command.
void CtrlImpl::OnShowHidePlayer(const dtEntity::Message &m)
{
const ShowHidePlayerMessage &msg = static_cast<const ShowHidePlayerMessage &>(m);
mBuildingManager->setShowHidePlayer(msg.GetAboutEntityId(), msg.GetShow());
}
////////////////////////////////////////////////////////////////////////////////
// user clicked on displayName in building view
void CtrlImpl::OnDisplayNameClicked(const dtEntity::Message& m)
{
// forward to simulator
if(mViewerCallback != nullptr)
{
const DisplayNameClickedMessage& msg = static_cast<const DisplayNameClickedMessage&>(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;
// delete mLogHandler; // osg::referenced
mLogHandler = new LogHandler(mViewerCallback);
dtEntity::LogManager::GetInstance().AddListener(mLogHandler);
}
////////////////////////////////////////////////////////////////////////////////
void CtrlImpl::RemoveViewerCallback()
{
dtEntity::LogManager::GetInstance().RemoveListener(mLogHandler);
mViewerCallback = nullptr;
// delete mLogHandler; // osg::referenced
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");
// replace .flt ending with .ive
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;
}
// create building entity
dtEntity::Entity *entity;
em.CreateEntity(entity);
// for internal bookkeeping
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);
// load building mesh
dtEntityOSG::StaticMeshComponent *smc;
if (!entity->CreateComponent(smc))
return false;
smc->SetMesh(meshpath.str());
smc->Finished();
// Remove doors from model
// place in scene
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();
// add to world scene
dtEntityOSG::LayerComponent *layer;
if (!entity->CreateComponent(layer))
return false;
layer->SetAttachedComponent(dtEntityOSG::PositionAttitudeTransformComponent::TYPE);
layer->SetLayer(dtEntity::SID("default"));
layer->Finished();
// used for splitting model for building views
ModelSplitterComponent *msc;
if (!entity->CreateComponent(msc))
return false;
msc->SetBuildingId(dtEntity::SID(b.mFeatureId));
// for coloring rooms by destruction
RoomDestructionComponent *btc;
if (!entity->CreateComponent(btc))
return false;
// add building entity to scene graph etc
mMapSystem->AddToScene(entity->GetId());
mBuildingManager->addBuilding(entity->GetId(), b.mFeatureId);
return true;
}
////////////////////////////////////////////////////////////////////////////////
void CtrlImpl::LoadBuilding(BuildingData& bd, bool useStaticMeshesFolder)
{
// The workaround: Add only if not already opened
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<dtEntity::EntityId> vecEntityIDs;
mMapSystem->GetEntitiesInMap("buildings", vecEntityIDs);
for (const auto &id : vecEntityIDs)
{
mMapSystem->DeleteComponent(id);
}
}
////////////////////////////////////////////////////////////////////////////////
/// \brief CtrlImpl::LoadAllBuildings
/// Loads all buildings contained within the lastly added system path.
/// A StaticMeshes-folder is not required
void CtrlImpl::LoadAllBuildings()
{
// Path list has been filled, e.g., in 'SetProjectDataPaths'
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; // 45.0
bd.mX = 5063.9998768380610;
bd.mY = 3331.0000427849591;
bd.mZ = 0.0;
LoadBuilding(bd, false);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// parse building xml file
bool CtrlImpl::LoadBuildingPositionMap(const std::string &path, bool loadAllAvailableBuildings)
{
if (path.empty())
{
deleteAllBuildings();
return true;
}
if(loadAllAvailableBuildings)
{
LoadAllBuildings();
}
else
{
std::vector<BuildingData> 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)
{
// create player entity for display in world view
dtEntity::Entity *e; mEntityManager->CreateEntity(e);
// for bookkeeping
dtEntity::MapComponent *mc;
if (!e->CreateComponent(mc))
return;
mc->SetEntityName(id);
mc->SetUniqueId(id);
mc->SetMapName("player");
// displays texture or dot
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();
// where to attach icon to scene graph
dtEntityOSG::LayerComponent *layer;
if (!e->CreateComponent(layer))
return;
layer->SetAttachedComponent(IconComponent::TYPE);
layer->Finished();
// player steering
PlayerComponent *pc;
if (!e->CreateComponent(pc))
return;
pc->SetColor(osg::Vec4(color.x, color.y, color.z, color.w));
pc->Finished();
// add to scene!
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<std::string> &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<std::string> &toFill) const
{
std::vector<dtEntity::EntityId> 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)
{
// send to the future
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<std::string> &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);
// change display in open windows
mBuildingManager->setRoomDestructionValue(eid, roomname, value);
// change in central model
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);
// change display in open windows
mBuildingManager->setBuildingDestructionValue(eid, value);
// change in central model
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 = v * obb.mMatrixInverse;
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
{
// OnShowMsgBox("Room (next Building) not found: " + rName + ", damage: " + std::to_string(rc.begin()->second));
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);
}
////////////////////////////////////////////////////////////////////////////////
// shoot to player
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)
{
//LOG_WARNING("Can't shoot myself!");
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);
}
////////////////////////////////////////////////////////////////////////////////
// shoot to room
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<std::string, VCtrl::OBB> &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); // Ignored since 'line' is a global setting
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;
}
// change display in open windows
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)
{
// send to the future
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<std::string, VCtrl::Color>& mapPlayerColors)
{
for (const auto& player : mapPlayerColors)
{
dtEntity::EntityId eid = mMapSystem->GetEntityIdByUniqueId(player.first);
mBuildingManager->updatePlayerPartyColor(eid, player.second);
}
}
////////////////////////////////////////////////////////////////////////////////
void CtrlImpl::SetProjectDataPaths(const std::vector<std::string> &paths)
{
/*
* Important: FilePathList must be kept even if a model has already been loaded into RAM
* since dynamic data is additionaly loaded when showing a building model!
*/
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));
}
// Wrapper function
bool CtrlImpl::open(const std::string& strFeatureID, bool exactPos)
{
std::vector<std::string> vecFeatureID = {strFeatureID};
return open(vecFeatureID, exactPos);
}
bool CtrlImpl::open(const std::vector<std::string> &vecFeatureIDs, bool exactPos)
{
if (vecFeatureIDs.empty())
return true;
if (!m_pMainWindow)
return false;
/*
* We have 2 cases:
*
* 1. View is already open and will therefore by highlighted (blinking border)
* 2. New View(s) is added and shown
*
* We could simply clear m_pMainWindow's layout but loading means that we are simply
* adding new widgets to the layout. If the user requested an already opened Widget it will be highlighted (blinking)
*/
// First case
for (const std::string &strFeatureID : vecFeatureIDs)
{
if (m_openedViewWidgets.exist(strFeatureID))
{
// View is already opened, let it blink
m_pMainWindow->updateHighlightThreads(m_openedViewWidgets.getViewWidget(strFeatureID));
}
}
// Second case
std::vector<ViewWidget *> 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))
{
// View has been requested but has not been created so far
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);
// Context IDs werden im vorangehenden Interface (das, was load(All) aufruft) nicht gespeichert. Daher die warnings, z.b. bei settransparency
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()
{
/*
QMessageBox msgBox;
msgBox.setText("Window handle has been requested");
msgBox.exec();
if(m_pMainWindow)
{
msgBox.setText("m_pMainWindow IS NULLPTR");
msgBox.exec();
}
msgBox.setText("m_pMainWindow: " + QString::number(m_pMainWindow->winId()));
msgBox.exec();
*/
assert(m_pMainWindow);
return m_pMainWindow->winId();
}
////////////////////////////////////////////////////////////////////////////////
/// \brief Loads all respectively all so far not loaded widgets
/// \return
///
bool CtrlImpl::openAll(bool exactPos)
{
std::vector<dtEntity::EntityId> vecEntityIDs;
mMapSystem->GetEntitiesInMap("buildings", vecEntityIDs);
std::vector<std::string> 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)
{
// Feature ID is, e.g., "House_16". We are only interested in the real ID "16"
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;
// Order is important: pWidget must be stored in 'mViewWidgets' before
// the following code is called
// Set correct ViewWidget button appearance
pWidget->setDisplayedViewMode(vmode);
pWidget->setDotModeCheckbox((displayMode == PlayerDisplayMode::Dots));
mBuildingManager->changeLineMode(contextid, true); // Always show hit lines for targets outside of a building (2018-05-17: Potential bug? Use m_showHitLines here?)
// Set corresponding button settings within BuildingManager
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; // ToDo: Find nice color for lightstyle? (112.0/256.0,112.0/256.0,112.0/256.0, 0.0);
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;
//it->second->show();
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))
{
//mViewWidgets[contextid]->show();
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) {
/*
* The following order rotates too much and results in a wrong (icon) visualization.
*
* Start (2D) -> Lock -> Switch to 3D -> Broken visualization
*
* The following works:
*
* Start (2D) -> Switch to 3D -> Lock -> Correct visualization
*
* Workaround: If the user changes the view mode to 3D and "lock" is active, we remove the lock,
* switch the viewmode and lock afterwards.
*/
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<std::string, VCtrl::OBB> &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<std::string> &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;
// create entity for display in world view
dtEntity::Entity *e; mEntityManager->CreateEntity(e);
// for bookkeeping
dtEntity::MapComponent *mc;
if (!e->CreateComponent(mc))
return false;
mc->SetEntityName(id);
mc->SetUniqueId(id);
mc->SetMapName("device");
// displays texture or dot
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();
// where to attach icon to scene graph
dtEntityOSG::LayerComponent *layer;
if (!e->CreateComponent(layer))
return false;
layer->SetAttachedComponent(IconComponent::TYPE);
layer->Finished();
// add to scene!
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)
{
/*
std::stringstream ss;
ss<<"CtrlImpl::ShowDeviceIcon: "<<std::endl;
ss<<"\tid : "<<id<<std::endl;
ss<<"\tbuildingid: "<<buildingid<<std::endl;
ss<<"\tposition : "<<position.x<<", "<<position.y<<", "<<position.z<<std::endl;
ss<<"\ticonpath : "<<iconpath<<std::endl;
OnShowMsgBox(ss.str());
*/
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;
// create entity for display in world view
dtEntity::Entity *e; mEntityManager->CreateEntity(e);
// for bookkeeping
dtEntity::MapComponent *mc;
if (!e->CreateComponent(mc))
return false;
mc->SetEntityName(id);
mc->SetUniqueId(id);
mc->SetMapName("device");
// displays texture or dot
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();
// where to attach icon to scene graph
dtEntityOSG::LayerComponent *layer;
if (!e->CreateComponent(layer))
return false;
layer->SetAttachedComponent(IconComponent::TYPE);
layer->Finished();
// add to scene!
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;
}
}