2846 lines
90 KiB
C++
Executable File
2846 lines
90 KiB
C++
Executable File
#include "buildingmanager.h"
|
|
|
|
#include "iconcomponent.h"
|
|
#include "modelsplittercomponent.h"
|
|
#include "motionmodel.h"
|
|
#include "orthomotionmodel.h"
|
|
#include "playercomponent.h"
|
|
#include "roomdestructioncomponent.h"
|
|
#include "textcomponent.h"
|
|
#include "visitors.h"
|
|
|
|
#include <dtEntity/entitymanager.h>
|
|
#include <dtEntity/commandmessages.h>
|
|
#include <dtEntity/core.h>
|
|
#include <dtEntity/mapcomponent.h>
|
|
#include <dtEntity/systemmessages.h>
|
|
#include <dtEntity/windowinterface.h>
|
|
|
|
#include <dtEntityOSG/cameracomponent.h>
|
|
#include <dtEntityOSG/layercomponent.h>
|
|
#include <dtEntityOSG/layerattachpointcomponent.h>
|
|
#include <dtEntityOSG/lightcomponent.h>
|
|
#include <dtEntityOSG/osginputinterface.h>
|
|
#include <dtEntityOSG/osgsysteminterface.h>
|
|
#include <dtEntityOSG/positionattitudetransformcomponent.h>
|
|
#include <dtEntityOSG/staticmeshcomponent.h>
|
|
|
|
#include <osg/BlendFunc>
|
|
#include <osg/Camera>
|
|
#include <osg/ComputeBoundsVisitor>
|
|
#include <osg/GraphicsContext>
|
|
#include <osg/io_utils>
|
|
#include <osg/LineWidth>
|
|
#include <osg/LineStipple>
|
|
#include <osg/Point>
|
|
#include <osg/Vec3>
|
|
|
|
#include <osgDB/FileNameUtils>
|
|
#include <osgDB/FileUtils>
|
|
|
|
#include <osgViewer/CompositeViewer>
|
|
#include <vector>
|
|
#include "rapidxml.hpp"
|
|
#include "rapidxml_utils.hpp"
|
|
|
|
// Subtract from room OBB height so that only room navmesh cells are in obb
|
|
#define ROOM_OBB_Z_MIN_SUBTRACT 0.1f
|
|
#define ROOM_OBB_Z_MAX_SUBTRACT 0.5f
|
|
|
|
namespace VCtrl
|
|
{
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
BuildingManager::BuildingManager(dtEntity::EntityManager &em)
|
|
: mEntityManager(&em)
|
|
, mShotOverview(false)
|
|
, mExactPos(true)
|
|
, mMapRotation(0)
|
|
, mTickFunctor(this, &BuildingManager::Tick)
|
|
, m_logger(BuildingViewer::getLogger("BuildingManager"))
|
|
{
|
|
em.RegisterForMessages(dtEntity::TickMessage::TYPE, mTickFunctor);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
BuildingManager::~BuildingManager()
|
|
{
|
|
deleteAllBuildings();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::deleteAllBuildings()
|
|
{
|
|
for (auto building : mBuildings)
|
|
{
|
|
qDeleteAll(building->mShots);
|
|
qDeleteAll(building->mDevices);
|
|
qDeleteAll(building->mNames);
|
|
delete building;
|
|
}
|
|
mBuildings.clear();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
osg::Vec2d BuildingManager::AddRoomUsages(const std::string& bldgname, const std::string& roomname, VCtrl::PlayerPosition& playPos)
|
|
{
|
|
const std::string key = bldgname + " " + roomname;
|
|
auto i = mUsedRooms.find(key);
|
|
if (i == mUsedRooms.end())
|
|
{
|
|
RoomPlayers mroomPlayers;
|
|
mroomPlayers.push_back(playPos);
|
|
mUsedRooms[key] = mroomPlayers;
|
|
}
|
|
else
|
|
{
|
|
// room contains player
|
|
RoomPlayers &mroomPlayers = i->second;
|
|
bool knownPlayer = false;
|
|
// for (const PlayerPosition &pp :mroomPlayers)
|
|
for (auto it = mroomPlayers.begin(); it != mroomPlayers.end(); ++it)
|
|
{
|
|
if (it->mWorldPlayerId == playPos.mWorldPlayerId)
|
|
{
|
|
it = mroomPlayers.erase(it);
|
|
//knownPlayer = true;
|
|
// playPos.mPosition = pp.mPosition;
|
|
break;
|
|
}
|
|
}
|
|
if (knownPlayer == false)
|
|
{
|
|
VCtrl::OBB roomObb;
|
|
getRoomBounds(bldgname, roomname, roomObb);
|
|
double shiftVal = 0.6;
|
|
for (const PlayerPosition &pp : mroomPlayers)
|
|
{
|
|
if (qFuzzyCompare(pp.mPosition[0], playPos.mPosition[0]) &&
|
|
qFuzzyCompare(pp.mPosition[1], playPos.mPosition[1]))
|
|
{
|
|
playPos.mPosition = shiftPosition(roomObb, playPos.mPosition, shiftVal);
|
|
}
|
|
}
|
|
mroomPlayers.push_back(playPos);
|
|
}
|
|
}
|
|
return playPos.mPosition;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::deleteRoomUsagePlayer(const std::string& bldgname, const std::string& roomname, dtEntity::EntityId playerId)
|
|
{
|
|
const std::string key = bldgname + " " + roomname;
|
|
auto i = mUsedRooms.find(key);
|
|
if (i != mUsedRooms.end())
|
|
{
|
|
RoomPlayers &mroomPlayers = i->second;
|
|
|
|
// VCtrl::OBB roomObb;
|
|
// getRoomBounds(bldgname, roomname, roomObb);
|
|
// double shiftVal = -0.6;
|
|
// size_t deletedPosition{0};
|
|
|
|
for (auto it = mroomPlayers.begin(); it != mroomPlayers.end(); ++it)
|
|
{
|
|
if (mroomPlayers.size() == 0)
|
|
break;
|
|
const PlayerPosition &pp = *it;
|
|
if (pp.mWorldPlayerId == playerId)
|
|
{
|
|
if (mroomPlayers.size() > 0 )
|
|
{
|
|
it = mroomPlayers.erase(it);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// deletedPosition++;
|
|
}
|
|
// for (auto pos = deletedPosition; pos < mroomPlayers.size(); pos++) {
|
|
// mroomPlayers[pos].mPosition = shiftPosition(roomObb, mroomPlayers[pos].mPosition, shiftVal);
|
|
// }
|
|
}
|
|
if (mUsedRooms[key].empty())
|
|
mUsedRooms.erase(key);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
osg::Vec2d BuildingManager::shiftPosition(const VCtrl::OBB& obb, const osg::Vec2d& pos, double& shiftValue)
|
|
{
|
|
osg::Vec2d position;
|
|
const double wall = 0.4;
|
|
osg::Vec3d v(pos[0], pos[1], 0);
|
|
|
|
v = v * obb.mMatrixInverse;
|
|
v.x() = v.x() + shiftValue;
|
|
if ( v.x() > (obb.mBB.xMax() - wall) )
|
|
{
|
|
v.x() = obb.mBB.xMin() + wall;
|
|
v.y() = v.y() + shiftValue;
|
|
}
|
|
if ( v.y() > obb.mBB.yMax() - wall)
|
|
{
|
|
v.y() = obb.mBB.yMin() + wall;
|
|
shiftValue = shiftValue / 2.0;
|
|
}
|
|
v = v * obb.mMatrix;
|
|
position.x() = v.x();
|
|
position.y() = v.y();
|
|
return position;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::Tick(const dtEntity::Message &message)
|
|
{
|
|
// TRACE_LOG(m_logger) << LOGFUNCTION;
|
|
|
|
QMutexLocker locker(&m_mutexShots);
|
|
|
|
const dtEntity::TickMessage &msg = static_cast<const dtEntity::TickMessage &>(message);
|
|
double simtime = msg.GetSimulationTime();
|
|
|
|
|
|
// for all buildings
|
|
for (Building *building : mBuildings)
|
|
{
|
|
Building &bldg = *building;
|
|
//new Tick system?
|
|
|
|
for (BuildingDisplay &dspl : bldg.mDisplays)
|
|
{
|
|
// FATAL_LOG(m_logger) << "tick display= " << dspl.mShotDisplays.size();
|
|
std::vector<ShotDisplay>::iterator itShotDisplay = dspl.mShotDisplays.begin();
|
|
while (itShotDisplay != dspl.mShotDisplays.end())
|
|
{
|
|
ShotDisplay &shotdspl = *itShotDisplay;
|
|
Shot *shot =shotdspl.mShot;
|
|
|
|
bool lifeTimeOver = (shot->lifeTime() <= simtime);
|
|
bool displayTimeOver = (shot->displayTime() <= simtime);
|
|
/*
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: ID=" << shot->getId();
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: getSimeTimeCreated=" << QString::number(shot->getSimeTimeCreated(),'f',3);
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: simtime=" << (int)simtime;
|
|
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: lifeTime=" << QString::number(shot->lifeTime(), 'f', 3);
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: lifeTimeOver=" << lifeTimeOver;
|
|
FATAL_LOG(m_logger) << "on shotDisplay Tick: displayTimeOver=" << displayTimeOver;
|
|
*/
|
|
if (displayTimeOver)
|
|
{
|
|
dtEntityOSG::LayerAttachPointComponent *lac;
|
|
if (!mEntityManager->GetComponent(dspl.mAttachPointId, lac))
|
|
{
|
|
WARNING_LOG(m_logger) << "NO sLayerAttachPointComponent";
|
|
return;
|
|
}
|
|
if( shotdspl.mGeode.valid())
|
|
{
|
|
DEBUG_LOG(m_logger) << "displayTimeOver OVER KILL IT drawables: !" << shotdspl.mGeode->getNumDrawables();
|
|
while (shotdspl.mGeode->getNumDrawables() > 0)
|
|
shotdspl.mGeode->removeDrawables(0, shotdspl.mGeode->getNumDrawables());
|
|
bool ret = lac->GetNode()->asGroup()->removeChild(shotdspl.mGeode);
|
|
DEBUG_LOG(m_logger) << "displayTimeOver OVER KILL IT! result: " << ret;
|
|
/*
|
|
assert(shotdspl.mGeode->getParent(0));
|
|
while (shotdspl.mGeode.valid() && shotdspl.mGeode->getNumParents() > 0)
|
|
{
|
|
shotdspl.mGeode->getParent(0)->removeChild(shotdspl.mGeode);
|
|
}
|
|
assert(shotdspl.mGeode->getNumParents() == 0);
|
|
*/
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
}
|
|
}
|
|
|
|
if (lifeTimeOver)
|
|
{
|
|
DEBUG_LOG(m_logger) << "lifeTimeOver OVER ERASE IT!";
|
|
itShotDisplay = dspl.mShotDisplays.erase(itShotDisplay);
|
|
}
|
|
else
|
|
++itShotDisplay;
|
|
} //while
|
|
} //for
|
|
|
|
/*
|
|
// for all shots in building
|
|
std::vector<Shot *>::iterator itShot = bldg.mShots.begin();
|
|
|
|
|
|
while (itShot != bldg.mShots.end())
|
|
{
|
|
Shot *shot = *itShot;
|
|
|
|
// Shot still visible and lifespan is not over? Nothing to do, keep current shot visualization
|
|
bool lifeTimeOver = (shot->lifeTime() <= simtime);
|
|
// DEBUG_LOG(m_logger) << LOGFUNCTION << " lifeTimeOver = " << lifeTimeOver << " shot->lifeTime() = " << (int)shot->lifeTime() << " simtime = " << (int)simtime;
|
|
|
|
if ((shot->displayTime() > simtime) && !lifeTimeOver)
|
|
{
|
|
++itShot;
|
|
// DEBUG_LOG(m_logger) << LOGFUNCTION << " continue....";
|
|
continue;
|
|
}
|
|
|
|
// for all building views
|
|
for (BuildingDisplay &dspl : bldg.mDisplays)
|
|
{
|
|
// DEBUG_LOG(m_logger) << LOGFUNCTION << " BuildingDisplay.mContextId = " << dspl.mContextId << ", dspl.mShotDisplays.size()=" << dspl.mShotDisplays.size();
|
|
|
|
// find shot display
|
|
std::vector<ShotDisplay>::iterator itShotDisplay = dspl.mShotDisplays.begin();
|
|
while (itShotDisplay != dspl.mShotDisplays.end())
|
|
{
|
|
ShotDisplay &shotdspl = *itShotDisplay;
|
|
bool remove = false;
|
|
if (shotdspl.mShot == shot)
|
|
{
|
|
if (shotdspl.mGeode.valid())
|
|
{
|
|
DEBUG_LOG(m_logger) <<LOGFUNCTION <<"Found Geopde and remove it";
|
|
osg::Group *parent = shotdspl.mGeode->getParent(0);
|
|
shotdspl.mShot->setDisplayTime(0);
|
|
assert(parent);
|
|
while (shotdspl.mGeode.valid() && shotdspl.mGeode->getNumParents() > 0)
|
|
{
|
|
shotdspl.mGeode->getParent(0)->removeChild(shotdspl.mGeode);
|
|
}
|
|
|
|
assert(shotdspl.mGeode->getNumParents() == 0);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
|
|
}
|
|
if (lifeTimeOver)
|
|
{
|
|
itShotDisplay = dspl.mShotDisplays.erase(itShotDisplay);
|
|
}
|
|
else
|
|
++itShotDisplay;
|
|
}
|
|
else
|
|
++itShotDisplay;
|
|
} // while
|
|
} // for
|
|
|
|
if (lifeTimeOver)
|
|
{
|
|
// Remove shot completely
|
|
itShot = bldg.mShots.erase(itShot);
|
|
delete shot;
|
|
}
|
|
else
|
|
++itShot;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
bool BuildingManager::getFloorOfRoom(const std::string &bdlgFeatureId, int roomNumber, int &floorOut) const
|
|
{
|
|
floorOut = -999;
|
|
auto it = mRoomToFloorPerBldg.find(bdlgFeatureId);
|
|
if (it == mRoomToFloorPerBldg.end())
|
|
return false;
|
|
|
|
const std::map<int, int> &roomToFloor = it->second;
|
|
{
|
|
auto itR = roomToFloor.find(roomNumber);
|
|
if (itR == roomToFloor.end())
|
|
return false;
|
|
floorOut = itR->second;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void BuildingManager::updateShotDuration(unsigned int newDuration_s)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " newDuration_s= " << newDuration_s;
|
|
|
|
QMutexLocker locker(&m_mutexShots);
|
|
|
|
// for all buildings
|
|
for (Building *building : qAsConst(mBuildings))
|
|
{
|
|
// for all shots in building
|
|
for (Shot *pShot : building->mShots)
|
|
pShot->setDisplayTime(newDuration_s);
|
|
|
|
if (!building->mDisplays.empty())
|
|
{
|
|
BuildingDisplay buildingDisplay = building->mDisplays.front();
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " buildingDisplay.mContextId " << buildingDisplay.mContextId;
|
|
updateShots(*building, buildingDisplay);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(buildingDisplay.mContextId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BuildingManager::setCallbackCamPosChanged(const CallbackCamPosChanged &cb)
|
|
{
|
|
mCbCamPosChanged = cb;
|
|
for (auto building : mBuildings)
|
|
{
|
|
for (auto &bd : building->mDisplays)
|
|
{
|
|
if (bd.pMotion)
|
|
bd.pMotion->m_callbackCamPosChanged = mCbCamPosChanged;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// \brief BuildingManager::setCameraPosition
|
|
/// Setting the camera position for a given Building (respectively its contextid)
|
|
/// is only possible, if an actual view has been opened by calling BuildingManager::displayBuilding.
|
|
/// Otherwise, no camera component is available.
|
|
/// \return
|
|
|
|
bool BuildingManager::setCameraPosition(unsigned int contextid, const BuildingViewer::CameraViewPosition& pos)
|
|
{
|
|
BuildingDisplay* pBuildingDisplay = getBuildingDisplay(contextid);
|
|
if (!pBuildingDisplay)
|
|
return false;
|
|
|
|
dtEntityOSG::CameraComponent *pCamComp = nullptr;
|
|
bool success = mEntityManager->GetComponent(pBuildingDisplay->mCameraId, pCamComp);
|
|
if (!success || !pCamComp)
|
|
return false;
|
|
|
|
pCamComp->SetOrthoLeft(pos.m_left);
|
|
pCamComp->SetOrthoRight(pos.m_right);
|
|
pCamComp->SetOrthoBottom(pos.m_bottom);
|
|
pCamComp->SetOrthoTop(pos.m_top);
|
|
pCamComp->UpdateProjectionMatrix();
|
|
pCamComp->UpdateViewMatrix();
|
|
|
|
dtEntity::GetWindowInterface()->RequestRedraw(contextid);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool BuildingManager::getCameraPosition(unsigned int contextid, BuildingViewer::CameraViewPosition& pos)
|
|
{
|
|
BuildingDisplay* pBuildingDisplay = getBuildingDisplay(contextid);
|
|
if (!pBuildingDisplay)
|
|
return false;
|
|
|
|
dtEntityOSG::CameraComponent *pCamComp = nullptr;
|
|
bool success = mEntityManager->GetComponent(pBuildingDisplay->mCameraId, pCamComp);
|
|
if (!success || !pCamComp)
|
|
return false;
|
|
|
|
double znear, zfar; // Unused
|
|
pCamComp->GetCamera()->getProjectionMatrixAsOrtho(pos.m_left, pos.m_right, pos.m_bottom, pos.m_top, znear, zfar);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool BuildingManager::setDefaultCameraPosition(unsigned int contextid)
|
|
{
|
|
BuildingDisplay *pBuildingDisplay = getBuildingDisplay(contextid);
|
|
if (!pBuildingDisplay)
|
|
return false;
|
|
|
|
Building *building = nullptr;
|
|
for (Building *b : mBuildings)
|
|
{
|
|
for (const auto &dspl : b->mDisplays)
|
|
{
|
|
if (&dspl == pBuildingDisplay)
|
|
{
|
|
building = b;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!building)
|
|
return false;
|
|
|
|
repositionCamera(*building, *pBuildingDisplay);
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// \brief BuildingManager::displayBuilding
|
|
/// Wrapper method.
|
|
/// Displays the desired building and checks whether the user tried to set
|
|
/// the building's room name before. If there are existing room names
|
|
/// they are additionally set after creating the building with 'displayBuilding'
|
|
bool BuildingManager::displayBuilding(const std::string& featureId, unsigned int contextid, dtEntity::EntityId buildingid, const osg::Vec4 &bgcolor, ViewMode viewmode, bool exactPos)
|
|
{
|
|
if (!displayBuilding(contextid, buildingid, bgcolor, viewmode, exactPos))
|
|
return false;
|
|
|
|
Building *building = nullptr;
|
|
for (Building *b : mBuildings)
|
|
{
|
|
if (b->mWorldBuildingId == buildingid)
|
|
{
|
|
building = b;
|
|
break;
|
|
}
|
|
}
|
|
assert(building);
|
|
|
|
auto it = m_mapBuildingRoomNames.find(featureId);
|
|
if(it == m_mapBuildingRoomNames.end())
|
|
return false;
|
|
|
|
const std::map<std::string, std::string>& mapRoomNames = it->second;
|
|
for(const auto& e : mapRoomNames)
|
|
setRoomDisplayName(building, e.first, e.second);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool BuildingManager::displayBuilding(unsigned int contextid, dtEntity::EntityId buildingid, const osg::Vec4& bgcolor, ViewMode viewmode, bool exactPos)
|
|
{
|
|
DEBUG_LOG (m_logger ) << "BuildingManager::displayBuilding";
|
|
mExactPos = exactPos;
|
|
dtEntity::EntityManager &em = *mEntityManager;
|
|
|
|
Building *building = nullptr;
|
|
for (Building *b : mBuildings)
|
|
{
|
|
if (b->mWorldBuildingId == buildingid)
|
|
{
|
|
building = b;
|
|
break;
|
|
}
|
|
}
|
|
assert(building);
|
|
if (!building)
|
|
return false;
|
|
|
|
// create new BuildingDisplay entry.
|
|
building->mDisplays.emplace_back(BuildingDisplay(contextid, viewmode));
|
|
BuildingDisplay &buildingDisplay = building->mDisplays.back();
|
|
|
|
// open 3d display window
|
|
dtEntity::WindowCreatedMessage msg;
|
|
msg.SetName("Building " + std::to_string(buildingid));
|
|
msg.SetContextId(contextid);
|
|
em.EmitMessage(msg);
|
|
|
|
std::string viewname = "Context_" + std::to_string(buildingDisplay.mContextId);
|
|
|
|
dtEntity::MapSystem *mapsys;
|
|
if (!em.GetES(mapsys))
|
|
return false;
|
|
|
|
// create attach point entity
|
|
{
|
|
dtEntity::Entity *e;
|
|
if (!em.CreateEntity(e))
|
|
return false;
|
|
buildingDisplay.mAttachPointId = e->GetId();
|
|
dtEntity::MapComponent *map;
|
|
if (!e->CreateComponent(map))
|
|
return false;
|
|
map->SetEntityName(viewname);
|
|
map->SetMapName("attach");
|
|
map->SetUniqueId(viewname);
|
|
dtEntityOSG::LayerAttachPointComponent *attach;
|
|
if (!e->CreateComponent(attach))
|
|
return false;
|
|
attach->SetName(dtEntity::SID(viewname));
|
|
mapsys->AddToScene(e->GetId());
|
|
}
|
|
|
|
// split the model
|
|
{
|
|
ModelSplitterComponent *msc;
|
|
bool success = em.GetComponent(buildingid, msc);
|
|
assert(success);
|
|
if (!success)
|
|
return false;
|
|
|
|
std::vector<dtEntity::EntityId> ids;
|
|
std::vector<float> heights;
|
|
std::vector<int> floors;
|
|
msc->Split(ids, heights, floors, dtEntity::SID(viewname));
|
|
|
|
// add floors / levels to building
|
|
for (unsigned int i = 0; i < ids.size(); ++i)
|
|
{
|
|
dtEntity::EntityId id = ids[i];
|
|
int floorId = floors[i];
|
|
float height = heights[i];
|
|
mapsys->AddToScene(id);
|
|
|
|
dtEntityOSG::StaticMeshComponent *smc;
|
|
success = em.GetComponent(id, smc);
|
|
assert(success);
|
|
if (!success)
|
|
continue;
|
|
|
|
osg::ComputeBoundsVisitor v;
|
|
smc->GetNode()->accept(v);
|
|
buildingDisplay.mWorldBounds.expandBy(v.getBoundingBox());
|
|
|
|
buildingDisplay.mLevels.emplace_back(BuildingLevel(id, floorId, height, v.getBoundingBox()));
|
|
|
|
// for coloring rooms by destruction value
|
|
RoomDestructionComponent *btc;
|
|
if (em.CreateComponent(id, btc))
|
|
btc->OnEnteredWorld();
|
|
|
|
// prepare meshes for transparency
|
|
ClearVertexColorsVisitor vcv;
|
|
smc->GetNode()->accept(vcv);
|
|
}
|
|
}
|
|
|
|
// create camera and motion model
|
|
{
|
|
dtEntity::Entity *cam;
|
|
if (!em.CreateEntity(cam))
|
|
return false;
|
|
buildingDisplay.mCameraId = cam->GetId();
|
|
|
|
dtEntityOSG::CameraComponent *camcomp;
|
|
if (!cam->CreateComponent(camcomp))
|
|
return false;
|
|
camcomp->SetContextId(contextid);
|
|
camcomp->SetLayerAttachPoint(dtEntity::SID(viewname));
|
|
camcomp->SetClearColor(bgcolor);
|
|
camcomp->SetProjectionMode(dtEntityOSG::CameraComponent::ModeOrthoId);
|
|
camcomp->Finished();
|
|
|
|
|
|
OrthoMotionModelComponent *motion;
|
|
if (!cam->CreateComponent(motion))
|
|
return false;
|
|
motion->SetContextId(contextid);
|
|
motion->Finished();
|
|
buildingDisplay.pMotion = motion;
|
|
buildingDisplay.pMotion->m_callbackCamPosChanged = mCbCamPosChanged;
|
|
|
|
dtEntity::MapComponent *mapcomp;
|
|
if (!cam->CreateComponent(mapcomp))
|
|
return false;
|
|
std::string name = "cam_" + std::to_string(contextid);
|
|
mapcomp->SetEntityName(name);
|
|
mapcomp->SetUniqueId(name);
|
|
mapcomp->SetMapName("cams");
|
|
mapcomp->Finished();
|
|
|
|
mapsys->AddToScene(cam->GetId());
|
|
}
|
|
|
|
// create light source
|
|
{
|
|
dtEntity::Entity *light;
|
|
if (!em.CreateEntity(light))
|
|
return false;
|
|
buildingDisplay.mLightId = light->GetId();
|
|
dtEntityOSG::LightComponent *lightcomp;
|
|
if (!light->CreateComponent(lightcomp))
|
|
return false;
|
|
lightcomp->SetVec4(dtEntityOSG::LightComponent::PositionId, osg::Vec4(0.8f, 0.2f, 1, 0));
|
|
lightcomp->SetVec4(dtEntityOSG::LightComponent::DiffuseId, osg::Vec4(1, 1, 1, 1));
|
|
lightcomp->SetVec4(dtEntityOSG::LightComponent::AmbientId, osg::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
|
|
|
|
dtEntity::MapComponent *mapc;
|
|
if (!light->CreateComponent(mapc))
|
|
return false;
|
|
std::string name = "light_" + std::to_string(contextid);
|
|
mapc->SetEntityName(name);
|
|
mapc->SetUniqueId(name);
|
|
mapc->SetMapName("lights");
|
|
|
|
dtEntityOSG::LayerComponent *layer;
|
|
if (!light->CreateComponent(layer))
|
|
return false;
|
|
layer->SetAttachedComponent(dtEntityOSG::LightComponent::TYPE);
|
|
layer->SetLayer(dtEntity::SID(viewname));
|
|
layer->Finished();
|
|
|
|
mapsys->AddToScene(light->GetId());
|
|
}
|
|
|
|
applyViewModeToBuildingParts(*building, buildingDisplay);
|
|
repositionCamera(*building, buildingDisplay);
|
|
|
|
// add existing players to view
|
|
{
|
|
PlayerSystem *ps;
|
|
if (mEntityManager->GetES(ps))
|
|
{
|
|
for (const auto &i : *ps)
|
|
{
|
|
PlayerComponent *pc = i.second;
|
|
// if they are in this building
|
|
if (dtEntity::GetStringFromSID(pc->GetCurrentCellGroup()) == building->mNavMeshGrpName)
|
|
{
|
|
IconComponent *ic;
|
|
if (mEntityManager->GetComponent(i.first, ic))
|
|
addPlayerToBuilding(*building, buildingDisplay, i.first, pc->GetColor(), ic->GetPath(), ic->GetTranslation(), ic->GetVisible());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// add existing shot lines to view
|
|
{
|
|
QMutexLocker locker(&m_mutexShots);
|
|
if (!building->mShots.empty())
|
|
{
|
|
for (Shot *s : building->mShots)
|
|
{
|
|
ShotDisplay sd;
|
|
sd.mShot = s;
|
|
buildingDisplay.mShotDisplays.push_back(std::move(sd));
|
|
}
|
|
updateShots(*building, buildingDisplay);
|
|
}
|
|
}
|
|
|
|
// add existing device icons to view
|
|
{
|
|
DEBUG_LOG(m_logger) << "mDevices.size = " << building->mDevices.size();
|
|
if (!building->mDevices.empty())
|
|
{
|
|
for (Device *d : building->mDevices)
|
|
{
|
|
DeviceDisplay sd;
|
|
sd.mDevice = d;
|
|
sd.mWorldPlayerId = d->mWorldPlayerId;
|
|
buildingDisplay.mDeviceDisplays.push_back(std::move(sd));
|
|
}
|
|
updateDevices(*building, buildingDisplay);
|
|
}
|
|
}
|
|
|
|
// apply room destruction values
|
|
{
|
|
RoomDestructionComponent *btc1;
|
|
if (em.GetComponent(buildingid, btc1))
|
|
{
|
|
const RoomDestructionComponent::RoomDestructions &rd = btc1->GetRoomDestructions();
|
|
|
|
for (const BuildingLevel &level : buildingDisplay.mLevels)
|
|
{
|
|
RoomDestructionComponent *btc2;
|
|
if (mEntityManager->GetComponent(level.mEntityId, btc2))
|
|
{
|
|
if (!btc2)
|
|
continue;
|
|
for (const auto &destr : rd)
|
|
btc2->SetRoomDestructionValue(destr.first, destr.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// create names
|
|
if(building->mNames.empty())
|
|
{
|
|
createRoomNames(buildingid, *building);
|
|
}
|
|
|
|
// add roomnames to view
|
|
{
|
|
if(!building->mNames.empty())
|
|
{
|
|
for (Name *n : building->mNames)
|
|
{
|
|
NameDisplay nd;
|
|
nd.mName = n;
|
|
nd.mWorldPlayerId = n->mWorldPlayerId;
|
|
nd.visible = false;
|
|
buildingDisplay.mNameDisplays.push_back(std::move(nd));
|
|
}
|
|
updateNames(*building, buildingDisplay);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::closeBuildingDisplay(unsigned int contextid)
|
|
{
|
|
dtEntity::MapSystem* mapsys;
|
|
if (!mEntityManager->GetES(mapsys))
|
|
return;
|
|
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (auto it = building->mDisplays.begin(); it != building->mDisplays.end(); ++it)
|
|
{
|
|
const BuildingDisplay &bd = (*it);
|
|
if (bd.mContextId == contextid)
|
|
{
|
|
osgViewer::CompositeViewer* cv = static_cast<osgViewer::CompositeViewer*>(dtEntityOSG::GetOSGSystemInterface()->GetViewer());
|
|
cv->stopThreading();
|
|
|
|
// remove view from CompositeViewer
|
|
osgViewer::ViewerBase::Cameras cams;
|
|
cv->getCameras(cams);
|
|
for (osg::Camera *c : cams)
|
|
{
|
|
if (c->getGraphicsContext()->getState()->getContextID() == contextid)
|
|
{
|
|
cv->removeView(dynamic_cast<osgViewer::View*>(c->getView()));
|
|
}
|
|
}
|
|
cv->startThreading();
|
|
|
|
// remove all level entities
|
|
for (const BuildingLevel &level : bd.mLevels)
|
|
{
|
|
dtEntity::EntityId eid = level.mEntityId;
|
|
mapsys->RemoveFromScene(eid);
|
|
mEntityManager->KillEntity(eid);
|
|
}
|
|
|
|
mapsys->RemoveFromScene(bd.mLightId);
|
|
mEntityManager->KillEntity(bd.mLightId);
|
|
mapsys->RemoveFromScene(bd.mCameraId);
|
|
mEntityManager->KillEntity(bd.mCameraId);
|
|
mapsys->RemoveFromScene(bd.mAttachPointId);
|
|
mEntityManager->KillEntity(bd.mAttachPointId);
|
|
|
|
// remove all players on this building
|
|
for (const PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
mapsys->RemoveFromScene(pd.mLocalPlayerId);
|
|
mEntityManager->KillEntity(pd.mLocalPlayerId);
|
|
}
|
|
|
|
for (const DeviceDisplay &pd : bd.mDeviceDisplays)
|
|
{
|
|
mapsys->RemoveFromScene(pd.mLocalPlayerId);
|
|
mEntityManager->KillEntity(pd.mLocalPlayerId);
|
|
}
|
|
|
|
// remove all names on this building
|
|
for (const NameDisplay &nd : bd.mNameDisplays)
|
|
{
|
|
mapsys->RemoveFromScene(nd.mLocalPlayerId);
|
|
mEntityManager->KillEntity(nd.mLocalPlayerId);
|
|
}
|
|
building->mDisplays.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::addBuilding(dtEntity::EntityId buildingid, const std::string &featureId)
|
|
{
|
|
Building *b = new Building;
|
|
b->mWorldBuildingId = buildingid;
|
|
b->mFeatureId = featureId;
|
|
mBuildings.push_back(b);
|
|
|
|
// get transform matrix of building in world space.
|
|
dtEntityOSG::PositionAttitudeTransformComponent *pat;
|
|
mEntityManager->GetComponent(buildingid, pat);
|
|
if (!pat)
|
|
return;
|
|
b->mLocalToWorld.setRotate(pat->GetAttitude());
|
|
b->mLocalToWorld.setTrans(pat->GetTranslation());
|
|
b->mWorldToLocal = osg::Matrix::inverse(b->mLocalToWorld);
|
|
|
|
// get BuildingID (navmesh group name). Used to determine if a player is inside this building
|
|
VCtrl::ModelSplitterComponent *msc;
|
|
mEntityManager->GetComponent(buildingid, msc);
|
|
if (!msc)
|
|
return;
|
|
b->mNavMeshGrpName = dtEntity::GetStringFromSID(msc->GetBuildingId());
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
BuildingDisplay *BuildingManager::getBuildingDisplay(unsigned int contextid)
|
|
{
|
|
for (Building *b : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : b->mDisplays)
|
|
{
|
|
if (bd.mContextId == contextid)
|
|
return &bd;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// get eye direction in isometric mode.
|
|
// when rotation is locked then this is a static direction,
|
|
// else it is map angle relative to world space north
|
|
osg::Vec3 getIsoEyeDir(const Building &bd, const BuildingDisplay &d, float maprotation)
|
|
{
|
|
if (d.mLockRotation)
|
|
{
|
|
osg::Vec3 eyedir(0, 1, -0.7f);
|
|
eyedir = bd.mWorldToLocal.getRotate() * eyedir;
|
|
eyedir.normalize();
|
|
eyedir = osg::Quat(-osg::DegreesToRadians(maprotation), osg::Vec3(0, 0, 1)) * eyedir;
|
|
return eyedir;
|
|
}
|
|
else
|
|
{
|
|
osg::Vec3 eye = osg::Vec3(-1, 1, -1);
|
|
eye.normalize();
|
|
return eye;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// place building parts according to projection mode (iso or ortho)
|
|
void BuildingManager::applyViewModeToBuildingParts(const Building &bldg, BuildingDisplay &dspl) const
|
|
{
|
|
dtEntity::EntityManager &em = *mEntityManager;
|
|
|
|
// recalculate bounds
|
|
dspl.mLocalBounds = osg::BoundingBox();
|
|
float maprotation = dspl.mLockRotation ? mMapRotation : 0;
|
|
|
|
switch (dspl.mViewMode)
|
|
{
|
|
case ViewMode::ISOMETRIC:
|
|
{
|
|
// place building parts stacked over each other in z dir.
|
|
// Also update local bounds.
|
|
float h = dspl.mWorldBounds.radius() * osg::PI_2;
|
|
int count = 0;
|
|
for (BuildingLevel &lvl : dspl.mLevels)
|
|
{
|
|
dtEntityOSG::PositionAttitudeTransformComponent *pat;
|
|
if (!em.GetComponent(lvl.mEntityId, pat))
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
|
|
float height = h * count++;
|
|
lvl.mLocalToLevel.makeTranslate(osg::Vec3d(0, 0, height - lvl.mHeightAboveGround));
|
|
pat->SetPosition(osg::Vec3d(0, 0, height - lvl.mHeightAboveGround));
|
|
|
|
osg::ComputeBoundsVisitor v;
|
|
pat->GetNode()->accept(v);
|
|
dspl.mLocalBounds.expandBy(v.getBoundingBox());
|
|
}
|
|
break;
|
|
}
|
|
case ViewMode::ORTHOGRAPHIC:
|
|
{
|
|
// place building parts beside each other in y dir.
|
|
// Parts are each rotated individually. Rotated bounding box
|
|
// defines the distance between building parts.
|
|
// Also update local bounds.
|
|
|
|
float h = 0;
|
|
for (BuildingLevel &lvl : dspl.mLevels)
|
|
{
|
|
dtEntityOSG::PositionAttitudeTransformComponent *pat;
|
|
if (!em.GetComponent(lvl.mEntityId, pat))
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
|
|
pat->SetPosition(osg::Vec3d());
|
|
osg::ComputeBoundsVisitor v;
|
|
pat->GetNode()->accept(v);
|
|
float w = v.getBoundingBox().yMax() - v.getBoundingBox().yMin();
|
|
h += w * 0.6f;
|
|
|
|
osg::Vec3d pos(0, h - v.getBoundingBox().center()[1], -lvl.mHeightAboveGround);
|
|
pat->SetPosition(pos);
|
|
lvl.mLocalToLevel.makeTranslate(osg::Vec3d(0, h - v.getBoundingBox().center()[1], 0));
|
|
h += w * 0.6f;
|
|
|
|
osg::Quat q(0, 0, 0, 1);
|
|
if (dspl.mLockRotation)
|
|
{
|
|
q = bldg.mLocalToWorld.getRotate();
|
|
q *= osg::Quat(osg::DegreesToRadians(maprotation), osg::Vec3(0, 0, 1));
|
|
lvl.mLocalToLevel.setRotate(q);
|
|
}
|
|
pat->SetAttitude(q);
|
|
|
|
osg::ComputeBoundsVisitor v2;
|
|
pat->GetNode()->accept(v2);
|
|
dspl.mLocalBounds.expandBy(v2.getBoundingBox());
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
LOG_ERROR("Unknown view mode set!");
|
|
return;
|
|
}
|
|
|
|
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// position camera according to projection mode and map rotation value.
|
|
void BuildingManager::repositionCamera(const Building &bd, const BuildingDisplay &dspl, bool useOriginViewPos)
|
|
{
|
|
float maprotation = (dspl.mLockRotation) ? mMapRotation : 0;
|
|
|
|
osg::Vec3d eyedir;
|
|
osg::Vec3d up;
|
|
|
|
switch (dspl.mViewMode)
|
|
{
|
|
case ViewMode::ISOMETRIC:
|
|
eyedir = getIsoEyeDir(bd, dspl, maprotation);
|
|
up.set(0, 0, 1);
|
|
break;
|
|
case ViewMode::ORTHOGRAPHIC:
|
|
eyedir.set(0, 0, -1);
|
|
up.set(0, 1, 0);
|
|
break;
|
|
}
|
|
|
|
// fit ortho camera projection to building height (eye direction dependent)
|
|
osg::Vec3 pxa(eyedir ^ up);
|
|
osg::Vec3 pya(pxa ^ eyedir);
|
|
pya.normalize();
|
|
|
|
osg::Plane py(pya, dspl.mLocalBounds.center());
|
|
float ydist = 0;
|
|
for (unsigned int i = 0; i < 8; ++i)
|
|
{
|
|
osg::Vec3 corner = dspl.mLocalBounds.corner(i);
|
|
float dist = fabs(py.distance(corner));
|
|
ydist = std::max(ydist, dist);
|
|
}
|
|
ydist *= 1.1f; // add some margin
|
|
|
|
|
|
// Get camera entity and component
|
|
dtEntityOSG::CameraComponent *camcomp;
|
|
if (!mEntityManager->GetComponent(dspl.mCameraId, camcomp))
|
|
return;
|
|
|
|
/*
|
|
* Save old view state.
|
|
* If called for the first time for dspl.mContextId the values left, right, ... will be INF.
|
|
* In this case 'initialCameraPosWasSet' will be false.
|
|
*/
|
|
bool initialCameraPosWasSet = (m_setInitialCameraPositionSet.find(dspl.mContextId) != m_setInitialCameraPositionSet.end());
|
|
double left, right, bottom, top, znear, zfar;
|
|
camcomp->GetCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, znear, zfar);
|
|
|
|
|
|
// Request window properties
|
|
int x, y, w, h;
|
|
dtEntity::GetWindowInterface()->GetWindowGeometry(dspl.mContextId, x, y, w, h);
|
|
|
|
|
|
/*
|
|
* Jump back to origin and draw building according to the window properties.
|
|
* This step is always required to keep the building's aspect ratio according to
|
|
* the window size.
|
|
*/
|
|
camcomp->SetOrthoLeft(-ydist * w / h);
|
|
camcomp->SetOrthoRight(ydist * w / h);
|
|
camcomp->SetOrthoBottom(-ydist);
|
|
camcomp->SetOrthoTop(ydist);
|
|
camcomp->SetOrthoZNear(-1000);
|
|
camcomp->SetOrthoZFar(1000);
|
|
m_setInitialCameraPositionSet.insert(dspl.mContextId);
|
|
|
|
camcomp->SetPosition(dspl.mLocalBounds.center());
|
|
camcomp->SetEyeDirection(eyedir);
|
|
camcomp->SetUp(up);
|
|
camcomp->UpdateProjectionMatrix();
|
|
camcomp->UpdateViewMatrix();
|
|
|
|
/*
|
|
* If 'useOriginViewPos' is false and an initial camera position has been set
|
|
* we move the camera back from the origin to the last position the user has set with the mouse/keyboard.
|
|
*/
|
|
if(!useOriginViewPos && initialCameraPosWasSet) {
|
|
camcomp->SetOrthoLeft(left);
|
|
camcomp->SetOrthoRight(right);
|
|
camcomp->SetOrthoBottom(bottom);
|
|
camcomp->SetOrthoTop(top);
|
|
camcomp->UpdateViewMatrix();
|
|
}
|
|
|
|
// move light source
|
|
dtEntityOSG::LightComponent *light;
|
|
if (!mEntityManager->GetComponent(dspl.mLightId, light))
|
|
return;
|
|
osg::Vec3 dir(0, 0, -1);
|
|
if (dspl.mViewMode == ViewMode::ISOMETRIC)
|
|
dir = pxa;
|
|
light->SetVec3(dtEntityOSG::LightComponent::DirectionId, dir);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::updatePlayerPositions(const Building &bd, BuildingDisplay &dspl)
|
|
{
|
|
LOG_DEBUG("BuildingManager::updatePlayerPositions: " << " mBuildingDisplayName" << bd.mBuildingDisplayName);
|
|
|
|
// reposition all players currently displayed in building
|
|
for (PlayerDisplay &pd : dspl.mPlayers)
|
|
{
|
|
IconComponent *ic;
|
|
mEntityManager->GetComponent(pd.mWorldPlayerId, ic);
|
|
if (!ic)
|
|
continue;
|
|
int roomNumber = pd.mIcon->GetRoomNumber();
|
|
|
|
LOG_DEBUG("BuildingManager::updatePlayerPositions: "
|
|
<< ", pd.mWorldPlayerId" << pd.mWorldPlayerId
|
|
<< ", roomNumber" << roomNumber);
|
|
|
|
pd.mIcon->SetTranslation(remapPosition(bd, dspl, ic->GetTranslation(), roomNumber));
|
|
pd.mIcon->SetOriginAtBottom(dspl.mViewMode == ViewMode::ISOMETRIC);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::changeViewMode(unsigned int contextId, ViewMode viewmode, bool useOriginViewPos)
|
|
{
|
|
for (Building *bldg : mBuildings)
|
|
{
|
|
for (BuildingDisplay &dspl : bldg->mDisplays)
|
|
{
|
|
if (dspl.mContextId == contextId)
|
|
{
|
|
if (dspl.mViewMode != viewmode)
|
|
{
|
|
dspl.mViewMode = viewmode;
|
|
|
|
applyViewModeToBuildingParts(*bldg, dspl);
|
|
updateShots(*bldg, dspl);
|
|
updatePlayerPositions(*bldg, dspl);
|
|
updateDevices(*bldg, dspl);
|
|
updateNames(*bldg, dspl);
|
|
applyMapRotation(*bldg, dspl);
|
|
}
|
|
|
|
repositionCamera(*bldg, dspl, useOriginViewPos);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(contextId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::applyMapRotation(const Building &bd, BuildingDisplay &dspl)
|
|
{
|
|
dtEntityOSG::CameraComponent *camcomp;
|
|
if (!mEntityManager->GetComponent(dspl.mCameraId, camcomp))
|
|
return;
|
|
|
|
if (dspl.mViewMode == VCtrl::ViewMode::ISOMETRIC)
|
|
{
|
|
camcomp->SetEyeDirection(getIsoEyeDir(bd, dspl, mMapRotation));
|
|
camcomp->UpdateViewMatrix();
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
}
|
|
else
|
|
{
|
|
// have to rotate all building parts individually
|
|
applyViewModeToBuildingParts(bd, dspl);
|
|
updatePlayerPositions(bd, dspl);
|
|
updateDevices(bd, dspl);
|
|
updateNames(bd, dspl);
|
|
|
|
camcomp->UpdateViewMatrix();
|
|
}
|
|
|
|
updateShots(bd, dspl);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::lockViewRotationToMapRotation(unsigned int contextId, bool lock)
|
|
{
|
|
for (Building *bldg : mBuildings)
|
|
{
|
|
for (BuildingDisplay &dspl : bldg->mDisplays)
|
|
{
|
|
if (dspl.mContextId == contextId && dspl.mLockRotation != lock)
|
|
{
|
|
dspl.mLockRotation = lock;
|
|
repositionCamera(*bldg, dspl, false);
|
|
applyViewModeToBuildingParts(*bldg, dspl);
|
|
applyMapRotation(*bldg, dspl);
|
|
repositionCamera(*bldg, dspl, false);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setPlayerDisplayMode(unsigned int contextId, PlayerDisplayMode mode)
|
|
{
|
|
BuildingDisplay *bd = getBuildingDisplay(contextId);
|
|
if (!bd)
|
|
{
|
|
LOG_ERROR("Could not lock view rotation, view with this context id does not exist!");
|
|
return;
|
|
}
|
|
if (bd->mPlayerDisplayMode == mode)
|
|
return;
|
|
bd->mPlayerDisplayMode = mode;
|
|
|
|
for (PlayerDisplay &pd : bd->mPlayers)
|
|
pd.mIcon->SetShowDot(mode == PlayerDisplayMode::Dots);
|
|
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd->mContextId);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setWallTransparency(unsigned int contextId, float value)
|
|
{
|
|
BuildingDisplay *bd = getBuildingDisplay(contextId);
|
|
if (!bd)
|
|
{
|
|
LOG_ERROR("Could not lock view rotation, view with this context id does not exist!");
|
|
return;
|
|
}
|
|
//LOG_ALWAYS("Transparency: " << value)
|
|
SetWallsTransparentVisitor v(value);
|
|
|
|
for (const BuildingLevel &lvl : bd->mLevels)
|
|
{
|
|
dtEntityOSG::StaticMeshComponent *smc;
|
|
if (!mEntityManager->GetComponent(lvl.mEntityId, smc))
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
smc->GetNode()->accept(v);
|
|
}
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd->mContextId);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
float BuildingManager::getMapRotation() const
|
|
{
|
|
return mMapRotation;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setMapRotation(float angle)
|
|
{
|
|
if (qFuzzyCompare(mMapRotation, angle))
|
|
return;
|
|
mMapRotation = angle;
|
|
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
if (bd.mLockRotation)
|
|
applyMapRotation(*building, bd);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::openOverview(unsigned int contextid)
|
|
{
|
|
dtEntity::GetDebugDrawInterface()->SetEnabled(true);
|
|
|
|
dtEntity::WindowCreatedMessage msg;
|
|
msg.SetName("Overview");
|
|
msg.SetContextId(contextid);
|
|
mEntityManager->EmitMessage(msg);
|
|
|
|
dtEntity::Entity *camera;
|
|
if (!mEntityManager->CreateEntity(camera))
|
|
return;
|
|
dtEntityOSG::CameraComponent *camcomp;
|
|
if (!camera->CreateComponent(camcomp))
|
|
return;
|
|
camcomp->SetClearColor(osg::Vec4(0.2f, 0.2f, 0.2f, 1));
|
|
camcomp->SetContextId(contextid);
|
|
camcomp->SetEyeDirection(osg::Vec3(0, -1, 0));
|
|
camcomp->SetLayerAttachPoint(dtEntity::SID("root"));
|
|
camcomp->SetAspectRatio(1.3);
|
|
camcomp->Finished();
|
|
|
|
dtEntity::MapComponent *cammap;
|
|
if (!camera->CreateComponent(cammap))
|
|
return;
|
|
cammap->SetEntityName("cam_overview");
|
|
cammap->SetUniqueId("cam_overview");
|
|
cammap->SetMapName("cams");
|
|
|
|
MotionModelComponent *motion;
|
|
if (!camera->CreateComponent(motion))
|
|
return;
|
|
motion->Finished();
|
|
|
|
dtEntity::MapSystem *ms;
|
|
if (mEntityManager->GetES(ms))
|
|
ms->AddToScene(camera->GetId());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::addPlayerToBuilding(const Building &bd, BuildingDisplay &dspl, dtEntity::EntityId eid,
|
|
const osg::Vec4 &color, const std::string &symbol, const osg::Vec3d &pos, bool visible)
|
|
{
|
|
PlayerDisplay pd;
|
|
pd.mWorldPlayerId = eid;
|
|
|
|
dtEntity::Entity *e;
|
|
if (!mEntityManager->CreateEntity(e))
|
|
return;
|
|
pd.mLocalPlayerId = e->GetId();
|
|
|
|
dtEntity::MapComponent *mc;
|
|
if (!e->CreateComponent(mc))
|
|
return;
|
|
std::string en = "ctx_" + std::to_string(dspl.mContextId) + "_plr_" + std::to_string(pd.mWorldPlayerId);
|
|
mc->SetEntityName(en);
|
|
mc->SetUniqueId(en);
|
|
mc->SetMapName("proxies");
|
|
|
|
if (!e->CreateComponent(pd.mIcon))
|
|
return;
|
|
pd.mIcon->SetVisible(visible);
|
|
pd.mIcon->SetPath(symbol);
|
|
pd.mIcon->SetColor(color);
|
|
pd.mIcon->SetVOffset(0.0f);
|
|
int roomNumber = pd.mIcon->GetRoomNumber();
|
|
pd.mIcon->SetTranslation(remapPosition(bd, dspl, pos, roomNumber));
|
|
pd.mIcon->SetOriginAtBottom(dspl.mViewMode == ViewMode::ISOMETRIC);
|
|
pd.mIcon->SetShowDot(dspl.mPlayerDisplayMode == PlayerDisplayMode::Dots);
|
|
|
|
pd.mIcon->Finished();
|
|
|
|
std::string viewname = "Context_" + std::to_string(dspl.mContextId);
|
|
|
|
dtEntityOSG::LayerComponent *lc;
|
|
if (!e->CreateComponent(lc))
|
|
return;
|
|
lc->SetAttachedComponent(IconComponent::TYPE);
|
|
lc->SetLayer(dtEntity::SID(viewname));
|
|
|
|
dtEntity::MapSystem *ms;
|
|
if (!mEntityManager->GetES(ms))
|
|
return;
|
|
ms->AddToScene(e->GetId());
|
|
|
|
dspl.mPlayers.push_back(std::move(pd));
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::addPlayerToBuildings(const std::string &navmeshgrpname, dtEntity::EntityId eid,
|
|
const osg::Vec4 &color, const std::string &symbol, const osg::Vec3d &pos,
|
|
bool visible)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mNavMeshGrpName != navmeshgrpname)
|
|
continue;
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
addPlayerToBuilding(*building, bd, eid, color, symbol, pos, visible);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::removePlayerFromBuilding(const std::string &navmeshgrpname, dtEntity::EntityId eid, const std::string& roomname)
|
|
{
|
|
if (mExactPos == false)
|
|
deleteRoomUsagePlayer(navmeshgrpname, roomname, eid);
|
|
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mNavMeshGrpName != navmeshgrpname)
|
|
continue;
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (auto it = bd.mPlayers.begin(); it != bd.mPlayers.end(); ++it)
|
|
{
|
|
const PlayerDisplay &pd = *it;
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
dtEntity::MapSystem *ms;
|
|
if (mEntityManager->GetES(ms))
|
|
ms->RemoveFromScene(pd.mLocalPlayerId);
|
|
mEntityManager->KillEntity(pd.mLocalPlayerId);
|
|
bd.mPlayers.erase(it);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::updatePlayerPosition(const std::string &navmeshgrpname, dtEntity::EntityId eid, const osg::Vec3d &pos, int roomNumber)
|
|
{
|
|
LOG_DEBUG("BuildingManager::updatePlayerPosition: " << "navmeshgrpname='"<< navmeshgrpname << "'"
|
|
<< ", eid/WorldPlayerId="<< eid
|
|
<< ", pos: x=" << pos.x() << " y=" << pos.y() << " z=" << pos.z()
|
|
<< ", roomNumber="<< roomNumber);
|
|
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mNavMeshGrpName != navmeshgrpname)
|
|
continue;
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
pd.mIcon->SetTranslation(remapPosition(*building, bd, pos, roomNumber));
|
|
pd.mIcon->SetRoomNumber(roomNumber);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
osg::Vec3d BuildingManager::remapPosition(const Building &bd, const BuildingDisplay &dspl, const osg::Vec3d &world, int roomNumber)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " mFeatureId = " << bd.mFeatureId.c_str()
|
|
<< ", roomNumber= " << roomNumber;
|
|
|
|
if (roomNumber > 0)
|
|
{
|
|
// unfortunately the roomNumber/roomName can not be used to retrieve the floor.
|
|
// Bldg_1106 has floor_-1 with room R_002, 003, 004 ... and floor_-2 has room R_006.
|
|
// So mRoomToFloorPerBldg is introduced and filled while reading the xml file
|
|
int floorOut;
|
|
if (getFloorOfRoom(bd.mFeatureId, roomNumber, floorOut))
|
|
{
|
|
for (const auto &level : dspl.mLevels)
|
|
{
|
|
if (level.mFloorId == floorOut)
|
|
{
|
|
const osg::Vec3d &l = world * bd.mWorldToLocal;
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " mFeatureId = " << bd.mFeatureId.c_str()
|
|
<< ", roomNumber= " << roomNumber
|
|
<< ", floorOut= " << floorOut
|
|
<< ", world.z()= " << world.z()
|
|
<< ", RET value is =" << (l * level.mLocalToLevel).z();
|
|
return l * level.mLocalToLevel;
|
|
}
|
|
} // for
|
|
}
|
|
} // if (roomNumber > 0)
|
|
|
|
// roomNumber NOT set: use approach of Christian Ehrlicher
|
|
// (works for excatly horizontal floors)
|
|
const osg::Vec3d l = world * bd.mWorldToLocal;
|
|
const size_t numlevels = dspl.mLevels.size();
|
|
for (unsigned int i = 0; i < numlevels; ++i)
|
|
{
|
|
if (i == (numlevels - 1) || (dspl.mLevels[i + 1].mHeightAboveGround - 0.1f) > l[2]) // l[2] == l.z()
|
|
{
|
|
const BuildingLevel &level = dspl.mLevels[i];
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION
|
|
<< " remapXPosition"
|
|
<< ", l.z=" << l.z()
|
|
<< ", i=" << i
|
|
<< ", numlevels=" << numlevels
|
|
<< ", (dspl.mLevels[i + 1].mHeightAboveGround - 0.1f)="
|
|
<< (dspl.mLevels[i + 1].mHeightAboveGround - 0.1f)
|
|
<< ", l[2]=" << l[2]
|
|
<< ", ret=" << (l * level.mLocalToLevel).z();
|
|
return l * level.mLocalToLevel;
|
|
}
|
|
}
|
|
LOG_ERROR("Could not remap position!");
|
|
return world;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setPlayerColor(dtEntity::EntityId eid, const osg::Vec4 &color)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
pd.mIcon->SetColor(color);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setPlayerIcon(dtEntity::EntityId eid, const std::string &path)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
pd.mIcon->SetPath(path);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::reloadPlayerIcons()
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
pd.mIcon->Reload();
|
|
|
|
if (bd.mPlayers.size())
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::updatePlayerPartyColor(dtEntity::EntityId eid, const VCtrl::Color& col)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
pd.mIcon->SetColor(osg::Vec4(col.x,col.y,col.z,col.w));
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setShowPlayerSelection(dtEntity::EntityId eid, bool show)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
pd.mIcon->SetShowSelection(show);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setShowHidePlayer(dtEntity::EntityId eid, bool show)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mWorldPlayerId == eid)
|
|
{
|
|
if (pd.mIcon->GetVisible() != show)
|
|
{
|
|
pd.mIcon->SetVisible(show);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setRoomDestructionValue(dtEntity::EntityId eid, const std::string &roomname, float value)
|
|
{
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
if (building->mWorldBuildingId != eid)
|
|
continue;
|
|
for (const BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
bool bRequestRedraw = false;
|
|
for (const BuildingLevel &level : bd.mLevels)
|
|
{
|
|
RoomDestructionComponent *btc;
|
|
if (mEntityManager->GetComponent(level.mEntityId, btc))
|
|
{
|
|
btc->SetRoomDestructionValue(roomname, value);
|
|
bRequestRedraw = true;
|
|
}
|
|
|
|
// if (roomname.compare("2201") == 0)
|
|
// {
|
|
// qCritical() << "XXX setRoomDestructionValue: ";
|
|
|
|
// RoomDestructionComponent *btc;
|
|
// if (mEntityManager->GetComponent(level.mEntityId, btc))
|
|
// {
|
|
// qCritical() << " setRoomDestructionValue: "
|
|
// << ", roomname=" << roomname.c_str()
|
|
// << ", value=" << value
|
|
// << ", level.mEntityId=" << level.mEntityId;
|
|
|
|
// btc->SetRoomDestructionValue("2301", value);
|
|
// bRequestRedraw = true;
|
|
// }
|
|
// }
|
|
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::setBuildingDestructionValue(dtEntity::EntityId eid, float value)
|
|
{
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
if (building->mWorldBuildingId != eid)
|
|
continue;
|
|
for (const BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
bool bRequestRedraw = false;
|
|
for (const BuildingLevel &level : bd.mLevels)
|
|
{
|
|
RoomDestructionComponent *btc;
|
|
if (mEntityManager->GetComponent(level.mEntityId, btc))
|
|
{
|
|
btc->SetBuildingDestructionValue(value);
|
|
bRequestRedraw = true;
|
|
}
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
dtEntity::EntityId BuildingManager::getWorldPlayerIdFromLocalPlayer(dtEntity::EntityId local) const
|
|
{
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
for (const BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (const PlayerDisplay &pd : bd.mPlayers)
|
|
{
|
|
if (pd.mLocalPlayerId == local)
|
|
return pd.mWorldPlayerId;
|
|
}
|
|
|
|
for (const DeviceDisplay &pd : bd.mDeviceDisplays)
|
|
{
|
|
if (pd.mLocalPlayerId == local)
|
|
return pd.mWorldPlayerId;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::removeShoot(int32_t id)
|
|
{
|
|
DEBUG_LOG(m_logger) << "removeShoot id=" << id;
|
|
QMutexLocker locker(&m_mutexShots);
|
|
for (Building *bldg : mBuildings)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Vorher: bldg->mShots.size()=" << bldg->mShots.size();
|
|
auto it = std::remove_if(bldg->mShots.begin(), bldg->mShots.end(),
|
|
[id]( Shot *shot)
|
|
{
|
|
if (shot->getId() == id)
|
|
{
|
|
//delete shot;
|
|
const unsigned int duration = 0;
|
|
shot->setDisplayTime(duration);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
bool wasRemoved = (it != bldg->mShots.end());
|
|
|
|
bldg->mShots.erase(it, bldg->mShots.end());
|
|
DEBUG_LOG(m_logger) << "Nachher: bldg->mShots.size()=" << bldg->mShots.size();
|
|
|
|
if (wasRemoved)
|
|
for (BuildingDisplay &dspl : bldg->mDisplays)
|
|
{
|
|
DEBUG_LOG(m_logger) << "wasRemoved id=" << id;
|
|
updateShots(*bldg, dspl);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::showShoot(int32_t id, dtEntity::EntityId shooter, dtEntity::EntityId target,
|
|
const dtEntity::Vec3d &shooterPos, const dtEntity::Vec3d &targetPos,
|
|
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
|
|
int lineType, float duration, double simTimeCreated)
|
|
{
|
|
PlayerComponent *shooterpc, *targetpc;
|
|
|
|
mEntityManager->GetComponent(shooter, shooterpc);
|
|
mEntityManager->GetComponent(target, targetpc);
|
|
if (!shooterpc) // no check for target - may be a building
|
|
{
|
|
assert(false);
|
|
return;
|
|
}
|
|
|
|
if (mShotOverview == false && targetpc) // only display shots between players in same building
|
|
{
|
|
if (shooterpc->GetCurrentCellGroup() != targetpc->GetCurrentCellGroup())
|
|
return;
|
|
}
|
|
|
|
std::string navmeshname = dtEntity::GetStringFromSID(shooterpc->GetCurrentCellGroup());
|
|
std::string targetnavmeshname;
|
|
if (mShotOverview == true && targetpc)
|
|
targetnavmeshname = dtEntity::GetStringFromSID(targetpc->GetCurrentCellGroup());
|
|
|
|
|
|
QMutexLocker locker(&m_mutexShots);
|
|
for (Building *bldg : mBuildings)
|
|
{
|
|
if ((targetpc == nullptr && target == bldg->mWorldBuildingId) ||
|
|
(bldg->mNavMeshGrpName == navmeshname) ||
|
|
(bldg->mNavMeshGrpName == targetnavmeshname))
|
|
{
|
|
|
|
double _simTimeCreated = simTimeCreated != 0 ? simTimeCreated : dtEntity::GetSystemInterface()->GetSimulationTime() ;
|
|
//float _simTimeCreated = dtEntity::GetSystemInterface()->GetSimulationTime();
|
|
Shot* shot = new Shot(id,
|
|
shooterPos,
|
|
targetPos,
|
|
buildingIdSrc, roomNumberSrc,
|
|
buildingIdDst, roomNumberDst,
|
|
lineType,
|
|
shooterpc->GetColor(),
|
|
static_cast<unsigned int>(duration),
|
|
120,
|
|
_simTimeCreated);
|
|
for(const auto it : bldg->mShots)
|
|
{
|
|
if (it->getId() == shot->getId())
|
|
{
|
|
delete shot;
|
|
return;
|
|
}
|
|
}
|
|
bldg->mShots.push_back(shot);
|
|
DEBUG_LOG(m_logger) << "XXXX SIM TIME CREATED = " << QString::number(_simTimeCreated, 'f', 5) << " and SIM TIME IS " <<QString::number(dtEntity::GetSystemInterface()->GetSimulationTime(), 'f', 5);
|
|
|
|
for (BuildingDisplay &bldgDispl : bldg->mDisplays)
|
|
{
|
|
ShotDisplay shotDispl;
|
|
shotDispl.mShot = shot;
|
|
DEBUG_LOG(m_logger) << "mShotDisplays.push_back id=" << shot->getId();
|
|
bldgDispl.mShotDisplays.push_back(std::move(shotDispl));
|
|
|
|
updateShots(*bldg, bldgDispl);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bldgDispl.mContextId);
|
|
}
|
|
if (targetpc == nullptr && target == bldg->mWorldBuildingId)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::updateShots(const Building &bd, BuildingDisplay &dspl)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " Building= " << bd.mWorldBuildingId;
|
|
|
|
dtEntityOSG::CameraComponent *camcomp;
|
|
if (!mEntityManager->GetComponent(dspl.mCameraId, camcomp))
|
|
return;
|
|
osg::Vec3 eyedir(camcomp->GetEyeDirection());
|
|
|
|
dtEntityOSG::LayerAttachPointComponent *lac;
|
|
if (!mEntityManager->GetComponent(dspl.mAttachPointId, lac))
|
|
return;
|
|
|
|
const double simTime = dtEntity::GetSystemInterface()->GetSimulationTime();
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " dspl.mShotDisplays.size()= " << dspl.mShotDisplays.size()
|
|
<< ", simTime=" << (int)simTime;
|
|
|
|
for (ShotDisplay &shotdspl : dspl.mShotDisplays)
|
|
{
|
|
if (!shotdspl.mShot)
|
|
continue;
|
|
|
|
/*
|
|
* Only show hitlines when: the current
|
|
* sim time is >= getSimeTimeCreated
|
|
* and simdtime <= displayTime
|
|
*
|
|
*/
|
|
|
|
const bool bDisplay = (shotdspl.mShot->displayTime() > simTime) && (shotdspl.mShot->simTimeCreated() <= simTime);
|
|
/*
|
|
FATAL_LOG(m_logger) << LOGFUNCTION << " AA DURATION= "<< shotdspl.mShot->getDuration();
|
|
FATAL_LOG(m_logger) << LOGFUNCTION << " AA SIM TIME= " << (int)simTime << " displayTime= " << (int)shotdspl.mShot->displayTime()<< " (shotdspl.mShot->displayTime() > simTime)= "<< (shotdspl.mShot->displayTime() > simTime);
|
|
FATAL_LOG(m_logger) << LOGFUNCTION << " AA SIM TIME= " << (int)simTime << " simTimeCreated= " << (int)shotdspl.mShot->getSimeTimeCreated()<< " (shotdspl.mShot->simTimeCreated() <= simTime)= "<< (shotdspl.mShot->simTimeCreated() <= simTime);
|
|
FATAL_LOG(m_logger) << LOGFUNCTION << " AA shotdspl.mShot->getId()= " << shotdspl.mShot->getId()
|
|
<< ", bDisplay=" << bDisplay
|
|
<< ", shotdspl.mGeode=" << shotdspl.mGeode;
|
|
*/
|
|
// NLDEVCTRL-1556 Anzeige der Trefferlinien von aussen auf das Gebäude (Raum)
|
|
// ändern sich nicht korrekt mit bei der Umschaltung 2D/3D bzw. Nord/Gelände Sicht
|
|
// Es wird der Geode wieder neu aufgebaut. Dadurch zeigt die Linie an die
|
|
// richtige Stelle und die Pfeilspitzen ist auch 'schön'
|
|
while (shotdspl.mGeode.valid() && shotdspl.mGeode->getNumParents() > 0)
|
|
shotdspl.mGeode->getParent(0)->removeChild(shotdspl.mGeode);
|
|
shotdspl.mGeode = osg::ref_ptr<osg::Geode>();
|
|
|
|
int numParents = -1;
|
|
if (shotdspl.mGeode)
|
|
numParents = shotdspl.mGeode->getNumParents();
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " BB shotdspl.mShot->getId()= " << shotdspl.mShot->getId()
|
|
<< ", shotdspl.mGeode=" << shotdspl.mGeode
|
|
<< ", shotdspl.mGeode->getNumParents=" << numParents
|
|
<< ", bDisplay=" << bDisplay;
|
|
|
|
// does not exist, but should be:
|
|
if ((!shotdspl.mGeode || shotdspl.mGeode->getNumParents() == 0) && bDisplay)
|
|
{
|
|
DEBUG_LOG(m_logger) << "NEW mGeode! id " << shotdspl.mShot->getId();
|
|
if (!shotdspl.mGeode)
|
|
shotdspl.mGeode = new osg::Geode();
|
|
|
|
osg::StateSet *ss = shotdspl.mGeode->getOrCreateStateSet();
|
|
ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
|
ss->setRenderBinDetails(240001, "RenderBin");
|
|
osg::ref_ptr<osg::LineWidth> lw = new osg::LineWidth();
|
|
DEBUG_LOG(m_logger) << "NEW LINE " << shotdspl.mShot->getLineType();
|
|
|
|
if (shotdspl.mShot->getLineType() < 2 )
|
|
{
|
|
int stippleSize = 5;
|
|
if (shotdspl.mShot->getLineType() == 1) //LRF
|
|
stippleSize = 2;
|
|
|
|
osg::ref_ptr<osg::LineStipple> ls = new osg::LineStipple(stippleSize, 0xAAAA);
|
|
ss->setAttributeAndModes(ls, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
|
|
}
|
|
|
|
//osg::ref_ptr<osg::LineStipple> ls = new osg::LineStipple(5, 0xAAAA); //dashed line
|
|
// ss->setAttributeAndModes(ls, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE); // normal LINE
|
|
|
|
lw->setWidth(2);
|
|
//ss->setAttributeAndModes(lw, osg::StateAttribute::ON);
|
|
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
|
// lac->GetNode()->asGroup()->addChild(shotdspl.mGeode); //
|
|
|
|
osg::Geometry *gmtr = new osg::Geometry();
|
|
shotdspl.mGeode->addDrawable(gmtr);
|
|
|
|
osg::Vec4Array *col = new osg::Vec4Array(1);
|
|
(*col)[0] = shotdspl.mShot->getColor();
|
|
gmtr->setColorArray(col);
|
|
gmtr->setColorBinding(osg::Geometry::BIND_OVERALL);
|
|
|
|
osg::Vec3d shooterpos = remapPosition(bd, dspl, shotdspl.mShot->getShooterPos(), shotdspl.mShot->getRoomNumberSrc());
|
|
osg::Vec3d targetpos = remapPosition(bd, dspl, shotdspl.mShot->getTargetPos(), shotdspl.mShot->getRoomNumberDst());
|
|
|
|
// make shot lines go to body center height
|
|
shooterpos[2] += 1;
|
|
targetpos[2] += 1;
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " shotdspl.mShot->getId()= " << shotdspl.mShot->getId()
|
|
<< ", getShooterPos.z()=" << shotdspl.mShot->getShooterPos().z()
|
|
<< ", BuildingIdSrc=" << shotdspl.mShot->getBuildingIdSrc() << ", RoomNumberSrc=" << shotdspl.mShot->getRoomNumberSrc()
|
|
<< ", shooterpos=" << shooterpos
|
|
<< ", getTargetPos.z()=" << shotdspl.mShot->getTargetPos().z()
|
|
<< ", BuildingIdDst=" << shotdspl.mShot->getBuildingIdDst() << ", RoomNumberDst=" << shotdspl.mShot->getRoomNumberDst()
|
|
<< ", targetpos=" << targetpos;
|
|
|
|
osg::Vec3Array *coords = new osg::Vec3Array(6);
|
|
(*coords)[0] = shooterpos;
|
|
(*coords)[1] = targetpos;
|
|
|
|
osg::Vec3d edge = targetpos - shooterpos;
|
|
edge.normalize();
|
|
edge *= 0.8;
|
|
|
|
osg::Vec3d p1 = eyedir ^ edge;
|
|
p1.normalize();
|
|
p1 *= 0.8;
|
|
|
|
|
|
(*coords)[2] = p1 - edge * 1.5 + targetpos;
|
|
(*coords)[3] = targetpos;
|
|
(*coords)[4] = -p1 - edge * 1.5 + targetpos;
|
|
(*coords)[5] = targetpos;
|
|
|
|
gmtr->setVertexArray(coords);
|
|
//gmtr->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 6));
|
|
gmtr->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 6));
|
|
|
|
//gmtr->getOrCreateStateSet()->setAttributeAndModes(new osg::Point(10.0f));
|
|
//gmtr->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, 6));
|
|
|
|
// lac->GetNode()->asGroup()->addChild(shotdspl.mGeode);
|
|
}
|
|
|
|
if (bDisplay)
|
|
lac->GetNode()->asGroup()->addChild(shotdspl.mGeode);
|
|
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::updateDevices(const Building &bd, BuildingDisplay &dspl)
|
|
{
|
|
for (DeviceDisplay &ddspl : dspl.mDeviceDisplays)
|
|
{
|
|
IconComponent *icon;
|
|
if (ddspl.mLocalPlayerId == 0)
|
|
{
|
|
dtEntity::Entity *e;
|
|
if (!mEntityManager->CreateEntity(e))
|
|
continue;
|
|
ddspl.mLocalPlayerId = e->GetId();
|
|
|
|
dtEntity::MapComponent *mc;
|
|
if (!e->CreateComponent(mc))
|
|
continue;
|
|
std::string en = "ctx_" + std::to_string(dspl.mContextId) + "_plr_" + std::to_string(ddspl.mDevice->mWorldPlayerId);
|
|
mc->SetEntityName(en);
|
|
mc->SetUniqueId(en);
|
|
mc->SetMapName("deviceproxies");
|
|
|
|
if (!e->CreateComponent(icon))
|
|
continue;
|
|
icon->SetPath(ddspl.mDevice->mPath);
|
|
icon->SetOriginAtBottom(false);
|
|
|
|
|
|
dtEntityOSG::LayerComponent *lc;
|
|
if (!e->CreateComponent(lc))
|
|
continue;
|
|
std::string viewname = "Context_" + std::to_string(dspl.mContextId);
|
|
lc->SetAttachedComponent(IconComponent::TYPE);
|
|
lc->SetLayer(dtEntity::SID(viewname));
|
|
|
|
dtEntity::MapSystem *ms;
|
|
if (mEntityManager->GetES(ms))
|
|
ms->AddToScene(e->GetId());
|
|
}
|
|
else
|
|
{
|
|
if (!mEntityManager->GetComponent(ddspl.mLocalPlayerId, icon))
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
int roomNumber = icon->GetRoomNumber();
|
|
icon->SetTranslation(remapPosition(bd, dspl, ddspl.mDevice->mPosition, roomNumber));
|
|
icon->Finished();
|
|
icon->SetVisible(true);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::addDeviceToBuilding(dtEntity::EntityId iconmainid, dtEntity::EntityId buildingid,
|
|
const osg::Vec3d &pos, const std::string &iconpath)
|
|
{
|
|
DEBUG_LOG(m_logger) << "addDeviceToBuilding";
|
|
for (Building *building : mBuildings)
|
|
{
|
|
|
|
DEBUG_LOG(m_logger) << "mWorldBuildingId=" << building->mWorldBuildingId
|
|
<< " buildingid=" << buildingid;
|
|
|
|
if (building->mWorldBuildingId != buildingid)
|
|
continue;
|
|
DEBUG_LOG(m_logger) << "addDeviceToBuilding 1";
|
|
|
|
Device *device = new Device();
|
|
device->mWorldPlayerId = iconmainid;
|
|
device->mPath = iconpath;
|
|
device->mPosition = pos;
|
|
building->mDevices.push_back(device);
|
|
|
|
DEBUG_LOG(m_logger) << "building->mDisplays.size=" << building->mDisplays.size();
|
|
for (BuildingDisplay &dspl : building->mDisplays)
|
|
{
|
|
DEBUG_LOG(m_logger) << "addDeviceToBuilding 2";
|
|
DeviceDisplay dd;
|
|
dd.mDevice = device;
|
|
dd.mWorldPlayerId = iconmainid;
|
|
dspl.mDeviceDisplays.push_back(std::move(dd));
|
|
updateDevices(*building, dspl);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(dspl.mContextId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::removeDeviceFromBuilding(dtEntity::EntityId iconmainid)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
std::vector<Device *>::iterator j = building->mDevices.begin();
|
|
while (j != building->mDevices.end())
|
|
{
|
|
Device *device = *j;
|
|
if (device->mWorldPlayerId == iconmainid)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
std::vector<DeviceDisplay>::iterator l = bd.mDeviceDisplays.begin();
|
|
while (l != bd.mDeviceDisplays.end())
|
|
{
|
|
DeviceDisplay &pd = *l;
|
|
if (pd.mDevice->mWorldPlayerId == iconmainid)
|
|
{
|
|
dtEntity::MapSystem *ms;
|
|
mEntityManager->GetES(ms);
|
|
if (ms)
|
|
ms->RemoveFromScene(pd.mLocalPlayerId);
|
|
mEntityManager->KillEntity(pd.mLocalPlayerId);
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
l = bd.mDeviceDisplays.erase(l);
|
|
}
|
|
else
|
|
++l;
|
|
}
|
|
}
|
|
j = building->mDevices.erase(j);
|
|
delete device;
|
|
}
|
|
else
|
|
++j;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// helper function for handling XML
|
|
template <class T>
|
|
bool fetchAttr(T &t, const rapidxml::xml_node<> *node, const char *name)
|
|
{
|
|
using namespace rapidxml;
|
|
for (xml_attribute<> *attr = node->first_attribute(); attr; attr = attr->next_attribute())
|
|
{
|
|
if (strcmp(attr->name(), name) == 0)
|
|
{
|
|
std::istringstream iss(attr->value());
|
|
return !(iss >> std::dec >> t).fail();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// helper function for handling XML
|
|
static bool HasTagName(const rapidxml::xml_node<> *node, const char *name)
|
|
{
|
|
return (node->type() == rapidxml::node_element && strcmp(name, node->name()) == 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
bool BuildingManager::getRoomBounds(const std::string &bldgname, const std::string &roomname, VCtrl::OBB &obb) const
|
|
{
|
|
const std::string key = bldgname + " " + roomname;
|
|
auto i = mRooms.find(key);
|
|
if (i == mRooms.end() || !i->second.mBB.valid())
|
|
{
|
|
for (const auto &room : mRooms)
|
|
{
|
|
const osg::BoundingBox &bb = room.second.mBB;
|
|
QByteArray ba("id: ");
|
|
ba += room.first.c_str();
|
|
ba += ", min: " +
|
|
QByteArray::number(bb.xMin()) + ", " +
|
|
QByteArray::number(bb.yMin()) + ", " +
|
|
QByteArray::number(bb.zMin());
|
|
ba += ", max: " +
|
|
QByteArray::number(bb.xMax()) + ", " +
|
|
QByteArray::number(bb.yMax()) + ", " +
|
|
QByteArray::number(bb.zMax());
|
|
#ifdef LTS_DEBUG
|
|
LOG_ERROR(ba.data());
|
|
#endif
|
|
}
|
|
LOG_ERROR("Could not find room " << bldgname << "-" << roomname << ", #mRooms: " << mRooms.size());
|
|
return false;
|
|
}
|
|
obb = i->second;
|
|
if (!obb.mBB.valid())
|
|
{
|
|
LOG_ERROR("Room" << bldgname << "-" << roomname << " has invalid bounds");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
static void readBBoxMin(const rapidxml::xml_node<> *roomnode, VCtrl::OBB &room)
|
|
{
|
|
if (HasTagName(roomnode, "BBox_Min"))
|
|
{
|
|
fetchAttr(room.mBB._min[0], roomnode, "X");
|
|
fetchAttr(room.mBB._min[1], roomnode, "Y");
|
|
fetchAttr(room.mBB._min[2], roomnode, "Z");
|
|
}
|
|
}
|
|
static void readBBoxMax(const rapidxml::xml_node<> *roomnode, VCtrl::OBB &room)
|
|
{
|
|
if (HasTagName(roomnode, "BBox_Max"))
|
|
{
|
|
fetchAttr(room.mBB._max[0], roomnode, "X");
|
|
fetchAttr(room.mBB._max[1], roomnode, "Y");
|
|
fetchAttr(room.mBB._max[2], roomnode, "Z");
|
|
}
|
|
}
|
|
|
|
static void readPolygon(const rapidxml::xml_node<> *roomnode, VCtrl::OBB &room)
|
|
{
|
|
if (HasTagName(roomnode, "Group"))
|
|
{
|
|
for (auto grp0node(roomnode->first_node()); grp0node != nullptr; grp0node = grp0node->next_sibling())
|
|
{
|
|
|
|
if (HasTagName(grp0node, "Polygon"))
|
|
{
|
|
for (auto grp1node(grp0node->first_node()); grp1node != nullptr; grp1node = grp1node->next_sibling())
|
|
{
|
|
if (HasTagName(grp1node, "Vertex"))
|
|
{
|
|
for (auto grp2node(grp1node->first_node()); grp2node != nullptr; grp2node = grp2node->next_sibling())
|
|
{
|
|
if (HasTagName(grp2node, "Coord"))
|
|
{
|
|
double x,y;
|
|
fetchAttr(x, grp2node, "X");
|
|
fetchAttr(y, grp2node, "Y");
|
|
room.mPoly.append(QPointF(x,y));
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool BuildingManager::AddRoomOBBs(const BuildingData &b)
|
|
{
|
|
LOG_DEBUG("AddRoomOBBs: " + b.mFileName);
|
|
|
|
if (b.mBuildingXMLPath.empty())
|
|
{
|
|
LOG_WARNING("Buildings xml is not set: " + b.mFileName);
|
|
return false;
|
|
}
|
|
|
|
const std::string xmlpath = b.mBuildingXMLPath;
|
|
|
|
using namespace rapidxml;
|
|
const std::string absPath = dtEntity::GetSystemInterface()->FindDataFile(xmlpath);
|
|
if (absPath.empty())
|
|
{
|
|
LOG_ERROR("Map not found: " + absPath);
|
|
return false;
|
|
}
|
|
|
|
file<> file(absPath.c_str());
|
|
|
|
try
|
|
{
|
|
xml_document<> doc; // character type defaults to char
|
|
doc.parse<0>(file.data());
|
|
|
|
xml_node<> *rootnode = doc.first_node("STREIF");
|
|
if (rootnode == nullptr)
|
|
{
|
|
LOG_ERROR("Could not parse building xml!");
|
|
return false;
|
|
}
|
|
|
|
int floorNumber = -999;
|
|
std::map<int, int> roomToFloor;
|
|
|
|
for (xml_node<> *hdrNode(rootnode->first_node()); hdrNode != nullptr; hdrNode = hdrNode->next_sibling())
|
|
{
|
|
if (HasTagName(hdrNode, "Header"))
|
|
{
|
|
for (xml_node<> *grp1Node(hdrNode->first_node()); grp1Node != nullptr; grp1Node = grp1Node->next_sibling())
|
|
{
|
|
if (HasTagName(grp1Node, "Group"))
|
|
{
|
|
for (xml_node<> *grp2Node(grp1Node->first_node()); grp2Node != nullptr; grp2Node = grp2Node->next_sibling())
|
|
{
|
|
if (HasTagName(grp2Node, "Group"))
|
|
{
|
|
for (xml_node<> *swtchNode(grp2Node->first_node()); swtchNode != nullptr; swtchNode = swtchNode->next_sibling())
|
|
{
|
|
std::string temp;
|
|
if (HasTagName(swtchNode, "Name"))
|
|
{
|
|
temp = swtchNode->value();
|
|
// floor_
|
|
if (temp.substr(0,6).compare("floor_") == 0)
|
|
{
|
|
bool bOk = false;
|
|
floorNumber = QString::fromStdString(temp.substr(6)).toInt(&bOk);
|
|
if (!bOk)
|
|
floorNumber = -999;
|
|
// ERROR_LOG(m_logger) << LOGFUNCTION << " floorName=" << floorNumber;
|
|
}
|
|
}
|
|
|
|
if (HasTagName(swtchNode, "Switch"))
|
|
{
|
|
VCtrl::OBB room;
|
|
room.mMatrix.setTrans(b.mX, b.mY, b.mZ);
|
|
osg::Quat q;
|
|
q.makeRotate(-b.mOrientation / 180.0 * osg::PI, osg::Vec3(0, 0, 1));
|
|
room.mMatrix.setRotate(q);
|
|
room.mMatrixInverse.invert(room.mMatrix);
|
|
std::string name;
|
|
for (xml_node<> *roomnode(swtchNode->first_node()); roomnode != nullptr; roomnode = roomnode->next_sibling())
|
|
{
|
|
int roomNumber = -999;
|
|
if (HasTagName(roomnode, "Name"))
|
|
{
|
|
temp = roomnode->value();
|
|
// floor_
|
|
if (temp.substr(0,8).compare("SW_room_") == 0)
|
|
{
|
|
bool bOk = false;
|
|
roomNumber = QString::fromStdString(temp.substr(8)).toInt(&bOk);
|
|
if (!bOk)
|
|
roomNumber = -999;
|
|
// ERROR_LOG(m_logger) << LOGFUNCTION << " roomName= " << roomNumber;
|
|
// ERROR_LOG(m_logger) << LOGFUNCTION << " Bldg=" << b.mFeatureId << "Floor=" << floorNumber << " Room=" << roomNumber;
|
|
|
|
if (roomNumber>=0)
|
|
roomToFloor[roomNumber+2000]=floorNumber;
|
|
}
|
|
}
|
|
|
|
if (HasTagName(roomnode, "SubId"))
|
|
{
|
|
for (xml_attribute<> *attr = roomnode->first_attribute(); attr; attr = attr->next_attribute())
|
|
{
|
|
if (strcmp(attr->name(), "ID") == 0)
|
|
name = attr->value();
|
|
}
|
|
}
|
|
if (name.empty())
|
|
continue;
|
|
readBBoxMin(roomnode, room);
|
|
readBBoxMax(roomnode, room);
|
|
}
|
|
|
|
// LOG_ERROR("BBox111 room" << name << " in xml " << xmlpath << " - "
|
|
// << " minX " << room.mBB._min.x() << " minY " << room.mBB._min.y()
|
|
// << " maxX " << room.mBB._max.x() << " minY " << room.mBB._max.y()
|
|
// );
|
|
|
|
|
|
// no bbox found? check for new xml structure
|
|
if (!room.mBB.valid())
|
|
{
|
|
for (auto roomnode(swtchNode->first_node()); roomnode != nullptr; roomnode = roomnode->next_sibling())
|
|
{
|
|
if (HasTagName(roomnode, "Group"))
|
|
{
|
|
for (auto grp3node(roomnode->first_node()); grp3node != nullptr; grp3node = grp3node->next_sibling())
|
|
{
|
|
readBBoxMin(grp3node, room);
|
|
readBBoxMax(grp3node, room);
|
|
readPolygon(grp3node, room);
|
|
}
|
|
if (room.mBB.valid() && !room.mPoly.empty())
|
|
{
|
|
// LOG_ERROR("BBox222 room" << name << " in xml " << xmlpath << " - "
|
|
// << " minX " << room.mBB._min.x() << " minY " << room.mBB._min.y()
|
|
// << " maxX " << room.mBB._max.x() << " minY " << room.mBB._max.y()
|
|
// );
|
|
break; // short circuit
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!room.mBB.valid())
|
|
LOG_ERROR("Could not parse room bounding boxes for room" << name << " in xml " << xmlpath);
|
|
|
|
room.mBB._min[2] -= ROOM_OBB_Z_MIN_SUBTRACT; // 0.1f
|
|
room.mBB._max[2] -= ROOM_OBB_Z_MAX_SUBTRACT; // 0.5f
|
|
|
|
// GUEZE-605 / GUEZE-668
|
|
// U_Bahn-Tunnel: Roomnames and player were not shown
|
|
// Due to ROOM_OBB_Z_.._SUBTRACT the bb became invalid. Skip in that cases
|
|
if (!room.mBB.valid())
|
|
{
|
|
// Subtract from room OBB height so that only room navmesh cells are in obb
|
|
LOG_ERROR("Subtract from room OBB height fails, revert... room=" << name);
|
|
room.mBB._min[2] += ROOM_OBB_Z_MIN_SUBTRACT; // 0.1f
|
|
room.mBB._max[2] += ROOM_OBB_Z_MAX_SUBTRACT; // 0.5f
|
|
}
|
|
|
|
if (!room.mBB.valid())
|
|
LOG_ERROR("Could not parse room bounding boxes for room " << name << " in xml " << xmlpath);
|
|
|
|
const std::string key = b.mFeatureId + " " + name;
|
|
room.mBuilding = dtEntity::SID(b.mFeatureId);
|
|
mRooms[key] = room;
|
|
|
|
dtEntity::GetDebugDrawInterface()->AddOBB(room.mMatrix, room.mBB._min, room.mBB._max, osg::Vec4(1, 0, 1, 1), 1, FLT_MAX, false);
|
|
osg::Vec3 pos = room.mBB.center() * room.mMatrix;
|
|
dtEntity::GetDebugDrawInterface()->AddString(pos, key, osg::Vec4(0, 1, 0, 1), FLT_MAX, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
mRoomToFloorPerBldg[b.mFeatureId] = roomToFloor;
|
|
|
|
}
|
|
catch (const std::exception &ex)
|
|
{
|
|
LOG_ERROR("XML Parsing error: " + std::string(ex.what()));
|
|
return false;
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BuildingManager::LoadBuildings(const std::string &path, std::vector<BuildingData> &buildings)
|
|
{
|
|
using namespace rapidxml;
|
|
const std::string absPath = dtEntity::GetSystemInterface()->FindDataFile(path);
|
|
if (absPath.empty())
|
|
{
|
|
LOG_ERROR("Map not found: " + absPath);
|
|
return false;
|
|
}
|
|
|
|
file<> file(absPath.c_str());
|
|
|
|
try
|
|
{
|
|
xml_document<> doc; // character type defaults to char
|
|
doc.parse<0>(file.data());
|
|
|
|
xml_node<> *rootnode = doc.first_node("MetaData");
|
|
if (rootnode == nullptr)
|
|
{
|
|
LOG_ERROR("Could not parse map xml!");
|
|
return false;
|
|
}
|
|
|
|
for (xml_node<> *tagNode(rootnode->first_node()); tagNode != nullptr; tagNode = tagNode->next_sibling())
|
|
{
|
|
if (HasTagName(tagNode, "Tag"))
|
|
{
|
|
int topmesh = -1;
|
|
for (xml_node<> *groupNode(tagNode->first_node()); groupNode != nullptr; groupNode = groupNode->next_sibling())
|
|
{
|
|
if (HasTagName(groupNode, "Group"))
|
|
{
|
|
++topmesh;
|
|
for (xml_node<> *modelNode(groupNode->first_node()); modelNode != nullptr; modelNode = modelNode->next_sibling())
|
|
{
|
|
if (HasTagName(modelNode, "Model"))
|
|
{
|
|
BuildingData b;
|
|
|
|
for (xml_node<> *dataNode(modelNode->first_node()); dataNode != nullptr; dataNode = dataNode->next_sibling())
|
|
{
|
|
if (HasTagName(dataNode, "Orientation"))
|
|
fetchAttr(b.mOrientation, dataNode, "Angle");
|
|
else if (HasTagName(dataNode, "Position"))
|
|
{
|
|
fetchAttr(b.mX, dataNode, "X");
|
|
fetchAttr(b.mY, dataNode, "Y");
|
|
fetchAttr(b.mZ, dataNode, "Z");
|
|
}
|
|
else if (HasTagName(dataNode, "Description"))
|
|
fetchAttr(b.mDescription, dataNode, "Name");
|
|
else if (HasTagName(dataNode, "Feature"))
|
|
fetchAttr(b.mFeatureId, dataNode, "Id");
|
|
else if (HasTagName(dataNode, "File"))
|
|
fetchAttr(b.mFileName, dataNode, "Name");
|
|
else if (HasTagName(dataNode, "STREIF"))
|
|
fetchAttr(b.mBuildingXMLPath, dataNode, "Name");
|
|
}
|
|
b.mBuildingGroup = topmesh;
|
|
LOG_INFO("add building " + b.mFeatureId + " - " + b.mFileName);
|
|
buildings.push_back(std::move(b));
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (const std::exception &ex)
|
|
{
|
|
LOG_ERROR("XML Parsing error: " + std::string(ex.what()));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
size_t BuildingManager::getNumBuildings() const
|
|
{
|
|
return mBuildings.size();
|
|
}
|
|
|
|
|
|
void BuildingManager::getBuildingIds(std::vector<dtEntity::EntityId> &toFill) const
|
|
{
|
|
toFill.reserve(mBuildings.size());
|
|
for (const Building *building : mBuildings)
|
|
toFill.push_back(building->mWorldBuildingId);
|
|
}
|
|
|
|
dtEntity::EntityId BuildingManager::getNextBuilding(const osg::Vec3d &pos, float &distance, std::string &featureId) const
|
|
{
|
|
const osg::Vec2d pos2d(pos[0], pos[1]);
|
|
float minDist = 1000000.0f;
|
|
dtEntity::EntityId eid = -1;
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
const osg::Vec3d currentPos = osg::Vec3d(0, 0, 0) * building->mLocalToWorld;
|
|
const osg::Vec2d currentPos2d(currentPos[0], currentPos[1]);
|
|
float dist = (currentPos2d - pos2d).length();
|
|
if (dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
eid = building->mWorldBuildingId;
|
|
featureId = building->mFeatureId;
|
|
}
|
|
}
|
|
distance = minDist;
|
|
return eid;
|
|
}
|
|
|
|
Building BuildingManager::getBuildingFromFeatureId(const std::string &bldname) const
|
|
{
|
|
Building bld;
|
|
bld.mWorldBuildingId = 0;
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
if (building->mFeatureId == bldname)
|
|
{
|
|
bld.mBuildingDisplayName = building->mBuildingDisplayName;
|
|
bld.mFeatureId = building->mFeatureId;
|
|
bld.mWorldBuildingId = building->mWorldBuildingId;
|
|
}
|
|
}
|
|
return bld;
|
|
|
|
}
|
|
void BuildingManager::updateNames(const Building& bd, BuildingDisplay& dspl)
|
|
{
|
|
for (NameDisplay& ddspl : dspl.mNameDisplays)
|
|
{
|
|
TextComponent *name;
|
|
if (ddspl.mLocalPlayerId == 0)
|
|
{
|
|
dtEntity::Entity* e;
|
|
if (!mEntityManager->CreateEntity(e))
|
|
continue;
|
|
ddspl.mLocalPlayerId = e->GetId();
|
|
|
|
dtEntity::MapComponent* mc;
|
|
if (!e->CreateComponent(mc))
|
|
continue;
|
|
std::string en = "ctx_" + std::to_string(dspl.mContextId) +
|
|
"_nam_" + std::to_string(ddspl.mName->mWorldPlayerId);
|
|
mc->SetEntityName(en);
|
|
mc->SetUniqueId(en);
|
|
mc->SetMapName("nameproxies");
|
|
|
|
if (!e->CreateComponent(name))
|
|
continue;
|
|
name->SetText(ddspl.mName->mtext);
|
|
name->SetDisText(ddspl.mName->mdistext);
|
|
|
|
dtEntityOSG::LayerComponent* lc;
|
|
if (!e->CreateComponent(lc))
|
|
continue;
|
|
std::string viewname = "Context_" + std::to_string(dspl.mContextId);
|
|
lc->SetAttachedComponent(TextComponent::TYPE);
|
|
lc->SetLayer(dtEntity::SID(viewname));
|
|
|
|
dtEntity::MapSystem* ms;
|
|
if (mEntityManager->GetES(ms))
|
|
ms->AddToScene(e->GetId());
|
|
}
|
|
else
|
|
{
|
|
if (!mEntityManager->GetComponent(ddspl.mLocalPlayerId, name))
|
|
{
|
|
assert(false);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
int roomNumber = -1;
|
|
{
|
|
bool bOk = false;
|
|
roomNumber = QString::fromStdString(ddspl.mName->mtext).toInt(&bOk);;
|
|
if (!bOk)
|
|
roomNumber = -1;
|
|
}
|
|
|
|
name->SetTranslation(remapPosition(bd, dspl, ddspl.mName->mPosition, roomNumber));
|
|
name->SetVisible(dspl.mNameMode);
|
|
name->SetDisText(ddspl.mName->mdistext);
|
|
name->Finished();
|
|
}
|
|
}
|
|
|
|
|
|
dtEntity::EntityId BuildingManager::getWorldNameIdFromLocalName(dtEntity::EntityId local, std::string &buildingName, std::string &room) const
|
|
{
|
|
for (const Building *building : mBuildings)
|
|
{
|
|
for (const BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (const NameDisplay &nd : bd.mNameDisplays)
|
|
{
|
|
if (nd.mLocalPlayerId == local)
|
|
{
|
|
buildingName = nd.mName->mbuilding;
|
|
room = nd.mName->mtext;
|
|
return nd.mWorldPlayerId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void BuildingManager::changeLineMode(unsigned int contextId, bool line)
|
|
{
|
|
mShotOverview = line;
|
|
bool bRequestRedraw = false;
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
if (bd.mContextId == contextId)
|
|
{
|
|
if (bd.mLineMode != line)
|
|
{
|
|
bd.mLineMode = line;
|
|
bRequestRedraw = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(contextId);
|
|
}
|
|
|
|
|
|
void BuildingManager::changeNameMode(unsigned int contextId, bool name)
|
|
{
|
|
bool bRequestRedraw = false;
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
if (bd.mContextId == contextId)
|
|
{
|
|
if (bd.mNameMode != name)
|
|
{
|
|
bd.mNameMode = name;
|
|
setShowHideDisplayNames(building->mWorldBuildingId, contextId, name);
|
|
bRequestRedraw = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(contextId);
|
|
}
|
|
|
|
void BuildingManager::setBuildingDisplayName(const std::string& featureId, dtEntity::EntityId eid, const std::string& strDisplayName)
|
|
{
|
|
m_mapBuildingDisplayNames[featureId] = strDisplayName;
|
|
|
|
// Building already opened?
|
|
if(eid > 0)
|
|
{
|
|
setBuildingDisplayName(eid, strDisplayName);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void BuildingManager::setBuildingDisplayName(dtEntity::EntityId eid, const std::string& strDisplayName)
|
|
{
|
|
// TODO: Set Building Name
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mWorldBuildingId != eid)
|
|
continue;
|
|
building->mBuildingDisplayName = strDisplayName;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void BuildingManager::setRoomDisplayName(const std::string& featureId, dtEntity::EntityId eid, const std::string& roomname, const std::string& strDisplayName)
|
|
{
|
|
m_mapBuildingRoomNames[featureId][roomname] = strDisplayName;
|
|
|
|
// Building already opened?
|
|
if (eid > 0)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mWorldBuildingId != eid)
|
|
continue;
|
|
setRoomDisplayName(building, roomname, strDisplayName);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void BuildingManager::setRoomDisplayName(Building *building, const std::string& roomname, const std::string& strDisplayName)
|
|
{
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
for (NameDisplay &nd : bd.mNameDisplays)
|
|
{
|
|
if (nd.mName->mtext == roomname)
|
|
{
|
|
nd.mName->mdistext = strDisplayName;
|
|
TextComponent* tc;
|
|
if (mEntityManager->GetComponent(nd.mLocalPlayerId, tc))
|
|
{
|
|
tc->SetDisText(strDisplayName);
|
|
tc->Finished();
|
|
}
|
|
// roomname must be unique, so we can stop here
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BuildingManager::setShowHideDisplayNames(dtEntity::EntityId eid, unsigned int contextId, bool show)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
if (building->mWorldBuildingId != eid)
|
|
continue;
|
|
for (BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
bool bRequestRedraw = false;
|
|
if ( (bd.mContextId == contextId) || (contextId == 9999) )
|
|
{
|
|
for (NameDisplay &nd : bd.mNameDisplays)
|
|
{
|
|
nd.visible = show;
|
|
TextComponent* tc;
|
|
if (mEntityManager->GetComponent(nd.mLocalPlayerId, tc))
|
|
{
|
|
tc->SetVisible(show);
|
|
bRequestRedraw = true;
|
|
}
|
|
}
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void BuildingManager::setShowDisplayNamesSelection(dtEntity::EntityId eid, bool show)
|
|
{
|
|
for (Building *building : mBuildings)
|
|
{
|
|
for (const BuildingDisplay &bd : building->mDisplays)
|
|
{
|
|
bool bRequestRedraw = false;
|
|
for (const NameDisplay &nd : bd.mNameDisplays)
|
|
{
|
|
if (nd.mWorldPlayerId == eid)
|
|
{
|
|
TextComponent* tc;
|
|
if (mEntityManager->GetComponent(nd.mLocalPlayerId, tc))
|
|
{
|
|
tc->SetShowSelection(show);
|
|
bRequestRedraw = true;
|
|
}
|
|
}
|
|
}
|
|
if (bRequestRedraw)
|
|
dtEntity::GetWindowInterface()->RequestRedraw(bd.mContextId);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void BuildingManager::createRoomNames(dtEntity::EntityId buildingid, Building& building)
|
|
{
|
|
RoomDestructionComponent* btc;
|
|
if (mEntityManager->GetComponent(buildingid, btc))
|
|
{
|
|
const RoomDestructionComponent::RoomDestructions& rc = btc->GetRoomDestructions();
|
|
for (const auto &i : rc)
|
|
{
|
|
const std::string &roomName = i.first;
|
|
VCtrl::OBB roomObb;
|
|
getRoomBounds(building.mNavMeshGrpName, roomName, roomObb);
|
|
|
|
osg::Vec3 posX = roomObb.mBB.center();
|
|
// wg. [GUEZE-726] wird der neue Anpassung zunächst deaktiviert, bis Klarheit in
|
|
// die flt.XML-Datei gekommen ist (undest_room vs. FOOTPRINT vs. polygon1 vs. polygon2 ...
|
|
// Es handelt sich um einen Flüchtigkeitsfehler bei bldg_1111. (fix: SPD-/Renoir r 4747)
|
|
// Daher wird "[GUEZE-609] Positionierung der Raumnamen" wieder aktiviert:
|
|
if (!roomObb.mPoly.isEmpty() && !roomObb.mPoly.containsPoint(QPointF(posX.x(), posX.y()), Qt::OddEvenFill))
|
|
{
|
|
// [GUEZE-609] Positionierung der Raumnamen
|
|
const QPointF qpfCenter(posX.x(), posX.y());
|
|
QPointF nearestVertex;
|
|
qreal distance = 999999999;
|
|
for (const QPointF &vertex : qAsConst(roomObb.mPoly))
|
|
{
|
|
// distance:
|
|
qreal dis = (vertex-qpfCenter).manhattanLength();
|
|
if (dis<distance)
|
|
{
|
|
distance = dis;
|
|
nearestVertex = vertex;
|
|
}
|
|
}
|
|
if (nearestVertex.isNull())
|
|
{
|
|
// something fails, use fallback
|
|
posX.x() = roomObb.mPoly.at(0).x();
|
|
posX.y() = roomObb.mPoly.at(0).y();
|
|
} else {
|
|
posX.x() = nearestVertex.x();
|
|
posX.y() = nearestVertex.y();
|
|
}
|
|
}
|
|
const osg::Vec3 pos = posX * roomObb.mMatrix;
|
|
// osg::Vec3 center3D = roomObb.mBB.center();
|
|
// center3D.z() = (roomObb.mBB.zMin() + center3D.z()) / 2.0;
|
|
// const osg::Vec3 pos = center3D * roomObb.mMatrix;
|
|
|
|
// create entity for display in world view
|
|
dtEntity::Entity* e;
|
|
if (!mEntityManager->CreateEntity(e))
|
|
continue;
|
|
|
|
// for bookkeeping
|
|
dtEntity::MapComponent* mc;
|
|
if (!e->CreateComponent(mc))
|
|
{
|
|
mEntityManager->KillEntity(e->GetId());
|
|
continue;
|
|
}
|
|
const std::string en = "bd_" + building.mNavMeshGrpName + "_rm_" + roomName;
|
|
mc->SetEntityName(en);
|
|
mc->SetUniqueId(en);
|
|
mc->SetMapName("roomlabel");
|
|
|
|
dtEntity::EntityId nameMainId = e->GetId();
|
|
Name* name = new Name();
|
|
name->mWorldPlayerId = nameMainId;
|
|
name->mtext = roomName;
|
|
name->mdistext = "";
|
|
name->mPosition = pos;
|
|
//name->SetColor(osg::Vec4(1,1,1,1));
|
|
name->mbuilding = building.mNavMeshGrpName;
|
|
building.mNames.push_back(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|