2345 lines
73 KiB
C++
Executable File
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;
|
|
}
|
|
|
|
}
|