#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "viewerinterface.h" #include "cameraviewposition.h" #include "logger.h" namespace dtEntity { class EntityManager; } namespace VCtrl { class IconComponent; class TextComponent; class ViewWidget; //////////////////////////////////////////////////////////////////////////////// struct OBB { osg::Matrix mMatrix; osg::Matrix mMatrixInverse; osg::BoundingBox mBB; QPolygonF mPoly; dtEntity::StringId mBuilding = 0; }; //////////////////////////////////////////////////////////////////////////////// struct BuildingData { std::string mDescription; std::string mDisplayName; std::string mFeatureId; std::string mFileName; std::string mBuildingXMLPath; double mX = 0; double mY = 0; double mZ = 0; double mOrientation = 0; int mBuildingGroup = 0; bool properlySpawned = false; bool roomBBoxedLoaded = false; }; //////////////////////////////////////////////////////////////////////////////// struct BuildingLevel { // entity id of visible entity in building view dtEntity::EntityId mEntityId; // floorId of xml file (-1 for floor_-1; 2 for floor_2...) int mFloorId; // height of lowest walkable area in level above building origin float mHeightAboveGround; // transforms from building local space to level local space osg::Matrix mLocalToLevel; // bounding box of level in world space (untransformed by view mode) osg::BoundingBox mBounds; BuildingLevel(dtEntity::EntityId eid, int floorId, float h, const osg::BoundingBox &bb) : mEntityId(eid), mFloorId(floorId), mHeightAboveGround(h), mBounds(bb) { } }; //////////////////////////////////////////////////////////////////////////////// struct PlayerPosition { osg::Vec2d mPosition; dtEntity::EntityId mWorldPlayerId = 0; }; //////////////////////////////////////////////////////////////////////////////// struct PlayerDisplay { dtEntity::EntityId mWorldPlayerId = 0; dtEntity::EntityId mLocalPlayerId = 0; IconComponent *mIcon = nullptr; }; //////////////////////////////////////////////////////////////////////////////// struct Device { dtEntity::EntityId mWorldPlayerId = 0; std::string mPath; osg::Vec3d mPosition; }; //////////////////////////////////////////////////////////////////////////////// struct DeviceDisplay { Device *mDevice = nullptr; dtEntity::EntityId mWorldPlayerId = 0; dtEntity::EntityId mLocalPlayerId = 0; }; //////////////////////////////////////////////////////////////////////////////// struct Name { dtEntity::EntityId mWorldPlayerId; std::string mtext; std::string mdistext; std::string mbuilding; osg::Vec3d mPosition; }; //////////////////////////////////////////////////////////////////////////////// struct NameDisplay { Name* mName = nullptr; dtEntity::EntityId mWorldPlayerId = 0; dtEntity::EntityId mLocalPlayerId = 0; bool visible = false; }; //////////////////////////////////////////////////////////////////////////////// class Shot { public: Shot(const int32_t id, const osg::Vec3d& shooterPos, const osg::Vec3d& targetPos, int buildingIdSrc, int rommNumberSrc, int buildingIdDst, int rommNumberDst, int lineType, const osg::Vec4& color, unsigned int duration_s, unsigned int durationMax_s, double simTimeCreated) : mId(id) , mShooterPos(shooterPos) , mTargetPos(targetPos) , mBuildingIdSrc(buildingIdSrc) , mRoomNumberSrc(rommNumberSrc) , mBuildingIdDst(buildingIdDst) , mRoomNumberDst(rommNumberDst) , mLineType(lineType) , mColor(color) , mDuration_s(duration_s) , m_DurationMax_s(durationMax_s) , mSimTimeCreated(simTimeCreated) { } void setDisplayTime(unsigned int duration_s) { if(duration_s > m_DurationMax_s) m_DurationMax_s = duration_s; mDuration_s = duration_s; } double simTimeCreated() const { return mSimTimeCreated; } double displayTime() const { return mSimTimeCreated + mDuration_s; } double lifeTime() const { return mSimTimeCreated + (m_DurationMax_s*2); } const osg::Vec3d& getShooterPos() const { return mShooterPos; } const osg::Vec3d& getTargetPos() const { return mTargetPos; } int getBuildingIdSrc() const { return mBuildingIdSrc; } double getSimeTimeCreated() const { return mSimTimeCreated; } int getRoomNumberSrc() const { return mRoomNumberSrc; } int getBuildingIdDst() const { return mBuildingIdDst; } int getRoomNumberDst() const { return mRoomNumberDst; } int getDuration() const { return mDuration_s; } int getLineType() const { return mLineType; } const osg::Vec4& getColor() const { return mColor; } int32_t getId() const { return mId; } private: int32_t mId; osg::Vec3d mShooterPos; osg::Vec3d mTargetPos; int mBuildingIdSrc; int mRoomNumberSrc; int mBuildingIdDst; int mRoomNumberDst; int mLineType; osg::Vec4 mColor; unsigned int mDuration_s, m_DurationMax_s; double mSimTimeCreated; }; //////////////////////////////////////////////////////////////////////////////// struct ShotDisplay { Shot *mShot = nullptr; osg::ref_ptr mGeode; }; // fwd decl struct Building; //////////////////////////////////////////////////////////////////////////////// /// \brief The BuildingDisplay struct class OrthoMotionModelComponent; struct BuildingDisplay { // context id of this display unsigned int mContextId = 0; // local entity holding building data dtEntity::EntityId mAttachPointId = 0; // all levels in building std::vector mLevels; // combined bounding box of all levels of building without viewmode transformation osg::BoundingBox mWorldBounds; // combined bounding box of all levels of building with viewmode transformation osg::BoundingBox mLocalBounds; // entity id of camera entity dtEntity::EntityId mCameraId = 0; // entity id of orthomotionmodel entity dtEntity::EntityId mMotionModelId = 0; OrthoMotionModelComponent *pMotion = nullptr; // entity id of light source entity dtEntity::EntityId mLightId = 0; // display players as dots or as icons? PlayerDisplayMode mPlayerDisplayMode = PlayerDisplayMode::Icons; // how are the buildings projected? ViewMode mViewMode = ViewMode::ISOMETRIC; // all players currently displayed in this building std::vector mPlayers; // shoot lines currently displayed std::vector mShotDisplays; // all players currently displayed in this building std::vector mDeviceDisplays; // all names currently displayed in this building std::vector mNameDisplays; // should camera rotation be locked to global map rotation? bool mLockRotation = false; // are the roomNames shown? bool mNameMode = false; // how are the shoot Lines displayed? bool mLineMode = false; BuildingDisplay() = default; BuildingDisplay(unsigned int contextid, ViewMode vm) : mContextId(contextid) , mViewMode(vm) { } }; //////////////////////////////////////////////////////////////////////////////// struct Building { // building entity in world space dtEntity::EntityId mWorldBuildingId = 0; // all currently open displays of this building std::vector mDisplays; // transformation of building in world space osg::Matrix mWorldToLocal; // transformation of building in world space osg::Matrix mLocalToWorld; // used for assigning walking entities to buildings std::string mNavMeshGrpName; // stores shot data std::vector mShots; // stores device data std::vector mDevices; // Building Display Name std::string mBuildingDisplayName; // stores name data std::vector mNames; // the corresponding feature id from the xml file std::string mFeatureId; }; //////////////////////////////////////////////////////////////////////////////// class BuildingManager { public: explicit BuildingManager(dtEntity::EntityManager &em); ~BuildingManager(); void addBuilding(dtEntity::EntityId buildingid, const std::string &featureId); void deleteAllBuildings(); BuildingDisplay *getBuildingDisplay(unsigned int contextid); void applyViewModeToBuildingParts(const Building &bldg, BuildingDisplay &dspl) const; bool displayBuilding(const std::string& featureId, unsigned int contextid, dtEntity::EntityId buildingid, const osg::Vec4 &bgcolor, ViewMode viewmode, bool exactPos); bool displayBuilding(unsigned int contextid, dtEntity::EntityId buildingid, const osg::Vec4 &bgcolor, ViewMode viewmode, bool exactPos); bool setCameraPosition(unsigned int contextid, const BuildingViewer::CameraViewPosition& pos); bool getCameraPosition(unsigned int contextid, BuildingViewer::CameraViewPosition& pos); bool setDefaultCameraPosition(unsigned int contextid); void closeBuildingDisplay(unsigned int contextid); void changeViewMode(unsigned int contextId, ViewMode viewmode, bool useOriginViewPos = true); void changeLineMode(unsigned int contextId, bool line); void changeNameMode(unsigned int contextId, bool name); void applyMapRotation(const Building &bd, BuildingDisplay &dspl); void lockViewRotationToMapRotation(unsigned int contextId, bool lock); void setPlayerDisplayMode(unsigned int contextId, PlayerDisplayMode mode); void setWallTransparency(unsigned int contextId, float value); float getMapRotation() const; void setMapRotation(float angle); void openOverview(unsigned int contextid); void addPlayerToBuildings(const std::string &navmeshgrpname, dtEntity::EntityId eid, const osg::Vec4 &color, const std::string &symbol, const osg::Vec3d &pos, bool visible); void removePlayerFromBuilding(const std::string &navmeshgrpname, dtEntity::EntityId eid, const std::string &roomname); void updatePlayerPosition(const std::string &navmeshgrpname, dtEntity::EntityId eid, const osg::Vec3d &pos, int roomNumber); osg::Vec3d remapPosition(const Building &bd, const BuildingDisplay &dspl, const osg::Vec3d &world, int roomNumber = -1); void setPlayerColor(dtEntity::EntityId eid, const osg::Vec4 &color); void setPlayerIcon(dtEntity::EntityId eid, const std::string &path); void reloadPlayerIcons(); void updatePlayerPartyColor(dtEntity::EntityId eid, const VCtrl::Color& col); void setShowPlayerSelection(dtEntity::EntityId eid, bool show); void setShowDisplayNamesSelection(dtEntity::EntityId eid, bool show); void setShowHidePlayer(dtEntity::EntityId eid, bool show); void setShowHideDisplayNames(dtEntity::EntityId eid, unsigned int contextId, bool show); void setRoomDestructionValue(dtEntity::EntityId eid, const std::string &roomname, float value); void setBuildingDestructionValue(dtEntity::EntityId eid, float value); void setBuildingDisplayName(const std::string& featureId, dtEntity::EntityId eid, const std::string& strDisplayName); void setBuildingDisplayName(dtEntity::EntityId eid, const std::string& strDisplayName); void setRoomDisplayName(const std::string& featureId, dtEntity::EntityId eid, const std::string& roomname, const std::string& strDisplayName); void setRoomDisplayName(Building *building, const std::string &roomname, const std::string& strDisplayName); void removeShoot(int32_t id); void 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); dtEntity::EntityId getWorldPlayerIdFromLocalPlayer(dtEntity::EntityId local) const; dtEntity::EntityId getWorldNameIdFromLocalName(dtEntity::EntityId local, std::string &buildingName, std::string &room) const; void addDeviceToBuilding(dtEntity::EntityId iconmainid, dtEntity::EntityId buildingid, const osg::Vec3d &pos, const std::string &iconpath); void removeDeviceFromBuilding(dtEntity::EntityId iconmainid); // Load building XML and add room OBBs to tree bool AddRoomOBBs(const BuildingData &); const std::map &GetRoomOBBs() const { return mRooms; } // Look up room OBB, return true if room exists bool getRoomBounds(const std::string &bldgname, const std::string &roomname, VCtrl::OBB &obb) const; bool LoadBuildings(const std::string &path, std::vector &); size_t getNumBuildings() const; void getBuildingIds(std::vector &toFill) const; dtEntity::EntityId getNextBuilding(const osg::Vec3d &pos, float &distance, std::string &featureId) const; Building getBuildingFromFeatureId(const std::string &bldname) const; // all players currently in this room using RoomPlayers = std::vector; // add player to room osg::Vec2d AddRoomUsages(const std::string& bldgname, const std::string& roomname, VCtrl::PlayerPosition& playPos); const std::map &GetRoomUsages() const { return mUsedRooms; } // delete player in room void deleteRoomUsagePlayer(const std::string& bldgname, const std::string& roomname, dtEntity::EntityId playerId); void SetExactPos(bool exactPos) { mExactPos = exactPos; } bool GetExactPos() const { return mExactPos; } void updateShotDuration(unsigned int newDuration_s); using CallbackCamPosChanged = std::function; void setCallbackCamPosChanged(const CallbackCamPosChanged &cb); private: void updateShots(const Building &bd, BuildingDisplay &dspl); void updateDevices(const Building &bd, BuildingDisplay &dspl); void createRoomNames(dtEntity::EntityId buildingid, Building& building); void updateNames(const Building& bd, BuildingDisplay& dspl); void repositionCamera(const Building &bd, const BuildingDisplay &dspl, bool useOriginViewPos = true); void updatePlayerPositions(const Building &bd, BuildingDisplay &dspl); void addPlayerToBuilding(const Building &bd, BuildingDisplay &dspl, dtEntity::EntityId eid, const osg::Vec4 &color, const std::string &symbol, const osg::Vec3d &pos, bool visible); static osg::Vec2d shiftPosition(const VCtrl::OBB& obb, const osg::Vec2d& pos, double& shiftValue); void cameraViewPositionChanged(unsigned int contextId, const BuildingViewer::CameraViewPosition &viewPos); std::set m_setInitialCameraPositionSet; // If an context ID of a building is included in this set the initial camera position had been set std::map> m_mapBuildingRoomNames; // Maps a building feature id (not the dtEntity::EntityId!) to the building's room names std::map m_mapBuildingDisplayNames; // key = feature id value = BuildingDisplayName dtEntity::EntityManager *mEntityManager; std::vector mBuildings; QMutex m_mutexShots; bool mShotOverview; bool mExactPos; float mMapRotation; dtEntity::MessageFunctor mTickFunctor; void Tick(const dtEntity::Message &message); std::map mRooms; std::map mUsedRooms; CallbackCamPosChanged mCbCamPosChanged; // NLDEVCTRL-495 // Die Positionierung der a) TeilnehmerSymbole, b) RaumBezeichner und c) Trefferlinien der Kanalisation ist problembehaftet. // Bei Raum 027 und 028 der Kanalisation wurde der RaumBezeichner nicht im unteren Level, sondern im darüberliegenden Level dargestellt. // Level entspricht den floors/Ebenen in der Standard-Darstellung isometric, also in "gespreizter" Darstellung. // Als Ursache hat sich Ansatz in BuildingManager::remapPosition() herausgestellt. Beim Remapping wird versucht, die aktuelle Position aufgrund des z-Wertes einem Floor/Level zuzuordnen. Wenn die Gebäude waagerechte Floors haben, funktioniert dies sehr gut. // Die Kanalisation weist aber im linken Bereich (Raum 027 und 028) einen Anstieg auf. Betritt also ein Teilnehmer einen der Räume, so wird aufgrund seines z-Wertes die darüberliegenden Etage ermittelt und der Tln "zu hoch" angezeigt. // Lösung: // Beim Einlesen der Struktur-XML-Datei wird ein Lookup-Table erstellt. mRoomToFloorPerBldg stellt dann zu jedem Raum den Floor zur Verfügung. // Bei Positionsmeldungen wird Bldg/Room durchgereicht, sodass es beim Remapping einbezogen werden kann. // Bei der Darstellung der RaumBezeichner verhält es sich analog. // Bei den Trefferlinien beinhaltet das DDS-Topic HitLineInfo den Information Bldg/Room nur für den Getroffenen. Daher wird die Peilspitze der Trefferlinien korrekt dargestellt. // ToDo: // Der Ursprung der Trefferlinien wird nach wie vor durch Analyse des z-Wertes vorgenommen -> Probleme bei Raum 027, 028. // Wahrscheinlich müsst im SVC PPM (ParticipantHandlerForExercise::createHitlineInfo) nixcht nur die OriginatorPosition, sondern ggf. auch Bldg/Room in das DDS-Topic HitLineInfo eingetragen werden. // Wahrscheinlich wegen dem Replay eine DB-Änderung notwendig. bool getFloorOfRoom(const std::string &bdlgFeatureId, int roomNumber, int &floorOut) const; // // std::map > mRoomToFloorPerBldg; NGL::INGLLogger &m_logger; }; }