Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,482 @@
#pragma once
#include <dtEntity/entityid.h>
#include <osg/BoundingBox>
#include <string>
#include <vector>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Matrix>
#include <osg/Geode>
#include <dtEntity/message.h>
#include <QMutex>
#include <QMutexLocker>
#include <QPolygonF>
#include <set>
#include <map>
#include <functional>
#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<osg::Geode> 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<BuildingLevel> 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<PlayerDisplay> mPlayers;
// shoot lines currently displayed
std::vector<ShotDisplay> mShotDisplays;
// all players currently displayed in this building
std::vector<DeviceDisplay> mDeviceDisplays;
// all names currently displayed in this building
std::vector<NameDisplay> 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<BuildingDisplay> 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<Shot *> mShots;
// stores device data
std::vector<Device *> mDevices;
// Building Display Name
std::string mBuildingDisplayName;
// stores name data
std::vector<Name*> 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<std::string, VCtrl::OBB> &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<BuildingData> &);
size_t getNumBuildings() const;
void getBuildingIds(std::vector<dtEntity::EntityId> &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<PlayerPosition>;
// add player to room
osg::Vec2d AddRoomUsages(const std::string& bldgname, const std::string& roomname, VCtrl::PlayerPosition& playPos);
const std::map<std::string, RoomPlayers> &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(unsigned int, const BuildingViewer::CameraViewPosition &)>;
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<unsigned int> m_setInitialCameraPositionSet; // If an context ID of a building is included in this set the initial camera position had been set
std::map<std::string, std::map<std::string, std::string>> m_mapBuildingRoomNames; // Maps a building feature id (not the dtEntity::EntityId!) to the building's room names
std::map<std::string, std::string> m_mapBuildingDisplayNames; // key = feature id value = BuildingDisplayName
dtEntity::EntityManager *mEntityManager;
std::vector<Building *> mBuildings;
QMutex m_mutexShots;
bool mShotOverview;
bool mExactPos;
float mMapRotation;
dtEntity::MessageFunctor mTickFunctor;
void Tick(const dtEntity::Message &message);
std::map<std::string, VCtrl::OBB> mRooms;
std::map<std::string, RoomPlayers> 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;
// <bldg , <roomNumber, floor>
// <featureId, <roomNumber, floor>
std::map<std::string, std::map<int,int> > mRoomToFloorPerBldg;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,17 @@
#pragma once
namespace BuildingViewer
{
struct CameraViewPosition
{
CameraViewPosition() = default;
CameraViewPosition(double left, double right, double bottom, double top)
: m_left(left), m_right(right), m_bottom(bottom), m_top(top)
{}
double m_left = 0;
double m_right = 0;
double m_bottom = 0;
double m_top = 0;
};
}
@@ -0,0 +1,24 @@
#pragma once
#if defined VIEWER_CTRL_LIBRARY_STATIC
# define VIEWER_CTRL_EXPORT
#else
# if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__)
# ifdef VIEWER_CTRL_LIBRARY
# define VIEWER_CTRL_EXPORT __declspec(dllexport)
# else
# define VIEWER_CTRL_EXPORT __declspec(dllimport)
# endif
# else
# ifdef VIEWER_CTRL_LIBRARY
# define VIEWER_CTRL_EXPORT __attribute__ ((visibility("default")))
# else
# define VIEWER_CTRL_EXPORT
# endif
# endif
#endif
#ifdef _WIN32
# pragma warning (disable: 4251)
# pragma warning(disable : 4355) // 'this' used in initializer list
#endif
@@ -0,0 +1,349 @@
#include "iconcomponent.h"
#include <dtEntity/nodemasks.h>
#include <osg/BlendFunc>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/LineWidth>
#include <osg/Node>
#include <osg/PolygonMode>
#include <osg/Texture2D>
#include <osgDB/ReadFile>
#include <sstream>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId IconComponent::TYPE(dtEntity::SID("Icon"));
const dtEntity::StringId IconComponent::PathId(dtEntity::SID("Path"));
const dtEntity::StringId IconComponent::VOffsetId(dtEntity::SID("VOffset"));
////////////////////////////////////////////////////////////////////////////////
IconComponent::IconComponent()
: dtEntityOSG::TransformComponent(new osg::AutoTransform())
, mPath(
dtEntity::DynamicStringProperty::SetValueCB(this, &IconComponent::SetPath),
dtEntity:: DynamicStringProperty::GetValueCB(this, &IconComponent::GetPath)
)
, mVOffset(
dtEntity::DynamicFloatProperty::SetValueCB(this, &IconComponent::SetVOffset),
dtEntity:: DynamicFloatProperty::GetValueCB(this, &IconComponent::GetVOffset)
)
{
Register(PathId, &mPath);
Register(VOffsetId, &mVOffset);
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
tr->setName("icon");
tr->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
tr->setAutoScaleToScreen(true);
tr->setNodeMask(dtEntity::NodeMasks::PICKABLE | dtEntity::NodeMasks::VISIBLE);
tr->setNormal(osg::Vec3(0, 1, 0));
osg::StateSet *ss = tr->getOrCreateStateSet();
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
ss->setRenderBinDetails(90, "DepthSortedBin");
ss->setMode(GL_BLEND, osg::StateAttribute::ON);
ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
osg::ref_ptr<osg::LineWidth> lw = new osg::LineWidth();
lw->setWidth(2);
ss->setAttributeAndModes(lw, osg::StateAttribute::ON);
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::Rebuild()
{
#define DOT_RADIUS 5
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
tr->dirtyBound();
tr->setInitialBound(osg::BoundingSphere(osg::Vec3(), 10));
tr->removeChildren(0, tr->getNumChildren());
if (!mVisible) return;
osg::ref_ptr<osg::Geode> g = new osg::Geode();
tr->addChild(g);
tr->setInitialBound(osg::BoundingSphere(osg::Vec3(), 1));
int x, y, w, h;
if (mShowDot)
{
x = y = -DOT_RADIUS * 2;
w = h = DOT_RADIUS * 4;
osg::ref_ptr<osg::Geometry> circle = new osg::Geometry();
osg::Vec4Array *colours = new osg::Vec4Array(1);
(*colours)[0] = mColor;
circle->setColorArray(colours);
circle->setColorBinding(osg::Geometry::BIND_OVERALL);
const unsigned int n_points = 16;
osg::Vec3Array *coords = new osg::Vec3Array(n_points + 2);
(*coords)[0] = osg::Vec3(0, 0, 0);
const double dx = 2.0 * osg::PI / n_points;
for (unsigned int j = 1; j < n_points + 2; ++j)
(*coords)[j].set(osg::Vec3(cos(dx * j) * DOT_RADIUS, sin(dx * j) * DOT_RADIUS, 0));
circle->setVertexArray(coords);
circle->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_FAN, 0, n_points + 2));
g->addDrawable(circle);
}
else
{
osg::ref_ptr<osg::Image> img = osgDB::readImageFile(mPathVal);
if (img.valid())
{
int b = 4;
g->addDrawable(IconSystem::CreateSquare(img->s(), img->t(), mVOffsetVal, mOriginAtBottom, img));
if (mOriginAtBottom)
{
x = -img->s() / 2 - b;
y = 0 - b;
w = img->s() + b * 2;
h = img->t() + b * 2;
}
else
{
x = -img->s() / 2 - b;
y = -img->t() / 2 - b;
w = img->s() + b * 2;
h = img->t() + b * 2;
}
}
else
{
LOG_ERROR("Could not read symbol from path '" << mPathVal<< "'");
return;
}
}
if (mSelected)
{
osg::ref_ptr<osg::Geometry> sel = new osg::Geometry();
g->addDrawable(sel);
osg::Vec4Array *colours = new osg::Vec4Array(1);
(*colours)[0] = osg::Vec4(1, 0, 0, 1);
sel->setColorArray(colours);
sel->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::Vec3Array *coords = new osg::Vec3Array(4);
(*coords)[0] = osg::Vec3(x , y , 0);
(*coords)[1] = osg::Vec3(x , y + h, 0);
(*coords)[2] = osg::Vec3(x + w, y + h, 0);
(*coords)[3] = osg::Vec3(x + w, y , 0);
sel->setVertexArray(coords);
sel->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, 4));
osg::ref_ptr<osg::PolygonMode> p = new osg::PolygonMode;
p->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
sel->getOrCreateStateSet()->setAttribute(p);
}
}
////////////////////////////////////////////////////////////////////////////////
std::string IconComponent::GetPath() const
{
return mPathVal;
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetPath(const std::string &path)
{
mPathVal = path;
Rebuild();
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::Reload()
{
if(mPathVal.size())
{
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
float IconComponent::GetVOffset() const
{
return mVOffsetVal;
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetVOffset(float v)
{
if (mVOffsetVal != v)
{
mVOffsetVal = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Vec3d IconComponent::GetTranslation() const
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
return tr->getPosition();
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetTranslation(const dtEntity::Vec3d &v)
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
tr->setPosition(v);
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Vec3d IconComponent::GetScale() const
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
return tr->getScale();
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetScale(const dtEntity::Vec3d &v)
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
tr->setScale(v);
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Quat IconComponent::GetRotation() const
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
return tr->getRotation();
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetRotation(const dtEntity::Quat &v)
{
osg::AutoTransform *tr = static_cast<osg::AutoTransform *>(GetNode());
tr->setRotation(v);
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetColor(const osg::Vec4 &v)
{
if (mColor != v)
{
mColor = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetShowDot(bool v)
{
if (mShowDot != v)
{
mShowDot = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetOriginAtBottom(bool v)
{
if (mOriginAtBottom != v)
{
mOriginAtBottom = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
bool IconComponent::GetShowSelection() const
{
return mSelected;
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetShowSelection(bool v)
{
if (mSelected != v)
{
mSelected = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetVisible(bool v)
{
if (mVisible != v)
{
mVisible = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
void IconComponent::SetRoomNumber(int roomNumber)
{
mRoomNumber = roomNumber;
}
////////////////////////////////////////////////////////////////////////////
IconSystem::IconSystem(dtEntity::EntityManager &em)
: dtEntity::DefaultEntitySystem<IconComponent>(em, dtEntityOSG::TransformComponent::TYPE)
{
}
////////////////////////////////////////////////////////////////////////////
osg::Drawable *IconSystem::CreateSquare(float width, float height, float voffset, bool originAtBottom, osg::Image *image)
{
// set up the Geometry.
osg::Geometry *geom = new osg::Geometry;
osg::Vec3Array *coords = new osg::Vec3Array(4);
if (originAtBottom)
{
(*coords)[0] = osg::Vec3(-width / 2.0f, voffset, 0);
(*coords)[1] = osg::Vec3(width / 2.0f, voffset, 0);
(*coords)[2] = osg::Vec3(width / 2.0f, voffset + height, 0);
(*coords)[3] = osg::Vec3(-width / 2.0f, voffset + height, 0);
}
else
{
(*coords)[0] = osg::Vec3(-width / 2.0f, voffset - height / 2, 0);
(*coords)[1] = osg::Vec3(width / 2.0f, voffset - height / 2, 0);
(*coords)[2] = osg::Vec3(width / 2.0f, voffset + height / 2, 0);
(*coords)[3] = osg::Vec3(-width / 2.0f, voffset + height / 2, 0);
}
geom->setVertexArray(coords);
osg::Vec3Array *norms = new osg::Vec3Array(1);
(*norms)[0] = osg::Vec3(0, 1, 0);
geom->setNormalArray(norms);
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
osg::Vec4Array *colours = new osg::Vec4Array(1);
(*colours)[0] = osg::Vec4(1, 1, 1, 1);
geom->setColorArray(colours);
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::Vec2Array *tcoords = new osg::Vec2Array(4);
(*tcoords)[0].set(0.0f, 0.0f);
(*tcoords)[1].set(1.0f, 0.0f);
(*tcoords)[2].set(1.0f, 1.0f);
(*tcoords)[3].set(0.0f, 1.0f);
geom->setTexCoordArray(0, tcoords);
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
if (image)
{
osg::StateSet *stateset = geom->getOrCreateStateSet();
osg::Texture2D *texture = new osg::Texture2D;
texture->setResizeNonPowerOfTwoHint(false);
texture->setImage(image);
stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
}
return geom;
}
}
@@ -0,0 +1,100 @@
#pragma once
#include <dtEntity/component.h>
#include <dtEntity/entity.h>
#include <dtEntity/defaultentitysystem.h>
#include <dtEntityOSG/nodecomponent.h>
#include <osg/AutoTransform>
#include <dtEntity/dynamicproperty.h>
#include <dtEntityOSG/transformcomponent.h>
namespace VCtrl
{
class IconComponent : public dtEntityOSG::TransformComponent
{
public:
static const dtEntity::StringId TYPE;
static const dtEntity::StringId PathId;
static const dtEntity::StringId VOffsetId;
IconComponent();
dtEntity::ComponentType GetType() const override { return TYPE; }
bool IsInstanceOf(dtEntity::ComponentType id) const
{
return ((id == TYPE));
}
std::string GetPath() const;
void SetPath(const std::string &path);
void Reload();
float GetVOffset() const;
void SetVOffset(float v);
osg::Vec4 GetColor() const { return mColor; }
void SetColor(const osg::Vec4 &);
bool GetShowDot() const { return mShowDot; }
void SetShowDot(bool);
bool GetOriginAtBottom() const { return mOriginAtBottom; }
void SetOriginAtBottom(bool);
dtEntity::Vec3d GetTranslation() const override;
void SetTranslation(const dtEntity::Vec3d &) override;
dtEntity::Vec3d GetScale() const override;
void SetScale(const dtEntity::Vec3d &) override;
dtEntity::Quat GetRotation() const override;
void SetRotation(const dtEntity::Quat &) override;
bool GetShowSelection() const;
void SetShowSelection(bool v);
void SetVisible(bool v);
bool GetVisible() const { return mVisible; }
void SetRoomNumber(int roomNumber);
int GetRoomNumber() const { return mRoomNumber; }
private:
void Rebuild();
dtEntity::DynamicStringProperty mPath;
dtEntity::DynamicFloatProperty mVOffset;
std::string mPathVal;
osg::Vec4 mColor;
float mVOffsetVal = 0;
bool mShowDot = false;
bool mOriginAtBottom = false;
bool mSelected = false;
bool mVisible = false;
int mRoomNumber{-1};
};
///////////////////////////////////////////////
// iterates over MovementComponents and updates the translation of the entity
// after applying forces
class IconSystem final : public dtEntity::DefaultEntitySystem<IconComponent>
{
public:
explicit IconSystem(dtEntity::EntityManager &em);
static osg::Drawable *CreateSquare(float width, float height, float voffset, bool originAtBottom, osg::Image *image = nullptr);
};
}
@@ -0,0 +1,440 @@
#include "mainloop.h"
#include "iconcomponent.h"
#include "modelsplittercomponent.h"
#include "motionmodel.h"
#include "orthomotionmodel.h"
#include "playercomponent.h"
#include "roomdestructioncomponent.h"
#include "textcomponent.h"
#include "viewerinterfaceimpl.h"
#include <dtEntity/core.h>
#include <dtEntity/commandmessages.h>
#include <dtEntity/init.h>
#include <dtEntity/mapcomponent.h>
#include <dtEntity/profile.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/systeminterface.h>
#include <dtEntity/entitymanager.h>
#include <dtEntityOSG/initosgviewer.h>
#include <dtEntityOSG/layerattachpointcomponent.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/lightcomponent.h>
#include <dtEntityOSG/cameracomponent.h>
#include <dtEntityOSG/osgsysteminterface.h>
#include <dtEntityOSG/osgwindowinterface.h>
#include <dtEntityOSG/osgdebugdrawinterface.h>
#include <dtEntityOSG/osginputinterface.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <dtEntityOSG/staticmeshcomponent.h>
#include <osgDB/Registry>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#ifdef BUILD_WITH_GSTREAMER
#include "videocomponent.h"
#endif
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
class MyReadFileCallback : public osgDB::Registry::ReadFileCallback
{
public:
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string &fileName, const osgDB::ReaderWriter::Options *options)
{
osgDB::ReaderWriter::ReadResult res = osgDB::Registry::instance()->readNodeImplementation(fileName, options);
if (res.notFound() || res.notHandled() || res.error())
{
LOG_DEBUG("DatabasePager could not load file, stopped trying: " << fileName);
return osgDB::ReaderWriter::ReadResult(nullptr, osgDB::ReaderWriter::ReadResult::FILE_LOADED);
}
return res;
}
};
////////////////////////////////////////////////////////////////////////////////
class MainLoop::Impl
{
public:
osg::ref_ptr<osgViewer::CompositeViewer> mViewer;
CtrlImpl *mInterface = nullptr;
dtEntityOSG::OSGSystemInterface *mSysIf = nullptr;
dtEntityOSG::OSGInputInterface *mInputIf = nullptr;
dtEntity::EntityManager *mEntityManager;
osg::Timer_t mStartFrameTick = 0;
dtEntity::Timer_t mSimulationClockTime = 0;
bool mProfilingEnabled = false;
Impl()
: mEntityManager(new dtEntity::EntityManager)
{
dtEntity::MessageFunctor f(this, &MainLoop::Impl::onFastForward);
mEntityManager->RegisterForMessages(dtEntity::SID("FastForwardMessage"), f);
dtEntity::MessageFunctor s(this, &MainLoop::Impl::onEntitySelected);
mEntityManager->RegisterForMessages(dtEntity::RequestEntitySelectMessage::TYPE, s);
dtEntity::MessageFunctor s2(this, &MainLoop::Impl::onEntityDeselected);
mEntityManager->RegisterForMessages(dtEntity::RequestEntityDeselectMessage::TYPE, s2);
}
~Impl()
{
delete mEntityManager;
delete mSysIf;
delete mInputIf;
delete mInterface;
}
// react to fast forward message by
void onFastForward(const dtEntity::Message &msg)
{
// TODO Test!
double endtime = msg.GetDouble(dtEntity::SID("EndTime"));
while (mInterface->GetSimulationTime() < endtime)
{
constexpr auto step = 0.5;
double t = mInterface->GetSimulationTime() + step;
mSimulationClockTime += step / osg::Timer::instance()->getSecondsPerTick();
mInterface->SetSimulationTime(t);
mSysIf->SetTimeValues(t, step, step, mSimulationClockTime);
mViewer->advance(t);
mViewer->eventTraversal();
mSysIf->EmitTickMessagesAndQueuedMessages();
mViewer->updateTraversal();
mSysIf->EmitPostUpdateMessage();
}
}
// translate RequestEntitySelectMessage to EntityDeselectedMessage
// (normally this would be handled by a selection manager, but
// selection in this viewer is so simple that it is not necessary
// to have real selection management)
void onEntitySelected(const dtEntity::Message &m)
{
const dtEntity::RequestEntitySelectMessage &msg =
static_cast<const dtEntity::RequestEntitySelectMessage &>(m);
dtEntity::EntitySelectedMessage mo;
mo.SetAboutEntityId(msg.GetAboutEntityId());
mEntityManager->EmitMessage(mo);
}
// translate RequestEntityDeselectMessage to EntityDeselectedMessage
void onEntityDeselected(const dtEntity::Message &m)
{
const dtEntity::RequestEntityDeselectMessage &msg =
static_cast<const dtEntity::RequestEntityDeselectMessage &>(m);
dtEntity::EntityDeselectedMessage mo;
mo.SetAboutEntityId(msg.GetAboutEntityId());
mEntityManager->EmitMessage(mo);
}
};
////////////////////////////////////////////////////////////////////////////////
MainLoop::MainLoop(int argc, char **argv, QWidget *parentWidget)
: mImpl(new Impl)
{
osgDB::Registry::instance()->setReadFileCallback(new MyReadFileCallback());
assert(!mImpl->mViewer.valid());
//////////////////////////// Setup OSG Viewer /////////////////////////
// osg arguments parser wants to modify argc, argv
{
int argc_cpy = argc;
std::vector<char *> argv_cpy;
argv_cpy.reserve(argc);
for (int i = 0; i < argc; ++i)
argv_cpy.push_back(argv[i]);
osg::ArgumentParser args(&argc_cpy, argv_cpy.data());
#ifdef _MSC_VER
_putenv_s("OSG_RUN_FRAME_SCHEME", "ON_DEMAND");
#else
setenv("OSG_RUN_FRAME_SCHEME", "ON_DEMAND", 1);
#endif
// turn on antialiasing
osg::DisplaySettings::instance()->setNumMultiSamples(4);
osg::DisplaySettings::instance()->setDepthBuffer(true);
mImpl->mViewer = new osgViewer::CompositeViewer(args);
// Qt5 is currently crashing and reporting "Cannot make QOpenGLContext current in a different
// thread" when the viewer is run multi-threaded, this is regression from Qt4
mImpl->mViewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
// don't exit on escape
mImpl->mViewer->setKeyEventSetsDone(0);
//mImpl->mViewer->setEndBarrierPosition(osgViewer::ViewerBase::BeforeSwapBuffers);
#ifdef LTS_DEBUG
dtEntity::LogManager::GetInstance().AddListener(new dtEntity::ConsoleLogHandler());
#endif
}
//////////////////////// setup dtEntity -> OSG interfaces ////////////////////////
{
mImpl->mSysIf = new dtEntityOSG::OSGSystemInterface(mImpl->mEntityManager->GetMessagePump(), argc, (const char **)argv);
mImpl->mInputIf = new dtEntityOSG::OSGInputInterface(mImpl->mEntityManager->GetMessagePump());
// give application system access to viewer
mImpl->mSysIf->SetViewer(mImpl->mViewer);
dtEntity::SetSystemInterface(mImpl->mSysIf);
dtEntity::SetInputInterface(mImpl->mInputIf);
dtEntity::SetWindowInterface(new dtEntityOSG::OSGWindowInterface(*mImpl->mEntityManager));
dtEntity::SetupDataPaths(argc, argv, false);
}
dtEntity::EntityManager &em = *mImpl->mEntityManager;
//////////////////////////// Add entity systems /////////////////////////
{
// this is a required component system, so add it immediately
em.AddEntitySystem(*new dtEntity::MapSystem(em));
em.AddEntitySystem(*new dtEntityOSG::LayerSystem(em));
em.AddEntitySystem(*new dtEntityOSG::CameraSystem(em));
em.AddEntitySystem(*new dtEntityOSG::PositionAttitudeTransformSystem(em));
em.AddEntitySystem(*new dtEntityOSG::StaticMeshSystem(em));
em.AddEntitySystem(*new RoomDestructionSystem(em));
em.AddEntitySystem(*new MotionModelSystem(em));
em.AddEntitySystem(*new ModelSplitterSystem(em));
em.AddEntitySystem(*new OrthoMotionModelSystem(em));
em.AddEntitySystem(*new dtEntityOSG::LightSystem(em));
em.AddEntitySystem(*new PlayerSystem(em));
em.AddEntitySystem(*new IconSystem(em));
em.AddEntitySystem(*new TextSystem(em));
#ifdef BUILD_WITH_GSTREAMER
em.AddEntitySystem(*new VideoSystem(em));
#endif
dtEntityOSG::LayerAttachPointSystem *layerattach = new dtEntityOSG::LayerAttachPointSystem(em);
em.AddEntitySystem(*layerattach);
layerattach->CreateSceneGraphRootEntity(new osg::Group());
mImpl->mInterface = new CtrlImpl(em, parentWidget);
// need layer system for debug draw interface, so set it up now
dtEntity::SetDebugDrawInterface(new dtEntityOSG::OSGDebugDrawInterface(em));
}
//////////////////////////// Init time tracking /////////////////////////
{
mImpl->mStartFrameTick = osg::Timer::instance()->tick();
mImpl->mInterface->SetSimulationTime(0);
time_t t;
time(&t);
mImpl->mSimulationClockTime = t / osg::Timer::instance()->getSecondsPerTick();
}
for (int i = 1; i < argc; ++i)
{
std::string curArgv = argv[i];
if (!curArgv.empty() && curArgv == "--openOverview")
mImpl->mInterface->OpenOverview();
}
//////////////////////////// Start simulation /////////////////////////
{
dtEntity::StartSystemMessage msg;
em.EnqueueMessage(msg);
}
}
////////////////////////////////////////////////////////////////////////////////
MainLoop::~MainLoop()
{
delete mImpl;
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::EntityManager *MainLoop::getEntityManager() const
{
return mImpl->mEntityManager;
}
////////////////////////////////////////////////////////////////////////////////
ViewerInterface *MainLoop::getViewerInterface() const
{
return mImpl->mInterface;
}
////////////////////////////////////////////////////////////////////////////////
bool MainLoop::getProfilingEnabled() const
{
return mImpl->mProfilingEnabled;
}
////////////////////////////////////////////////////////////////////////////////
void MainLoop::setProfilingEnabled(bool v)
{
mImpl->mProfilingEnabled = v;
}
////////////////////////////////////////////////////////////////////////////////
void MainLoop::tick()
{
dtEntityOSG::OSGSystemInterface *iface = dtEntityOSG::GetOSGSystemInterface();
if (!mImpl->mInterface->allViewWindowsExposed())
return;
if (getViewerInterface()->GetNonRealtimeMode())
{
float deltaTime = 1.0f / mImpl->mInterface->GetFrameRate();
float deltaSimTime = deltaTime;
mImpl->mSimulationClockTime += deltaSimTime / osg::Timer::instance()->getSecondsPerTick();
mImpl->mInterface->SetSimulationTime(mImpl->mInterface->GetSimulationTime() + deltaSimTime);
iface->SetTimeValues(mImpl->mInterface->GetSimulationTime(), deltaSimTime, deltaTime, mImpl->mSimulationClockTime);
}
else
{
float deltaTime = 0;
float deltaSimTime = 0;
dtEntity::Timer_t tick = osg::Timer::instance()->tick();
deltaTime = static_cast<float>(osg::Timer::instance()->delta_s(mImpl->mStartFrameTick, tick));
deltaSimTime = deltaTime * mImpl->mInterface->GetTimeScale();
mImpl->mStartFrameTick = tick;
mImpl->mSimulationClockTime += deltaSimTime / osg::Timer::instance()->getSecondsPerTick();
mImpl->mInterface->SetSimulationTime(mImpl->mInterface->GetSimulationTime() + deltaSimTime);
iface->SetTimeValues(mImpl->mInterface->GetSimulationTime(), deltaSimTime, deltaTime, mImpl->mSimulationClockTime);
}
if (mImpl->mProfilingEnabled)
{
static dtEntity::StringId frameId = dtEntity::SID("Frame");
static dtEntity::StringId frameAdvanceId = dtEntity::SID("Frame_Advance");
static dtEntity::StringId frameEvTrId = dtEntity::SID("Frame_EventTraversal");
static dtEntity::StringId frameUpTrId = dtEntity::SID("Frame_UpdateTraversal");
static dtEntity::StringId frameRenderTrId = dtEntity::SID("Frame_RenderingTraversals");
static unsigned int framecount = 0;
CProfileManager::Increment_Frame_Counter();
CProfileManager::Start_Profile(frameId);
CProfileManager::Start_Profile(frameAdvanceId);
mImpl->mViewer->advance();
CProfileManager::Stop_Profile();
CProfileManager::Start_Profile(frameEvTrId);
mImpl->mViewer->eventTraversal();
iface->EmitTickMessagesAndQueuedMessages();
CProfileManager::Stop_Profile();
if (mImpl->mViewer->getNumViews() > 0 && mImpl->mViewer->checkNeedToDoFrame())
{
CProfileManager::Start_Profile(frameUpTrId);
mImpl->mViewer->updateTraversal();
iface->EmitPostUpdateMessage();
CProfileManager::Stop_Profile();
CProfileManager::Start_Profile(frameRenderTrId);
mImpl->mViewer->renderingTraversals();
CProfileManager::Stop_Profile();
}
else
iface->EmitPostUpdateMessage();
CProfileManager::Stop_Profile(); // frameId
if (++framecount > 99)
{
CProfileManager::dumpAll();
fflush(stdout);
framecount = 0;
CProfileManager::Reset();
}
}
else
{
/**
NASTY BUG WORKAROUND:
Somehow, changes made to the frame are not immediately shown when
a new frame is requested. This only happens when more than one view is opened.
The workaround is to render again two more times even if no frame redraw
was requested.
*/
static int renderagaincnt = 0;
mImpl->mViewer->advance(DBL_MAX);
mImpl->mViewer->eventTraversal();
iface->EmitTickMessagesAndQueuedMessages();
bool needFrame = mImpl->mViewer->checkNeedToDoFrame();
if (mImpl->mViewer->getNumViews() > 0 && (renderagaincnt != 0 || needFrame))
{
if (mImpl->mViewer->getNumViews() == 1)
renderagaincnt = 0;
else if (needFrame)
renderagaincnt = 2;
else
--renderagaincnt;
mImpl->mViewer->updateTraversal();
iface->EmitPostUpdateMessage();
mImpl->mViewer->renderingTraversals();
}
else
iface->EmitPostUpdateMessage();
}
if (!getViewerInterface()->GetNonRealtimeMode() && mImpl->mViewer->getRunMaxFrameRate() > 0.0)
{
if (mImpl->mProfilingEnabled)
{
static dtEntity::StringId sleepId = dtEntity::SID("Frame_Sleep");
CProfileManager::Start_Profile(sleepId);
}
osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
double frameTime =
osg::Timer::instance()->delta_s(mImpl->mStartFrameTick, endFrameTick);
double minFrameTime = 1.0 / mImpl->mViewer->getRunMaxFrameRate();
if (frameTime < minFrameTime)
OpenThreads::Thread::microSleep(1000000.0 * (minFrameTime - frameTime));
if (mImpl->mProfilingEnabled)
CProfileManager::Stop_Profile();
}
}
////////////////////////////////////////////////////////////////////////////////
void MainLoop::GetCurrentPosition(Vec3d &position, Vec3d &lookAt)
{
position = Vec3d();
lookAt = Vec3d();
dtEntity::MapSystem *ms;
mImpl->mEntityManager->GetES(ms);
if (!ms)
return;
dtEntity::EntityId eid = ms->GetEntityIdByUniqueId("cam_overview");
dtEntityOSG::CameraComponent *camcomp;
if (!mImpl->mEntityManager->GetComponent(eid, camcomp))
{
LOG_ERROR("GetCurrentPosition: Error accessing camera");
return;
}
osg::Vec3d p = camcomp->GetPosition();
osg::Vec3d la = camcomp->GetEyeDirection() + camcomp->GetPosition();
position.x = p[0]; position.y = p[1]; position.z = p[2];
lookAt.x = la[0]; lookAt.y = la[1]; lookAt.z = la[2];
}
}
@@ -0,0 +1,42 @@
#pragma once
#include "export.h"
class QWidget;
namespace dtEntity
{
class EntityManager;
}
namespace VCtrl
{
class ViewerInterface;
struct Vec3d;
class VIEWER_CTRL_EXPORT MainLoop
{
public:
MainLoop(int argc, char **argv, QWidget *parentWidget);
~MainLoop();
dtEntity::EntityManager *getEntityManager() const;
ViewerInterface *getViewerInterface() const;
bool getProfilingEnabled() const;
void setProfilingEnabled(bool v);
void shutDown();
bool isRunning() const;
void tick();
void GetCurrentPosition(Vec3d &position, Vec3d &lookAt);
private:
class Impl;
Impl *mImpl;
};
}
@@ -0,0 +1,118 @@
#include "messages.h"
namespace VCtrl
{
///////////////////////////////////////////////////////////////////////////////////////////////////////
void RegisterMessageTypes(dtEntity::MessageFactory& em)
{
em.RegisterMessageType<NavMeshGroupChangedMessage>(NavMeshGroupChangedMessage::TYPE);
em.RegisterMessageType<TransformSendMessage>(TransformSendMessage::TYPE);
em.RegisterMessageType<PlayerPickedMessage>(PlayerPickedMessage::TYPE);
em.RegisterMessageType<DisplayNameClickedMessage>(DisplayNameClickedMessage::TYPE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType NavMeshGroupChangedMessage::TYPE(dtEntity::SID("NavMeshGroupChangedMessage"));
const dtEntity::StringId NavMeshGroupChangedMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
const dtEntity::StringId NavMeshGroupChangedMessage::GroupNameId(dtEntity::SID("GroupName"));
const dtEntity::StringId NavMeshGroupChangedMessage::PreviousGroupNameId(dtEntity::SID("PreviousGroupName"));
NavMeshGroupChangedMessage::NavMeshGroupChangedMessage()
: Message(TYPE)
{
this->Register(AboutEntityId, &mAboutEntity);
this->Register(GroupNameId, &mGroupName);
this->Register(PreviousGroupNameId, &mPreviousGroupName);
}
////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType TransformSendMessage::TYPE(dtEntity::SID("TransformSendMessage"));
const dtEntity::StringId TransformSendMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
const dtEntity::StringId TransformSendMessage::PositionId(dtEntity::SID("Position"));
const dtEntity::StringId TransformSendMessage::AttitudeId(dtEntity::SID("Attitude"));
const dtEntity::StringId TransformSendMessage::RoomNumberId(dtEntity::SID("RoomNumber"));
////////////////////////////////////////////////////////////////////////////////
TransformSendMessage::TransformSendMessage()
: Message(TYPE)
{
Register(AboutEntityId, &mAboutEntity);
Register(PositionId, &mPosition);
Register(AttitudeId, &mAttitude);
Register(RoomNumberId, &mRoomNumber);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType PlayerPickedMessage::TYPE(dtEntity::SID("PlayerPickedMessage"));
const dtEntity::StringId PlayerPickedMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
const dtEntity::StringId PlayerPickedMessage::PositionId(dtEntity::SID("Position"));
PlayerPickedMessage::PlayerPickedMessage()
: Message(TYPE)
{
this->Register(AboutEntityId, &mAboutEntity);
this->Register(PositionId, &mPosition);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType FastForwardMessage::TYPE(dtEntity::SID("FastForwardMessage"));
const dtEntity::StringId FastForwardMessage::EndTimeId(dtEntity::SID("EndTime"));
FastForwardMessage::FastForwardMessage()
: Message(TYPE)
{
this->Register(EndTimeId, &mEndTime);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType HideSelectionMessage::TYPE(dtEntity::SID("HideSelectionMessage"));
const dtEntity::StringId HideSelectionMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
const dtEntity::StringId HideSelectionMessage::NameFlagId(dtEntity::SID("NameFlag"));
HideSelectionMessage::HideSelectionMessage()
: Message(TYPE)
{
this->Register(AboutEntityId, &mAboutEntity);
this->Register(NameFlagId, &mNameFlag);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType RemoveShootMessage::TYPE(dtEntity::SID("RemoveShootMessage"));
RemoveShootMessage::RemoveShootMessage()
: Message(TYPE)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType ShootMessage::TYPE(dtEntity::SID("ShootMessage"));
ShootMessage::ShootMessage()
: Message(TYPE)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType ShowHidePlayerMessage::TYPE(dtEntity::SID("ShowHidePlayerMessage"));
const dtEntity::StringId ShowHidePlayerMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
ShowHidePlayerMessage::ShowHidePlayerMessage()
: Message(TYPE)
{
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
const dtEntity::MessageType DisplayNameClickedMessage::TYPE(dtEntity::SID("DisplayNameClickedMessage"));
const dtEntity::StringId DisplayNameClickedMessage::AboutEntityId(dtEntity::SID("AboutEntity"));
const dtEntity::StringId DisplayNameClickedMessage::PositionId(dtEntity::SID("Position"));
DisplayNameClickedMessage::DisplayNameClickedMessage()
: Message(TYPE)
{
this->Register(AboutEntityId, &mAboutEntity);
this->Register(PositionId, &mPosition);
}
}
@@ -0,0 +1,278 @@
#pragma once
#include <dtEntity/messagefactory.h>
#include <dtEntity/message.h>
#include <dtEntity/property.h>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////<
void RegisterMessageTypes(dtEntity::MessageFactory& em);
////////////////////////////////////////////////////////////////////////////////
class NavMeshGroupChangedMessage
: public dtEntity::Message
{
public:
// type identifier of this message class
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
static const dtEntity::StringId GroupNameId;
static const dtEntity::StringId PreviousGroupNameId;
NavMeshGroupChangedMessage();
// Create a copy of this message on the heap
dtEntity::Message* Clone() const override { return CloneContainer<NavMeshGroupChangedMessage>(); }
void SetAboutEntityId(dtEntity::EntityId id) { mAboutEntity.Set(id); }
dtEntity::EntityId GetAboutEntityId() const { return mAboutEntity.Get(); }
void SetGroupName(const std::string& v) { mGroupName.Set(v); }
std::string GetGroupName() const { return mGroupName.Get(); }
void SetPreviousGroupName(const std::string& v) { mPreviousGroupName.Set(v); }
std::string GetPreviousGroupName() const { return mPreviousGroupName.Get(); }
private:
dtEntity::IntProperty mAboutEntity;
dtEntity::StringProperty mGroupName;
dtEntity::StringProperty mPreviousGroupName;
};
////////////////////////////////////////////////////////////////////////////////
class TransformSendMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
static const dtEntity::StringId PositionId;
static const dtEntity::StringId AttitudeId;
static const dtEntity::StringId RoomNumberId;
TransformSendMessage();
dtEntity::Message* Clone() const override { return CloneContainer<TransformSendMessage>(); }
void SetAboutEntity(dtEntity::EntityId id) { mAboutEntity.Set(id); }
dtEntity::EntityId GetAboutEntity() const { return mAboutEntity.Get(); }
void SetPosition(const osg::Vec3f& id) { mPosition.Set(id); }
osg::Vec3f GetPosition() const { return mPosition.Get(); }
void SetAttitude(const osg::Quat& id) { mAttitude.Set(id); }
osg::Quat GetAttitude() const { return mAttitude.Get(); }
void SetRoomNumber(dtEntity::EntityId roomNumber) { mRoomNumber.Set(roomNumber); }
dtEntity::EntityId GetRoomNumber() const { return mRoomNumber.Get(); }
private:
dtEntity::UIntProperty mAboutEntity;
dtEntity::Vec3Property mPosition;
dtEntity::QuatProperty mAttitude;
dtEntity::UIntProperty mRoomNumber;
};
////////////////////////////////////////////////////////////////////////////////<
class PlayerPickedMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
static const dtEntity::StringId PositionId;
PlayerPickedMessage();
dtEntity::Message* Clone() const override { return CloneContainer<PlayerPickedMessage>(); }
void SetAboutEntityId(dtEntity::EntityId v) { mAboutEntity.Set(v); }
dtEntity::EntityId GetAboutEntityId() const { return mAboutEntity.Get(); }
void SetPosition(const osg::Vec3f& v) { mPosition.Set(v); }
osg::Vec3f GetPosition() const { return mPosition.Get(); }
private:
dtEntity::UIntProperty mAboutEntity;
dtEntity::Vec3Property mPosition;
};
////////////////////////////////////////////////////////////////////////////////
class FastForwardMessage
: public dtEntity::Message
{
public:
// type identifier of this message class
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId EndTimeId;
FastForwardMessage();
// Create a copy of this message on the heap
dtEntity::Message* Clone() const override { return CloneContainer<FastForwardMessage>(); }
void SetEndTime(double v) { mEndTime.Set(v); }
double GetEndTime() const { return mEndTime.Get(); }
private:
dtEntity::DoubleProperty mEndTime;
};
////////////////////////////////////////////////////////////////////////////////<
class HideSelectionMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
static const dtEntity::StringId NameFlagId;
HideSelectionMessage();
dtEntity::Message* Clone() const override { return CloneContainer<HideSelectionMessage>(); }
void SetAboutEntityId(dtEntity::EntityId v) { mAboutEntity.Set(v); }
dtEntity::EntityId GetAboutEntityId() const { return mAboutEntity.Get(); }
void SetNameFlagId(bool v) { mNameFlag.Set(v); }
bool GetNameFlagId() const { return mNameFlag.Get(); }
private:
dtEntity::UIntProperty mAboutEntity;
dtEntity::BoolProperty mNameFlag;
};
////////////////////////////////////////////////////////////////////////////////<
class RemoveShootMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
RemoveShootMessage();
dtEntity::Message* Clone() const override { return CloneContainer<RemoveShootMessage>(); }
void SetId(int32_t id) { mId = id; }
int32_t GetId() { return mId; }
private:
int32_t mId { 0 };
};
////////////////////////////////////////////////////////////////////////////////<
class ShootMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
ShootMessage();
dtEntity::Message* Clone() const override { return CloneContainer<ShootMessage>(); }
void SetShooter(dtEntity::EntityId v) { mShooter = v; }
dtEntity::EntityId GetShooter() const { return mShooter; }
void SetShooterPos(const dtEntity::Vec3d &shooterPos) { mShooterPos = shooterPos; }
dtEntity::Vec3d GetShooterPos() const { return mShooterPos; }
void SetTarget(dtEntity::EntityId v) { mTarget = v; }
dtEntity::EntityId GetTarget() const { return mTarget; }
void SetTargetPos(const dtEntity::Vec3d &targetPos) { mTargetPos = targetPos; }
dtEntity::Vec3d GetTargetPos() const { return mTargetPos; }
void SetBuildingIdSrc(dtEntity::EntityId v) { mBuildingIdSrc = v; }
dtEntity::EntityId GetBuildingIdSrc() const { return mBuildingIdSrc; }
void SetRoomNumberSrc(const dtEntity::EntityId &v) { mRoomNumberSrc = v; }
dtEntity::EntityId GetRoomNumberSrc() const { return mRoomNumberSrc; }
void SetBuildingIdDst(dtEntity::EntityId v) { mBuildingIdDst = v; }
dtEntity::EntityId GetBuildingIdDst() const { return mBuildingIdDst; }
void SetRoomNumberDst(const dtEntity::EntityId &v) { mRoomNumberDst = v; }
dtEntity::EntityId GetRoomNumberDst() const { return mRoomNumberDst; }
void SetDuration(float v) { mDuration = v; }
float GetDuration() const { return mDuration; }
void SetLineType(int v) { mLineType = v; }
float GetLineType() const { return mLineType; }
void SetSimTimeCreated(double v) { mSimTimeCreated = v; }
double GetSimTimeCreated() const { return mSimTimeCreated; }
void SetId(int32_t id) { mId = id; }
int32_t GetId() const { return mId; }
private:
int32_t mId { 0 };
dtEntity::Vec3d mShooterPos;
dtEntity::Vec3d mTargetPos;
dtEntity::EntityId mShooter = 0;
dtEntity::EntityId mTarget = 0;
dtEntity::EntityId mBuildingIdSrc = 0;
dtEntity::EntityId mRoomNumberSrc = 0;
dtEntity::EntityId mBuildingIdDst = 0;
dtEntity::EntityId mRoomNumberDst = 0;
int mLineType = 0;
float mDuration = 0.f;
double mSimTimeCreated = 0;
};
////////////////////////////////////////////////////////////////////////////////<
class ShowHidePlayerMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
ShowHidePlayerMessage();
dtEntity::Message* Clone() const override { return CloneContainer<ShowHidePlayerMessage>(); }
void SetAboutEntityId(dtEntity::EntityId v) { mAboutEntity.Set(v); }
dtEntity::EntityId GetAboutEntityId() const { return mAboutEntity.Get(); }
void SetShow(bool v) { mShow = v; }
bool GetShow() const { return mShow; }
private:
dtEntity::UIntProperty mAboutEntity = 0;
bool mShow = false;
};
////////////////////////////////////////////////////////////////////////////////<
class DisplayNameClickedMessage
: public dtEntity::Message
{
public:
static const dtEntity::MessageType TYPE;
static const dtEntity::StringId AboutEntityId;
static const dtEntity::StringId PositionId;
DisplayNameClickedMessage();
dtEntity::Message* Clone() const override { return CloneContainer<DisplayNameClickedMessage>(); }
void SetAboutEntityId(dtEntity::EntityId v) { mAboutEntity.Set(v); }
dtEntity::EntityId GetAboutEntityId() const { return mAboutEntity.Get(); }
void SetPosition(const osg::Vec3f& v) { mPosition.Set(v); }
osg::Vec3f GetPosition() const { return mPosition.Get(); }
private:
dtEntity::UIntProperty mAboutEntity;
dtEntity::Vec3Property mPosition;
};
}
@@ -0,0 +1,125 @@
#include "modelsplittercomponent.h"
#include "visitors.h"
#include <dtEntity/mapcomponent.h>
#include <dtEntity/systemmessages.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/layerattachpointcomponent.h>
#include <dtEntityOSG/staticmeshcomponent.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QSet>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId ModelSplitterComponent::TYPE(dtEntity::SID("ModelSplitter"));
const dtEntity::StringId ModelSplitterComponent::VerticalDisplaceId(dtEntity::SID("VerticalDisplace"));
const dtEntity::StringId ModelSplitterComponent::HorizontalDisplaceId(dtEntity::SID("HorizontalDisplace"));
////////////////////////////////////////////////////////////////////////////
ModelSplitterComponent::ModelSplitterComponent()
{
Register(VerticalDisplaceId, &mVerticalDisplace);
Register(HorizontalDisplaceId, &mHorizontalDisplace);
}
////////////////////////////////////////////////////////////////////////////
void ModelSplitterComponent::OnAddedToEntity(dtEntity::Entity &entity)
{
BaseClass::OnAddedToEntity(entity);
mEntity = &entity;
}
////////////////////////////////////////////////////////////////////////////
void ModelSplitterComponent::Split(std::vector<dtEntity::EntityId> &eids, std::vector<float> &heights, std::vector<int> &floors, dtEntity::StringId layerName)
{
dtEntityOSG::StaticMeshComponent *smc;
if (!mEntity->GetComponent(smc))
{
LOG_ERROR("Cannot split: Has no staticmeshcomponent");
return;
}
osg::ref_ptr<osg::Node> mesh = osgDB::readNodeFile(smc->GetMesh());
if (mesh == nullptr) return;
SplitVisitor v;
mesh->accept(v);
heights = v._heights;
mesh = nullptr;
for (const auto &part : v._parts)
{
osg::ref_ptr<osg::Node> node = osg::clone(part.get(), osg::CopyOp(
osg::CopyOp::DEEP_COPY_OBJECTS |
osg::CopyOp::DEEP_COPY_NODES |
osg::CopyOp::DEEP_COPY_USERDATA
));
dtEntity::Entity *e;
if (!mEntity->GetEntityManager().CreateEntity(e))
continue;
eids.push_back(e->GetId());
std::string nname = node->getName();
std::string floorstr = nname.substr(6, nname.size() - 1);
int floor = QString::fromStdString(floorstr).toInt();
floors.push_back(floor);
std::ostringstream entityname;
entityname << dtEntity::GetStringFromSID(layerName) << "_" << floorstr;
dtEntity::MapComponent *mc;
if (!e->CreateComponent(mc))
continue;
mc->SetEntityName(entityname.str());
mc->SetUniqueId(entityname.str());
mc->SetMapName("parts");
dtEntityOSG::StaticMeshComponent *smcFloor;
if (!e->CreateComponent(smcFloor))
continue;
smcFloor->SetStaticMesh(node);
dtEntityOSG::PositionAttitudeTransformComponent *pc;
if (!e->CreateComponent(pc))
continue;
pc->AddChildComponent(smcFloor->GetType());
dtEntityOSG::LayerComponent *lc;
if (!e->CreateComponent(lc))
continue;
lc->SetAttachedComponent(pc->GetType());
lc->SetLayer(layerName);
lc->Finished();
}
// sort
std::sort(floors.begin(), floors.end());
}
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId ModelSplitterSystem::TYPE(dtEntity::SID("ModelSplitter"));
////////////////////////////////////////////////////////////////////////////
ModelSplitterSystem::ModelSplitterSystem(dtEntity::EntityManager &em)
: dtEntity::DefaultEntitySystem<ModelSplitterComponent>(em)
{
}
}
@@ -0,0 +1,59 @@
#pragma once
#include <dtEntity/defaultentitysystem.h>
#include <dtEntity/component.h>
#include <dtEntity/message.h>
#include <dtEntity/stringid.h>
#include <dtEntity/dynamicproperty.h>
#include <dtEntity/scriptaccessor.h>
namespace VCtrl
{
class ModelSplitterComponent final : public dtEntity::Component
{
using BaseClass = dtEntity::Component;
public:
static const dtEntity::ComponentType TYPE;
static const dtEntity::StringId VerticalDisplaceId;
static const dtEntity::StringId HorizontalDisplaceId;
ModelSplitterComponent();
void OnAddedToEntity(dtEntity::Entity &entity) override;
dtEntity::ComponentType GetType() const override { return TYPE; }
void Split(std::vector<dtEntity::EntityId> &eids, std::vector<float> &heights, std::vector<int> &floors, dtEntity::StringId layerName);
dtEntity::FloatProperty mVerticalDisplace;
dtEntity::Vec2Property mHorizontalDisplace;
void SetBuildingId(dtEntity::StringId id) { mBuildingId = id; }
dtEntity::StringId GetBuildingId() const { return mBuildingId; }
private:
dtEntity::Entity *mEntity = nullptr;
dtEntity::StringId mBuildingId = 0;
};
//////////////////////////////////////////////////////////
class ModelSplitterSystem final
: public dtEntity::DefaultEntitySystem<ModelSplitterComponent>
, public dtEntity::ScriptAccessor
{
public:
explicit ModelSplitterSystem(dtEntity::EntityManager &em);
static const dtEntity::ComponentType TYPE;
};
}
@@ -0,0 +1,373 @@
#include "motionmodel.h"
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/core.h>
#include <dtEntity/systeminterface.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/transformcomponent.h>
#include <osg/io_utils>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId MotionModelComponent::TYPE(dtEntity::SID("MotionModel"));
const dtEntity::StringId MotionModelComponent::ContextIdId(dtEntity::SID("ContextId"));
const dtEntity::StringId MotionModelComponent::MoveSpeedId(dtEntity::SID("MoveSpeed"));
const dtEntity::StringId MotionModelComponent::RotateSpeedId(dtEntity::SID("RotateSpeed"));
const dtEntity::StringId MotionModelComponent::RotateKeySpeedId(dtEntity::SID("RotateKeySpeed"));
const dtEntity::StringId MotionModelComponent::EnabledId(dtEntity::SID("Enabled"));
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId MotionModelSystem::TYPE(dtEntity::SID("MotionModel"));
////////////////////////////////////////////////////////////////////////////
MotionModelComponent::MotionModelComponent()
{
Register(ContextIdId, &mContextId);
Register(MoveSpeedId, &mMoveSpeed);
Register(RotateSpeedId, &mRotateSpeed);
Register(RotateKeySpeedId, &mRotateKeySpeed);
Register(EnabledId, &mEnabled);
mContextId.Set(0);
mMoveSpeed.Set(100);
mRotateSpeed.Set(0.001f);
mRotateKeySpeed.Set(2);
mEnabled.Set(true);
}
////////////////////////////////////////////////////////////////////////////
void MotionModelComponent::OnAddedToEntity(dtEntity::Entity &entity)
{
mEntity = &entity;
dtEntity::GetInputInterface()->AddInputCallback(this);
}
////////////////////////////////////////////////////////////////////////////
void MotionModelComponent::OnRemovedFromEntity(dtEntity::Entity &)
{
mEntity = nullptr;
dtEntity::GetInputInterface()->RemoveInputCallback(this);
}
////////////////////////////////////////////////////////////////////////////
void MotionModelComponent::Finished()
{
assert(mEntity != nullptr);
bool success = mEntity->GetComponent(mCamera);
if (success)
mContextId.Set(mCamera->GetContextId());
else
LOG_ERROR("MotionModelComponent on entity without camera component!");
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::KeyUp(const std::string &key, bool handled, unsigned int contextid)
{
if (!handled && mEnabled.Get() && (int)contextid == mContextId.Get())
{
if (key == "t")
{
osg::Vec3d campos = mCamera->GetPosition();
LOG_ALWAYS("Translation: " << campos)
}
else if (key == "1") mMoveSpeed.Set(5);
else if (key == "2") mMoveSpeed.Set(15);
else if (key == "3") mMoveSpeed.Set(40);
else if (key == "4") mMoveSpeed.Set(100);
else if (key == "5") mMoveSpeed.Set(250);
else if (key == "6") mMoveSpeed.Set(600);
else if (key == "7") mMoveSpeed.Set(1500);
else if (key == "8") mMoveSpeed.Set(4000);
else if (key == "9") mMoveSpeed.Set(9000);
else if (key == "0") mMoveSpeed.Set(20000);
else if (key == "KP_Add") mMoveSpeed.Set(mMoveSpeed.Get() * 1.1f);
else if (key == "KP_Subtract") mMoveSpeed.Set(mMoveSpeed.Get() / 1.1f);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::KeyDown(const std::string &, bool, unsigned int)
{
return false;
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::MouseButtonUp(int button, bool, unsigned int contextid)
{
if (!mEnabled.Get() || (int)contextid != mContextId.Get()) return false;
if (button == 1 || button == 2)
dtEntity::GetInputInterface()->SetLockCursor(false);
return false;
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::MouseButtonDown(int button, bool handled, unsigned int contextid)
{
if (handled) return false;
if (!mEnabled.Get() || (int)contextid != mContextId.Get()) return false;
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
if (button == 1)
inputif->SetLockCursor(true);
else if (button == 2)
{
// do intersection test to get pivot point to rotate around
inputif->SetLockCursor(true);
double mouseX = inputif->GetAxis(dtEntity::InputInterface::MouseXId);
double mouseY = inputif->GetAxis(dtEntity::InputInterface::MouseYId);
osg::Vec3 pickray = dtEntity::GetWindowInterface()->GetPickRay(contextid, mouseX, mouseY);
osg::Vec3d campos = mCamera->GetPosition();
std::vector<dtEntity::WindowInterface::Intersection> isects;
bool found = dtEntity::GetWindowInterface()->GetIntersections(campos, campos + pickray * 10000, isects);
if (found)
mPivot = isects.front().mPosition;
else
mPivot = campos + pickray * 100;
}
return false;
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::MouseWheel(int dir, bool handled, unsigned int contextid)
{
if (!mEnabled.Get())
return false;
if (!handled && mCamera != nullptr && mContextId.Get() == (int)contextid)
{
osg::Vec3d campos = mCamera->GetPosition();
osg::Vec3d eyedir = mCamera->GetEyeDirection();
mCamera->SetPosition(campos + eyedir * dir * 20);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
}
return false;
}
////////////////////////////////////////////////////////////////////////////
bool MotionModelComponent::MouseMove(float, float, bool handled, unsigned int contextid)
{
if (handled)
return false;
if (mCamera == nullptr || !mEnabled.Get() || mContextId.Get() != (int)contextid)
return false;
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
double mouseX = inputif->GetAxis(dtEntity::InputInterface::MouseDeltaXRawId);
double mouseY = inputif->GetAxis(dtEntity::InputInterface::MouseDeltaYRawId);
osg::Vec3d up = mCamera->GetUp();
osg::Vec3d eyedir = mCamera->GetEyeDirection();
osg::Vec3d toRight = eyedir ^ up;
if (inputif->GetMouseButton(1, mContextId.Get()))
{
osg::Quat rotateop1; rotateop1.makeRotate(-mouseX * mRotateSpeed.Get(), up);
osg::Quat rotateop2; rotateop2.makeRotate(mouseY * mRotateSpeed.Get(), toRight);
eyedir = (rotateop1 * rotateop2) * eyedir;
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
}
else if (inputif->GetMouseButton(2, mContextId.Get()))
{
osg::Vec3d pivotToCam = mCamera->GetPosition() - mPivot;
osg::Quat rotateop1; rotateop1.makeRotate(mouseX * -0.001f, up);
osg::Quat rotateop2; rotateop2.makeRotate(mouseY * 0.001f, toRight);
pivotToCam = (rotateop1 * rotateop2) * pivotToCam;
mCamera->SetPosition(pivotToCam + mPivot);
pivotToCam *= -1;
pivotToCam.normalize();
mCamera->SetEyeDirection(pivotToCam);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
}
return false;
}
////////////////////////////////////////////////////////////////////////////
void MotionModelComponent::Tick(float dt)
{
if (mCamera == nullptr || !mEnabled.Get())
return;
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
float speed = mMoveSpeed.Get();
if (inputif->GetKey("Shift_L", mContextId.Get()))
speed *= 4;
bool modified = false;
if (inputif->GetKey("w", mContextId.Get()))
{
mCamera->SetPosition(mCamera->GetPosition() + mCamera->GetEyeDirection() * (dt * speed));
modified = true;
}
if (inputif->GetKey("s", mContextId.Get()))
{
mCamera->SetPosition(mCamera->GetPosition() + mCamera->GetEyeDirection() * (dt * -speed));
modified = true;
}
if (inputif->GetKey("a", mContextId.Get()))
{
osg::Vec3d toRight = mCamera->GetEyeDirection() ^ mCamera->GetUp();
mCamera->SetPosition(mCamera->GetPosition() + toRight * (dt * -speed));
modified = true;
}
if (inputif->GetKey("d", mContextId.Get()))
{
osg::Vec3d toRight = mCamera->GetEyeDirection() ^ mCamera->GetUp();
mCamera->SetPosition(mCamera->GetPosition() + toRight * (dt * speed));
modified = true;
}
if (inputif->GetKey("q", mContextId.Get()))
{
osg::Vec3d toRight = mCamera->GetEyeDirection() ^ mCamera->GetUp();
mCamera->SetPosition(mCamera->GetPosition() + (toRight ^ mCamera->GetEyeDirection()) * (dt * -speed));
modified = true;
}
if (inputif->GetKey("e", mContextId.Get()))
{
osg::Vec3d toRight = mCamera->GetEyeDirection() ^ mCamera->GetUp();
mCamera->SetPosition(mCamera->GetPosition() + (toRight ^ mCamera->GetEyeDirection()) * (dt * speed));
modified = true;
}
if (inputif->GetKey("Left", mContextId.Get()))
{
osg::Quat q; q.makeRotate(dt * mRotateKeySpeed.Get(), mCamera->GetUp());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Right", mContextId.Get()))
{
osg::Quat q; q.makeRotate(-dt * mRotateKeySpeed.Get(), mCamera->GetUp());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Up", mContextId.Get()))
{
osg::Quat q; q.makeRotate(-dt * mRotateKeySpeed.Get(), mCamera->GetUp() ^ mCamera->GetEyeDirection());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Down", mContextId.Get()))
{
osg::Quat q; q.makeRotate(dt * mRotateKeySpeed.Get(), mCamera->GetUp() ^ mCamera->GetEyeDirection());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (modified)
{
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
mCamera->UpdateViewMatrix();
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
MotionModelSystem::MotionModelSystem(dtEntity::EntityManager &em)
: BaseClass(em)
{
mTickFunctor = dtEntity::MessageFunctor(this, &MotionModelSystem::Tick);
GetEntityManager().RegisterForMessages(dtEntity::TickMessage::TYPE,
mTickFunctor, dtEntity::FilterOptions::ORDER_DEFAULT, "MotionModelSystem::Tick");
mMoveToPosFunctor = dtEntity::MessageFunctor(this, &MotionModelSystem::MoveToPos);
GetEntityManager().RegisterForMessages(dtEntity::MoveCameraToPositionMessage::TYPE,
mMoveToPosFunctor, dtEntity::FilterOptions::ORDER_DEFAULT, "MotionModelSystem::MoveToPos");
mMoveToEntityFunctor = dtEntity::MessageFunctor(this, &MotionModelSystem::MoveToEntity);
GetEntityManager().RegisterForMessages(dtEntity::MoveCameraToEntityMessage::TYPE,
mMoveToEntityFunctor, dtEntity::FilterOptions::ORDER_DEFAULT, "MotionModelSystem::MoveToEntity");
}
////////////////////////////////////////////////////////////////////////////
void MotionModelSystem::Tick(const dtEntity::Message &m)
{
const dtEntity::TickMessage &msg = static_cast<const dtEntity::TickMessage &>(m);
for (auto i : mComponents)
i.second->Tick(msg.GetDeltaRealTime());
}
////////////////////////////////////////////////////////////////////////////
void MotionModelSystem::MoveToPos(const dtEntity::Message &m)
{
const dtEntity::MoveCameraToPositionMessage &msg = static_cast<const dtEntity::MoveCameraToPositionMessage &>(m);
for (auto i : mComponents)
{
MotionModelComponent *mmc = i.second;
if ((int)mmc->GetContextId() == msg.GetContextId())
{
dtEntityOSG::CameraComponent *cam = mmc->GetCamera();
if (cam)
{
cam->SetPosition(msg.GetPosition());
osg::Vec3d eyedir = msg.GetLookAt() - msg.GetPosition();
eyedir.normalize();
cam->SetEyeDirection(eyedir);
cam->SetUp(msg.GetUp());
cam->UpdateViewMatrix();
}
}
}
}
////////////////////////////////////////////////////////////////////////////
void MotionModelSystem::MoveToEntity(const dtEntity::Message &m)
{
const dtEntity::MoveCameraToEntityMessage &msg = static_cast<const dtEntity::MoveCameraToEntityMessage &>(m);
dtEntityOSG::TransformComponent *transcomp;
if (!GetEntityManager().GetComponent(msg.GetAboutEntityId(), transcomp, true))
{
LOG_ERROR("Cannot jump to entity: has no transform component!");
return;
}
osg::Vec3d targetpos = transcomp->GetTranslation();
for (auto i : mComponents)
{
MotionModelComponent *mmc = i.second;
if ((int)mmc->GetContextId() != msg.GetContextId()) continue;
dtEntityOSG::CameraComponent *cam = mmc->GetCamera();
if (!cam) continue;
if (msg.GetKeepCameraDirection())
{
osg::Vec3d eyedir = cam->GetEyeDirection();
eyedir *= msg.GetDistance();
cam->SetPosition(targetpos - eyedir);
cam->UpdateViewMatrix();
}
else
{
osg::Vec3d eyedir = targetpos - cam->GetPosition();
eyedir.normalize();
cam->SetEyeDirection(eyedir);
cam->SetPosition(targetpos + eyedir * -msg.GetDistance());
cam->UpdateViewMatrix();
}
}
}
}
@@ -0,0 +1,84 @@
#pragma once
#include <dtEntity/defaultentitysystem.h>
#include <dtEntityOSG/cameracomponent.h>
#include <dtEntity/inputinterface.h>
namespace VCtrl
{
class MotionModelComponent final
: public dtEntity::Component
, public dtEntity::InputCallbackInterface
{
public:
static const dtEntity::ComponentType TYPE;
static const dtEntity::StringId ContextIdId;
static const dtEntity::StringId MoveSpeedId;
static const dtEntity::StringId RotateSpeedId;
static const dtEntity::StringId RotateKeySpeedId;
static const dtEntity::StringId EnabledId;
MotionModelComponent();
dtEntity::ComponentType GetType() const override { return TYPE; }
virtual bool IsInstanceOf(dtEntity::ComponentType id) const
{
return (id == TYPE);
}
void OnAddedToEntity(dtEntity::Entity &entity) override;
void OnRemovedFromEntity(dtEntity::Entity &) override;
void Finished() override;
void Tick(float dt);
unsigned int GetContextId() const { return mContextId.Get(); }
void SetContextId(unsigned int i) { mContextId.Set(i); }
bool KeyUp(const std::string &key, bool handled, unsigned int contextid) override;
bool KeyDown(const std::string &name, bool handled, unsigned int contextid) override;
bool MouseButtonUp(int button, bool handled, unsigned int contextid) override;
bool MouseButtonDown(int button, bool handled, unsigned int contextid) override;
bool MouseWheel(int dir, bool handled, unsigned int contextid) override;
bool MouseMove(float x, float y, bool handled, unsigned int contextid) override;
void MouseEnterLeave(bool, unsigned int) override {}
dtEntityOSG::CameraComponent *GetCamera() const { return mCamera; }
private:
dtEntity::IntProperty mContextId;
dtEntity::UIntProperty mMoveSpeed;
dtEntity::FloatProperty mRotateSpeed;
dtEntity::FloatProperty mRotateKeySpeed;
dtEntity::BoolProperty mEnabled;
dtEntityOSG::CameraComponent *mCamera = nullptr;
dtEntity::Entity *mEntity = nullptr;
osg::Vec3d mPivot;
};
////////////////////////////////////////////////////////////////////////////////
class MotionModelSystem final
: public dtEntity::DefaultEntitySystem<MotionModelComponent>
{
using BaseClass = dtEntity::DefaultEntitySystem<MotionModelComponent>;
public:
static const dtEntity::ComponentType TYPE;
explicit MotionModelSystem(dtEntity::EntityManager &em);
private:
void Tick(const dtEntity::Message &m);
void MoveToPos(const dtEntity::Message &m);
void MoveToEntity(const dtEntity::Message &m);
dtEntity::MessageFunctor mTickFunctor;
dtEntity::MessageFunctor mMoveToPosFunctor;
dtEntity::MessageFunctor mMoveToEntityFunctor;
};
}
@@ -0,0 +1,374 @@
#include "orthomotionmodel.h"
#include "messages.h"
#include <dtEntity/commandmessages.h>
#include <dtEntity/mapcomponent.h>
#include <dtEntity/profile.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/core.h>
#include <dtEntity/systeminterface.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/layerattachpointcomponent.h>
#include <dtEntityOSG/skyboxcomponent.h>
#include <dtEntityOSG/transformcomponent.h>
#include <osgUtil/LineSegmentIntersector>
#include <osgViewer/View>
namespace VCtrl
{
constexpr int LeftMouseButton = 0;
//const int RightMouseButton = 1;
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId OrthoMotionModelComponent::TYPE(dtEntity::SID("OrthoMotionModel"));
const dtEntity::StringId OrthoMotionModelComponent::ContextIdId(dtEntity::SID("ContextId"));
const dtEntity::StringId OrthoMotionModelComponent::EnabledId(dtEntity::SID("Enabled"));
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId OrthoMotionModelSystem::TYPE(dtEntity::SID("OrthoMotionModel"));
////////////////////////////////////////////////////////////////////////////
OrthoMotionModelComponent::OrthoMotionModelComponent()
{
Register(ContextIdId, &mContextId);
Register(EnabledId, &mEnabled);
mContextId.Set(0);
mEnabled.Set(true);
m_mouseMovedWhileLeftButtonPressed = false;
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelComponent::OnAddedToEntity(dtEntity::Entity &entity)
{
mEntity = &entity;
dtEntity::GetInputInterface()->AddInputCallback(this);
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelComponent::OnRemovedFromEntity(dtEntity::Entity &)
{
mEntity = nullptr;
dtEntity::GetInputInterface()->RemoveInputCallback(this);
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelComponent::Finished()
{
assert(mEntity != nullptr);
bool success = mEntity->GetComponent(mCamera);
if (success)
mContextId.Set(mCamera->GetContextId());
else
LOG_ERROR("MotionModelComponent on entity without camera component!");
}
////////////////////////////////////////////////////////////////////////////
bool OrthoMotionModelComponent::MouseButtonUp(int button, bool handled, unsigned int contextid)
{
(void)(handled);
if (!mEnabled.Get() || (int)contextid != mContextId.Get()) return false;
if (button == LeftMouseButton)
{
if(!m_mouseMovedWhileLeftButtonPressed)
{
/*
* Mouse has not been moved, this means user clicked and immediately released the left button.
* This means: Select object under cursor (if existent)
*/
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
double mouseX = inputif->GetAxis(dtEntity::InputInterface::MouseXRawId);
double mouseY = inputif->GetAxis(dtEntity::InputInterface::MouseYRawId);
dtEntityOSG::CameraSystem *camsys;
mEntity->GetEntityManager().GetES(camsys);
if (!camsys)
return false;
dtEntity::EntityId camid = camsys->GetCameraEntityByContextId(mContextId.Get());
dtEntityOSG::CameraComponent *camcomp;
mEntity->GetEntityManager().GetComponent(camid, camcomp);
if (!camcomp)
return false;
osgUtil::LineSegmentIntersector::Intersections isects;
osgViewer::View *v = dynamic_cast<osgViewer::View *>(camcomp->GetCamera()->getView());
bool found = v->computeIntersections(mouseX, mouseY, isects, 0xFFFFFFFF);
if (found)
{
osgUtil::LineSegmentIntersector::Intersections::const_iterator i;
for (const osgUtil::LineSegmentIntersector::Intersection &isect : isects)
{
for (osg::NodePath::const_reverse_iterator j = isect.nodePath.rbegin(); j != isect.nodePath.rend(); ++j)
{
const osg::Node *node = *j;
if (node->getName() == "icon")
{
const osg::Referenced *referenced = node->getUserData();
if (referenced == nullptr) continue;
const dtEntityOSG::EntityData *ed = dynamic_cast<const dtEntityOSG::EntityData *>(referenced);
if (ed != nullptr && ed->mEntity->GetId() != camid)
{
PlayerPickedMessage msg;
msg.SetAboutEntityId(ed->mEntity->GetId());
mEntity->GetEntityManager().EmitMessage(msg);
}
}
if(node->getName() == "text")
{
const osg::Referenced* referenced = node->getUserData();
if(referenced == nullptr) continue;
const dtEntityOSG::EntityData* ed = dynamic_cast<const dtEntityOSG::EntityData*>(referenced);
if(ed != nullptr && ed->mEntity->GetId() != camid)
{
DisplayNameClickedMessage msg;
msg.SetAboutEntityId(ed->mEntity->GetId());
mEntity->GetEntityManager().EmitMessage(msg);
}
}
}
}
}
}
m_mouseMovedWhileLeftButtonPressed = false;
dtEntity::GetInputInterface()->SetLockCursor(false);
dtEntity::GetWindowInterface()->SetShowCursor(contextid, true);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
bool OrthoMotionModelComponent::MouseButtonDown(int button, bool handled, unsigned int contextid)
{
if (handled) return false;
if (!mEnabled.Get() || (int)contextid != mContextId.Get()) return false;
if (button == LeftMouseButton)
{
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
inputif->SetLockCursor(true);
dtEntity::GetWindowInterface()->SetShowCursor(contextid, false);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
bool OrthoMotionModelComponent::MouseMove(float x, float y, bool handled, unsigned int contextid)
{
(void)(x);
(void)(y);
if (handled)
return false;
if (mCamera == nullptr || !mEnabled.Get() || mContextId.Get() != (int)contextid)
return false;
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
double mouseX = inputif->GetAxis(dtEntity::InputInterface::MouseDeltaXId);
double mouseY = inputif->GetAxis(dtEntity::InputInterface::MouseDeltaYId);
if (inputif->GetMouseButton(LeftMouseButton, mContextId.Get()))
{
m_mouseMovedWhileLeftButtonPressed = true;
double left, right, bottom, top, znear, zfar;
mCamera->GetCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, znear, zfar);
// scale movement speed by zoom factor
float speed = -0.35f * (right - left);
left = left + speed * mouseX;
right = right + speed * mouseX;
bottom = bottom + speed * mouseY;
top = top + speed * mouseY;
mCamera->SetOrthoLeft(left);
mCamera->SetOrthoRight(right);
mCamera->SetOrthoBottom(bottom);
mCamera->SetOrthoTop(top);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
if(m_callbackCamPosChanged)
{
m_callbackCamPosChanged(GetContextId(), BuildingViewer::CameraViewPosition(left, right, bottom, top));
}
}
/*else if(inputif->GetMouseButton(LeftButton, mContextId.Get()))
{
osg::Vec3d up = mCamera->GetUp();
osg::Vec3d eyedir = mCamera->GetEyeDirection();
osg::Vec3d toRight = eyedir ^ up;
osg::Vec3d pivotToCam = mCamera->GetPosition();
osg::Quat rotateop1; rotateop1.makeRotate(mouseX * -0.001f, up);
osg::Quat rotateop2; rotateop2.makeRotate(mouseY * 0.001f, toRight);
pivotToCam = (rotateop1 * rotateop2) * pivotToCam;
osg::Vec3d eyedir = pivotToCam;
eyedir *= -1;
eyedir.normalize();
if(fabs(eyedir[2]) < 0.99f)
{
mCamera->SetPosition(pivotToCam);
mCamera->SetEyeDirection(eyedir);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
}
}*/
return false;
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelComponent::performZoom(int dir, const osg::Vec2& zoompoint)
{
double left, right, bottom, top, znear, zfar;
mCamera->GetCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, znear, zfar);
osg::Vec2 zoompointabs(right * zoompoint[0] + left * (1 - zoompoint[0]),
top * zoompoint[1] + bottom * (1 - zoompoint[1]));
float zoom = 1.0f - dir * 0.2f;
left = zoompointabs[0] - (zoompointabs[0] - left) * zoom;
right = zoompointabs[0] - (zoompointabs[0] - right) * zoom;
bottom = zoompointabs[1] - (zoompointabs[1] - bottom) * zoom;
top = zoompointabs[1] - (zoompointabs[1] - top) * zoom;
mCamera->SetOrthoLeft(left);
mCamera->SetOrthoRight(right);
mCamera->SetOrthoBottom(bottom);
mCamera->SetOrthoTop(top);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
if(m_callbackCamPosChanged)
{
m_callbackCamPosChanged(GetContextId(), BuildingViewer::CameraViewPosition(left, right, bottom, top));
}
}
////////////////////////////////////////////////////////////////////////////
bool OrthoMotionModelComponent::MouseWheel(int dir, bool handled, unsigned int contextid)
{
if (!mEnabled.Get())
return false;
if (!handled && mCamera != nullptr && mContextId.Get() == (int)contextid)
{
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
double mouseX = inputif->GetAxis(dtEntity::InputInterface::MouseXId);
double mouseY = inputif->GetAxis(dtEntity::InputInterface::MouseYId);
osg::Vec2 zoompoint(0.5f, 0.5f);
int x, y, w, h;
dtEntity::GetWindowInterface()->GetWindowGeometry(contextid, x, y, w, h);
if (mouseX >= -1 && mouseX <= 1 && mouseY >= -1 && mouseY <= 1)
{
zoompoint[0] = (mouseX + 1) / 2.0f;
zoompoint[1] = (mouseY + 1) / 2.0f;
}
performZoom(dir, zoompoint);
}
return false;
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelComponent::Tick(float dt)
{
static const dtEntity::StringId MotionModelTick = dtEntity::SID("MotionModel Tick");
CProfileManager::Start_Profile(MotionModelTick);
if (mCamera == nullptr || !mEnabled.Get())
return;
dtEntity::InputInterface *inputif = dtEntity::GetInputInterface();
bool modified = false;
osg::Vec3d pos = mCamera->GetPosition();
float rotateKeySpeed = 1.0f;
if (inputif->GetKey("Left", mContextId.Get()))
{
osg::Quat q; q.makeRotate(dt * rotateKeySpeed, mCamera->GetUp());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Right", mContextId.Get()))
{
osg::Quat q; q.makeRotate(-dt * rotateKeySpeed, mCamera->GetUp());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Up", mContextId.Get()))
{
osg::Quat q; q.makeRotate(-dt * rotateKeySpeed, mCamera->GetUp() ^ mCamera->GetEyeDirection());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (inputif->GetKey("Down", mContextId.Get()))
{
osg::Quat q; q.makeRotate(dt * rotateKeySpeed, mCamera->GetUp() ^ mCamera->GetEyeDirection());
osg::Vec3d eyedir = q * mCamera->GetEyeDirection();
eyedir.normalize();
mCamera->SetEyeDirection(eyedir);
modified = true;
}
if (modified)
{
mCamera->SetPosition(pos);
mCamera->UpdateViewMatrix();
dtEntity::GetWindowInterface()->RequestRedraw(mContextId.Get());
}
CProfileManager::Stop_Profile();
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
OrthoMotionModelSystem::OrthoMotionModelSystem(dtEntity::EntityManager &em)
: BaseClass(em)
{
/*mTickFunctor = dtEntity::MessageFunctor(this, &OrthoMotionModelSystem::Tick);
GetEntityManager().RegisterForMessages(dtEntity::TickMessage::TYPE,
mTickFunctor, dtEntity::FilterOptions::ORDER_DEFAULT, "OrthoMotionModelSystem::Tick");*/
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelSystem::OnRemoveFromEntityManager(dtEntity::EntityManager &)
{
for (const auto &comp : mComponents)
dtEntity::GetInputInterface()->RemoveInputCallback(comp.second);
}
////////////////////////////////////////////////////////////////////////////
void OrthoMotionModelSystem::Tick(const dtEntity::Message &m)
{
const dtEntity::TickMessage &msg = static_cast<const dtEntity::TickMessage &>(m);
for (const auto &comp : mComponents)
comp.second->Tick(msg.GetDeltaRealTime());
}
}
@@ -0,0 +1,83 @@
#pragma once
#include <dtEntity/defaultentitysystem.h>
#include <dtEntity/inputinterface.h>
#include <dtEntityOSG/cameracomponent.h>
#include "cameraviewposition.h"
#include <functional>
namespace VCtrl
{
class OrthoMotionModelComponent final
: public dtEntity::Component
, public dtEntity::InputCallbackInterface
{
public:
static const dtEntity::ComponentType TYPE;
static const dtEntity::StringId ContextIdId;
static const dtEntity::StringId EnabledId;
OrthoMotionModelComponent();
dtEntity::ComponentType GetType() const override { return TYPE; }
virtual bool IsInstanceOf(dtEntity::ComponentType id) const
{
return (id == TYPE);
}
void OnAddedToEntity(dtEntity::Entity &entity) override;
void OnRemovedFromEntity(dtEntity::Entity &entity) override;
void Finished() override;
void Tick(float dt);
unsigned int GetContextId() const { return mContextId.Get(); }
void SetContextId(unsigned int i) { mContextId.Set(i); }
bool MouseButtonUp(int button, bool handled, unsigned int contextid) override;
bool MouseButtonDown(int button, bool handled, unsigned int contextid) override;
bool MouseWheel(int dir, bool handled, unsigned int contextid) override;
bool MouseMove(float x, float y, bool handled, unsigned int contextid) override;
void MouseEnterLeave(bool, unsigned int) override {}
void performZoom(int dir, const osg::Vec2& zoompoint);
dtEntityOSG::CameraComponent *GetCamera() const { return mCamera; }
// First parameter: contextID as returned by OrthoMotionModelComponent::GetContextId
std::function<void(unsigned int, const BuildingViewer::CameraViewPosition &)> m_callbackCamPosChanged;
private:
bool m_mouseMovedWhileLeftButtonPressed;
dtEntity::IntProperty mContextId;
dtEntity::BoolProperty mEnabled;
dtEntityOSG::CameraComponent *mCamera = nullptr;
dtEntity::Entity *mEntity = nullptr;
};
////////////////////////////////////////////////////////////////////////////////
class OrthoMotionModelSystem final
: public dtEntity::DefaultEntitySystem<OrthoMotionModelComponent>
{
using BaseClass = dtEntity::DefaultEntitySystem<OrthoMotionModelComponent>;
public:
static const dtEntity::ComponentType TYPE;
explicit OrthoMotionModelSystem(dtEntity::EntityManager &em);
void OnRemoveFromEntityManager(dtEntity::EntityManager &) override;
private:
void Tick(const dtEntity::Message &m);
dtEntity::MessageFunctor mTickFunctor;
};
}
@@ -0,0 +1,401 @@
#include "playercomponent.h"
#include "iconcomponent.h"
#include "messages.h"
#include <dtEntity/systemmessages.h>
#include <dtEntity/core.h>
#include <dtEntity/mapcomponent.h>
#include <dtEntity/profile.h>
#include <dtEntity/nodemasks.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <dtEntityOSG/shadercomponent.h>
#include <dtEntityOSG/transformcomponent.h>
#include <osgDB/ReadFile>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
struct ShowHidePlayerCommand : public PlayerComponent::Command
{
bool mShow;
ShowHidePlayerCommand(double when, bool show)
: Command(when)
, mShow(show)
{
}
void Execute(PlayerComponent *component) override
{
dtEntityOSG::LayerComponent *lc;
if (component->GetEntity()->GetComponent(lc))
{
lc->SetVisible(mShow);
dtEntity::GetWindowInterface()->RequestRedraw(0);
}
IconComponent *ic;
if (component->GetEntity()->GetComponent(ic))
ic->SetVisible(mShow);
ShowHidePlayerMessage msg;
msg.SetAboutEntityId(component->GetEntity()->GetId());
msg.SetShow(mShow);
component->GetEntity()->GetEntityManager().EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
struct TeleportToTargetCommand : public PlayerComponent::Command
{
osg::Vec3d mGoal;
VCtrl::OBB mOBB;
int mRoomNumber;
std::string mRoomname;
TeleportToTargetCommand(double when, const osg::Vec3d& goal, const VCtrl::OBB& obb, int roomNumber, const std::string& roomname)
: Command(when)
, mGoal(goal)
, mOBB(obb)
, mRoomNumber(roomNumber)
, mRoomname(roomname)
{
}
void Execute(PlayerComponent *component) override
{
dtEntityOSG::TransformComponent *tc = component->GetTransform();
if (tc)
{
tc->SetTranslation(mGoal);
tc->Finished();
}
else
LOG_ERROR("Cannot teleport: no transform component!");
component->PlaceAt(mGoal, mOBB, mRoomNumber, mRoomname);
}
};
////////////////////////////////////////////////////////////////////////////////
struct RemoveShootCommand : public PlayerComponent::Command
{
int mId;
RemoveShootCommand(double when, int32_t id)
: Command(when)
, mId(id)
{}
void Execute(PlayerComponent *component) override
{
dtEntity::EntityManager &em = component->GetEntity()->GetEntityManager();
RemoveShootMessage msg;
msg.SetId(mId);
em.EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
struct ShootCommand : public PlayerComponent::Command
{
int mId;
Vec3d mShooterPos;
Vec3d mTargetPos;
dtEntity::EntityId mShooter;
dtEntity::EntityId mTarget;
int mBuildingIdSrc;
int mRoomNumberSrc;
int mBuildingIdDst;
int mRoomNumberDst;
int mLineType;
float mDuration;
double mSimTimeCreated;
ShootCommand(double when, int id, dtEntity::EntityId shooter, dtEntity::EntityId target,
const Vec3d &shooterPos, const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
int lineType, float duration)
: Command(when)
, mId(id)
, mShooterPos(shooterPos)
, mTargetPos(targetPos)
, mShooter(shooter)
, mTarget(target)
, mBuildingIdSrc(buildingIdSrc)
, mRoomNumberSrc(roomNumberSrc)
, mBuildingIdDst(buildingIdDst)
, mRoomNumberDst(roomNumberDst)
, mLineType(lineType)
, mDuration(duration)
, mSimTimeCreated(when)
{
}
void Execute(PlayerComponent *component) override
{
dtEntity::EntityManager &em = component->GetEntity()->GetEntityManager();
// check if source/target is visible
dtEntity::Vec3d shooterpos(mShooterPos.x, mShooterPos.y, mShooterPos.z);
dtEntity::Vec3d targetpos(mTargetPos.x, mTargetPos.y, mTargetPos.z);
// draw an arrow
const osg::Vec4 shooterColor = component->GetColor();
dtEntity::GetDebugDrawInterface()->AddLine(shooterpos, targetpos, shooterColor, 2, mDuration, false);
osg::Vec3d edge = shooterpos - targetpos;
edge.normalize();
edge *= 0.5f;
osg::Quat q;
q.makeRotate(osg::PI / 4.0, 0, 0, 1);
osg::Vec3d result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
q.makeRotate(-osg::PI / 4.0, 0, 0, 1);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
osg::Vec3d left = edge ^ osg::Vec3d(0, 0, 1);
q.makeRotate(osg::PI / 4.0, left[0], left[1], left[2]);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
q.makeRotate(-osg::PI / 4.0, left[0], left[1], left[2]);
result = q * edge;
dtEntity::GetDebugDrawInterface()->AddLine(targetpos, targetpos + result, shooterColor, 2, mDuration, false);
ShootMessage msg;
msg.SetId(mId);
msg.SetShooter(mShooter);
msg.SetShooterPos(osg::Vec3d(mShooterPos.x, mShooterPos.y, mShooterPos.z));
msg.SetTarget(mTarget);
msg.SetTargetPos(osg::Vec3d(mTargetPos.x, mTargetPos.y, mTargetPos.z));
msg.SetBuildingIdSrc(mBuildingIdSrc);
msg.SetRoomNumberSrc(mRoomNumberSrc);
msg.SetBuildingIdDst(mBuildingIdDst);
msg.SetRoomNumberDst(mRoomNumberDst);
msg.SetLineType(mLineType);
msg.SetDuration(mDuration);
msg.SetSimTimeCreated(mSimTimeCreated);
em.EmitMessage(msg);
}
};
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId PlayerComponent::TYPE(dtEntity::SID("Player"));
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::OnAddedToEntity(dtEntity::Entity &entity)
{
mEntity = &entity;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::OnRemovedFromEntity(dtEntity::Entity &entity)
{
NavMeshGroupChangedMessage msg;
msg.SetPreviousGroupName(dtEntity::GetStringFromSID(mCurrentCellGroup));
msg.SetAboutEntityId(GetEntity()->GetId());
msg.SetGroupName("");
entity.GetEntityManager().EmitMessage(msg);
mEntity = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
dtEntityOSG::TransformComponent *PlayerComponent::GetTransform()
{
assert(mEntity != nullptr);
if (mTransform == nullptr)
{
mEntity->GetComponent(mTransform, true);
assert(mTransform);
}
return mTransform;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::ExecuteCommands(double timenow)
{
if (mCommands.empty())
return;
double nexttime = timenow;
osg::ref_ptr<Command> execcommand = nullptr;
for (const auto &command : mCommands)
{
if (command->mStartTime < nexttime)
{
execcommand = command;
nexttime = command->mStartTime;
}
}
if (execcommand.valid())
{
mCommands.erase(execcommand);
execcommand->Execute(this);
}
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::PositionOnMesh(const VCtrl::OBB& bb, osg::Vec3d& pos, const std::string& roomname)
{
GetTransform()->SetTranslation(pos);
mPreviousRoom = mCurrentRoom;
mCurrentRoom = dtEntity::SID(roomname);
if (bb.mBuilding != mCurrentCellGroup)
{
NavMeshGroupChangedMessage msg;
msg.SetPreviousGroupName(dtEntity::GetStringFromSID(mCurrentCellGroup));
msg.SetAboutEntityId(GetEntity()->GetId());
msg.SetGroupName(dtEntity::GetStringFromSID(bb.mBuilding));
mCurrentCellGroup = bb.mBuilding;
GetEntity()->GetEntityManager().EmitMessage(msg);
}
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::PlaceAt(const osg::Vec3d &_goal, const VCtrl::OBB &obb, int roomNumber, const std::string &roomname)
{
LOG_DEBUG("PlayerComponent::PlaceAt: " << "mEntity='"<< mEntity << "'"
<< ", _goal: x=" << _goal.x() << " y=" << _goal.y() << " z=" << _goal.z()
<< ", roomNumber="<< roomNumber
<< ", roomname='"<< roomname << "'");
osg::Vec3d pgoal = _goal;
PositionOnMesh(obb, pgoal, roomname);
dtEntity::GetWindowInterface()->RequestRedraw(0);
TransformSendMessage msg;
msg.SetAboutEntity(mEntity->GetId());
msg.SetPosition(pgoal);
msg.SetRoomNumber(roomNumber);
mEntity->GetEntityManager().EmitMessage(msg);
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::SetColor(const osg::Vec4f &color)
{
mColor = color;
}
////////////////////////////////////////////////////////////////////////////////
void PlayerComponent::DeleteQueuedCommands()
{
mCommands.clear();
}
////////////////////////////////////////////////////////////////////////////////
osg::Vec4f PlayerComponent::GetColor() const
{
return mColor;
}
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId PlayerSystem::TYPE(dtEntity::SID("Player"));
////////////////////////////////////////////////////////////////////////////
PlayerSystem::PlayerSystem(dtEntity::EntityManager &em)
: dtEntity::DefaultEntitySystem<PlayerComponent>(em)
{
mTickFunctor = dtEntity::MessageFunctor(this, &PlayerSystem::OnTick);
em.RegisterForMessages(dtEntity::TickMessage::TYPE, mTickFunctor, dtEntity::FilterOptions::ORDER_LATE, "PlayerSystem::OnTick");
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::OnTick(const dtEntity::Message &m)
{
static const dtEntity::StringId PlayerSystemTick = dtEntity::SID("PlayerSystem Tick");
CProfileManager::Start_Profile(PlayerSystemTick);
const dtEntity::TickMessage &msg = static_cast<const dtEntity::TickMessage &>(m);
for (const auto &comp : mComponents)
comp.second->ExecuteCommands(msg.GetSimulationTime());
CProfileManager::Stop_Profile();
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::PlayerShoot(int32_t id, dtEntity::EntityId shooterid, dtEntity::EntityId targetid,
const Vec3d &shooterPos, const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
int lineType, double when, double duration)
{
ComponentStore::iterator shooter = mComponents.find(shooterid);
if (shooter == mComponents.end())
return;
// targetid may be a building
//if (mComponents.find(targetid) == mComponents.end())
// return;
PlayerComponent *shooterc = shooter->second;
shooterc->AddCommand(new ShootCommand(when, id, shooterid, targetid, shooterPos, targetPos, buildingIdSrc, roomNumberSrc, buildingIdDst, roomNumberDst, lineType, duration));
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::RemovePlayerShoot(int32_t id, double when)
{
ComponentStore::iterator shooter = mComponents.find(id);
if (shooter == mComponents.end())
return;
PlayerComponent *shooterc = shooter->second;
shooterc->AddCommand(new RemoveShootCommand(when, id));
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::ShowHidePlayer(dtEntity::EntityId eid, bool show, double when)
{
ComponentStore::iterator i = mComponents.find(eid);
if (i != mComponents.end())
{
PlayerComponent *player = i->second;
if (when <= 0)
{
IconComponent *ic;
if (player->GetEntity()->GetComponent(ic))
ic->SetVisible(show);
}
else
player->AddCommand(new ShowHidePlayerCommand(when, show));
}
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::TeleportToTarget(dtEntity::EntityId id, double when, const osg::Vec3d &goal, const VCtrl::OBB &obb, int roomNumber, const std::string& roomname)
{
LOG_DEBUG("PlayerSystem::TeleportToTarget: " << "id='"<< id << "'"
<< ", when="<< when
<< ", goal: x=" << goal.x() << " y=" << goal.y() << " z=" << goal.z()
<< ", roomNumber="<< roomNumber
<< ", roomname='"<< roomname << "'");
ComponentStore::iterator i = mComponents.find(id);
if (i != mComponents.end())
{
PlayerComponent *player = i->second;
player->AddCommand(new TeleportToTargetCommand(when, goal, obb, roomNumber, roomname));
}
else
{
dtEntityOSG::TransformComponent *pat;
if (GetEntityManager().GetComponent(id, pat, true))
pat->SetTranslation(goal);
}
}
////////////////////////////////////////////////////////////////////////////
void PlayerSystem::DeleteQueuedCommands()
{
for (const auto &comp : mComponents)
comp.second->DeleteQueuedCommands();
}
}
@@ -0,0 +1,110 @@
#pragma once
#include <dtEntity/component.h>
#include <dtEntity/entity.h>
#include <dtEntity/defaultentitysystem.h>
#include <dtEntity/dynamicproperty.h>
#include <dtEntity/scriptaccessor.h>
#include <osg/Referenced>
#include <osg/PositionAttitudeTransform>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/osgdebugdrawinterface.h>
#include "buildingmanager.h"
#include <set>
namespace dtEntityOSG
{
class TransformComponent;
}
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
class PlayerComponent final : public dtEntity::Component
{
public:
static const dtEntity::StringId TYPE;
PlayerComponent() = default;
virtual dtEntity::ComponentType GetType() const override { return TYPE; }
virtual bool IsInstanceOf(dtEntity::ComponentType id) const
{
return ((id == TYPE));
}
void OnAddedToEntity(dtEntity::Entity &entity) override;
void OnRemovedFromEntity(dtEntity::Entity &entity) override;
dtEntity::Entity *GetEntity() const { return mEntity; }
void PlaceAt(const osg::Vec3d& _goal, const VCtrl::OBB& obb, int roomNumber, const std::string& roomname);
struct Command : public osg::Referenced
{
double mStartTime = 0;
Command(double startTime) : mStartTime(startTime) {}
virtual ~Command() = default;
virtual void Execute(PlayerComponent *component) = 0;
};
void AddCommand(Command *c) { mCommands.insert(c); }
size_t GetNumCommands() const { return mCommands.size(); }
void ExecuteCommands(double timenow);
void DeleteQueuedCommands();
dtEntityOSG::TransformComponent *GetTransform();
osg::Vec4 GetColor() const;
void SetColor(const osg::Vec4 &);
dtEntity::StringId GetCurrentCellGroup() const { return mCurrentCellGroup; }
dtEntity::StringId GetCurrentRoom() const { return mCurrentRoom; }
dtEntity::StringId GetPreviousRoom() const { return mPreviousRoom; }
private:
void PositionOnMesh(const VCtrl::OBB&, osg::Vec3d& pos, const std::string& roomname);
dtEntity::Entity *mEntity = nullptr;
using Commands = std::set<osg::ref_ptr<Command>>;
Commands mCommands;
dtEntityOSG::TransformComponent *mTransform = nullptr;
osg::Vec4f mColor;
dtEntity::StringId mCurrentCellGroup = dtEntity::StringId();
dtEntity::StringId mCurrentRoom = dtEntity::StringId();
dtEntity::StringId mPreviousRoom = dtEntity::StringId();
};
////////////////////////////////////////////////////////////////////////////////
class PlayerSystem final
: public dtEntity::DefaultEntitySystem<PlayerComponent>
, public dtEntity::ScriptAccessor
{
public:
static const dtEntity::StringId TYPE;
explicit PlayerSystem(dtEntity::EntityManager &em);
void OnTick(const dtEntity::Message &m);
void ShowHidePlayer(dtEntity::EntityId eid, bool show, double when);
void TeleportToTarget(dtEntity::EntityId id, double when, const osg::Vec3d &goal, const VCtrl::OBB &obb, int roomNumber, const std::string &roomname);
void PlayerShoot(int32_t id, dtEntity::EntityId shooterid, dtEntity::EntityId targetid,
const Vec3d &shooterPos, const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst, int lineType,
double when, double duration);
void RemovePlayerShoot(int32_t id, double when);
// delete commands from all players
void DeleteQueuedCommands();
private:
dtEntity::MessageFunctor mTickFunctor;
};
}
@@ -0,0 +1,142 @@
#include "roomdestructioncomponent.h"
#include "visitors.h"
#include <dtEntity/core.h>
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/staticmeshcomponent.h>
#include <osg/Depth>
#include <osg/PolygonMode>
#include <osg/BlendFunc>
#include <osg/Material>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Node>
#include <osgDB/FileUtils>
#include <sstream>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId RoomDestructionComponent::TYPE(dtEntity::SID("RoomDestruction"));
////////////////////////////////////////////////////////////////////////////////
void RoomDestructionComponent::OnEnteredWorld()
{
osg::Shader *vShader = osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("shaders/roomdestruction.vert"));
osg::Shader *fShader = osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("shaders/roomdestruction.frag"));
if (vShader == nullptr || fShader == nullptr)
{
LOG_ERROR("Could not load building transparency shaders!");
Q_ASSERT(false);
}
osg::Program *p = new osg::Program();
p->setName("RoomDestructionShader");
p->addShader(vShader);
p->addShader(fShader);
dtEntityOSG::LayerComponent *lc;
if (mEntity->GetComponent(lc))
{
osg::Node *n = lc->GetAttachedComponentNode();
if (n != nullptr)
{
ClearVertexColorsVisitor v;
lc->GetAttachedComponentNode()->accept(v);
osg::StateSet *ss = n->getOrCreateStateSet();
ss->setAttributeAndModes(p);
ss->addUniform(new osg::Uniform("room_color", osg::Vec4(1, 1, 1, 1)));
ss->addUniform(new osg::Uniform("wall_color", osg::Vec4(1, 1, 1, 1)));
}
}
dtEntityOSG::StaticMeshComponent *smc;
if (mEntity->GetComponent(smc))
{
FindRoomNamesVisitor v;
smc->GetNode()->accept(v);
for (const auto &roomName: v.mNames)
mRoomDestructions[roomName] = 0;
}
}
////////////////////////////////////////////////////////////////////////////
bool RoomDestructionComponent::SetRoomDestructionValue(const std::string &room, float value)
{
if (mRoomDestructions.find(room) == mRoomDestructions.end())
return false;
FindRoomByNumberVisitor fn;
fn.setNameToFind(room);
dtEntityOSG::LayerComponent *lc;
if (!mEntity->GetComponent(lc))
return false;
osg::Node *n = lc->GetAttachedComponentNode();
if (n == nullptr)
return false;
lc->GetAttachedComponentNode()->accept(fn);
for (const auto &node : fn.getNodeList())
{
RoomDestructionSystem *bts;
mEntity->GetEntityManager().GetES(bts);
FindRoomComponentsVisitor frc;
node->accept(frc);
FindExactNameVisitor v(frc.mNamesFound);
//LOG_ERROR("Found " + std::to_string(frc.mNamesFound.size()) + " component names");
osg::Node *partNode = lc->GetAttachedComponentNode();
if (partNode)
partNode->accept(v);
for (const auto &visitedNodes : v.mNodes)
{
osg::StateSet *ss = visitedNodes->getOrCreateStateSet();
ss->addUniform(new osg::Uniform("room_color", osg::Vec4(1, 1 - value, 1 - value, 1)));
}
}
dtEntity::GetWindowInterface()->RequestRedraw(0);
mRoomDestructions[room] = value;
return true;
}
////////////////////////////////////////////////////////////////////////////
bool RoomDestructionComponent::SetBuildingDestructionValue(float value)
{
for (const auto &rd : mRoomDestructions)
SetRoomDestructionValue(rd.first, value);
return true;
}
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId RoomDestructionSystem::TYPE(dtEntity::SID("RoomDestruction"));
RoomDestructionSystem::RoomDestructionSystem(dtEntity::EntityManager &em)
: dtEntity::DefaultEntitySystem<RoomDestructionComponent>(em)
{
mEnterWorldFunctor = dtEntity::MessageFunctor(this, &RoomDestructionSystem::OnEnterWorld);
em.RegisterForMessages(dtEntity::EntityAddedToSceneMessage::TYPE, mEnterWorldFunctor, "RoomDestructionSystem::OnEnterWorld");
}
////////////////////////////////////////////////////////////////////////////
void RoomDestructionSystem::OnEnterWorld(const dtEntity::Message &msg)
{
dtEntity::EntityId id = msg.Get(dtEntity::EntityAddedToSceneMessage::AboutEntityId)->UIntValue();
RoomDestructionComponent *bt;
if (GetEntityManager().GetComponent(id, bt))
bt->OnEnteredWorld();
}
}
@@ -0,0 +1,78 @@
#pragma once
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/component.h>
#include <dtEntity/entity.h>
#include <dtEntity/defaultentitysystem.h>
#include <osgSim/DOFTransform>
#include <dtEntity/dynamicproperty.h>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
class RoomDestructionComponent final : public dtEntity::Component
{
public:
static const dtEntity::StringId TYPE;
dtEntity::ComponentType GetType() const override { return TYPE; }
virtual bool IsInstanceOf(dtEntity::ComponentType id) const
{
return ((id == TYPE));
}
void OnAddedToEntity(dtEntity::Entity &entity) override
{
mEntity = &entity;
}
void OnEnteredWorld();
void OnRemovedFromEntity(dtEntity::Entity &) override
{
mEntity = nullptr;
}
bool SetRoomDestructionValue(const std::string &room, float value);
bool SetBuildingDestructionValue(float value);
using RoomDestructions = std::map<std::string, float>;
const RoomDestructions &GetRoomDestructions() const
{
return mRoomDestructions;
}
private:
RoomDestructions mRoomDestructions;
dtEntity::Entity *mEntity = nullptr;
};
///////////////////////////////////////////////
// iterates over MovementComponents and updates the translation of the entity
// after applying forces
class RoomDestructionSystem final
: public dtEntity::DefaultEntitySystem<RoomDestructionComponent>
{
public:
static const dtEntity::StringId TYPE;
explicit RoomDestructionSystem(dtEntity::EntityManager &em);
void OnEnterWorld(const dtEntity::Message &msg);
private:
dtEntity::MessageFunctor mEnterWorldFunctor;
};
}
@@ -0,0 +1,232 @@
#include "textcomponent.h"
#include <dtEntity/nodemasks.h>
#include <osg/BlendFunc>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/LineWidth>
#include <osg/Node>
#include <osg/PolygonMode>
#include <osgText/Text>
#include <sstream>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId TextComponent::TYPE(dtEntity::SID("Text"));
const dtEntity::StringId TextComponent::PathId(dtEntity::SID("Path"));
////////////////////////////////////////////////////////////////////////////////
TextComponent::TextComponent()
: dtEntityOSG::TransformComponent(new osg::AutoTransform())
, mPath(
dtEntity::DynamicStringProperty::SetValueCB(this, &TextComponent::SetText),
dtEntity:: DynamicStringProperty::GetValueCB(this, &TextComponent::GetText)
)
{
Register(PathId, &mPath);
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
tr->setName("text");
tr->setAutoRotateMode(osg::AutoTransform::ROTATE_TO_SCREEN);
tr->setAutoScaleToScreen(true);
tr->setNodeMask(dtEntity::NodeMasks::PICKABLE | dtEntity::NodeMasks::VISIBLE);
tr->setNormal(osg::Vec3(0,1,0));
osg::StateSet* ss = tr->getOrCreateStateSet();
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
ss->setRenderBinDetails(90, "DepthSortedBin");
ss->setMode(GL_BLEND,osg::StateAttribute::ON);
ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
osg::ref_ptr<osg::LineWidth> lw = new osg::LineWidth();
lw->setWidth(2);
ss->setAttributeAndModes(lw, osg::StateAttribute::ON);
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::Rebuild()
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
tr->dirtyBound();
tr->setInitialBound(osg::BoundingSphere(osg::Vec3(), 10));
tr->removeChildren(0, tr->getNumChildren());
if(!mVisible) return;
osg::ref_ptr<osg::Geode> g = new osg::Geode();
tr->addChild(g);
tr->setInitialBound(osg::BoundingSphere(osg::Vec3(), 1));
osgText::Text* text = new osgText::Text();
text->setBackdropType(osgText::Text::NONE);
text->setCharacterSize(20);
text->setCharacterSizeMode(osgText::TextBase::SCREEN_COORDS);
//text->setColor(color);
if(mDisText.empty())
{
text->setText(mText);
}
else
{
text->setText(mDisText);
}
text->setAlignment(osgText::TextBase::CENTER_CENTER);
text->setAxisAlignment(osgText::TextBase::SCREEN);
//text->setPosition(position);
osg::StateSet* ss = text->getOrCreateStateSet();
osg::PolygonMode* polyModeObj = new osg::PolygonMode;
polyModeObj->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL);
ss->setAttribute(polyModeObj);
g->addDrawable(text);
if(mSelected)
{
int x, y, w, h;
int b = 6;
x = -25 / 2 - b;
y = 0 - b;
w = 25 + b * 2;
h = 4 + b * 2;
osg::ref_ptr<osg::Geometry> sel = new osg::Geometry();
g->addDrawable(sel);
osg::Vec4Array* colours = new osg::Vec4Array(1);
(*colours)[0] = osg::Vec4(1,0,0,1);
sel->setColorArray(colours);
sel->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::Vec3Array* coords = new osg::Vec3Array(4);
(*coords)[0] = osg::Vec3(x , y , 0);
(*coords)[1] = osg::Vec3(x , y + h, 0);
(*coords)[2] = osg::Vec3(x + w, y + h, 0);
(*coords)[3] = osg::Vec3(x + w, y , 0);
sel->setVertexArray(coords);
sel->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, 4));
osg::ref_ptr<osg::PolygonMode> p = new osg::PolygonMode;
p->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
sel->getOrCreateStateSet()->setAttribute(p);
}
}
////////////////////////////////////////////////////////////////////////////////
std::string TextComponent::GetText() const
{
return mText;
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetText(const std::string& text)
{
if(mText != text)
{
mText = text;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
std::string TextComponent::GetDisText() const
{
return mDisText;
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetDisText(const std::string& text)
{
if(mDisText != text)
{
mDisText = text;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Vec3d TextComponent::GetTranslation() const
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
return tr->getPosition();
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetTranslation(const dtEntity::Vec3d& v)
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
tr->setPosition(v);
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Vec3d TextComponent::GetScale() const
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
return tr->getScale();
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetScale(const dtEntity::Vec3d& v)
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
tr->setScale(v);
}
////////////////////////////////////////////////////////////////////////////////
dtEntity::Quat TextComponent::GetRotation() const
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
return tr->getRotation();
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetRotation(const dtEntity::Quat& v)
{
osg::AutoTransform* tr = static_cast<osg::AutoTransform*>(GetNode());
tr->setRotation(v);
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetColor(const osg::Vec4& v)
{
if(mColor != v)
{
mColor = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
bool TextComponent::GetShowSelection() const
{
return mSelected;
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetShowSelection(bool v)
{
//if(mSelected != v)
{
mSelected = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////////
void TextComponent::SetVisible(bool v)
{
//if(mVisible != v)
{
mVisible = v;
Rebuild();
}
}
////////////////////////////////////////////////////////////////////////////
TextSystem::TextSystem(dtEntity::EntityManager& em)
: dtEntity::DefaultEntitySystem<TextComponent>(em, dtEntityOSG::TransformComponent::TYPE)
{
}
}
@@ -0,0 +1,84 @@
#pragma once
#include <dtEntity/component.h>
#include <dtEntity/entity.h>
#include <dtEntity/defaultentitysystem.h>
#include <dtEntityOSG/nodecomponent.h>
#include <osg/AutoTransform>
#include <dtEntity/dynamicproperty.h>
#include <dtEntityOSG/transformcomponent.h>
namespace VCtrl
{
class TextComponent final : public dtEntityOSG::TransformComponent
{
public:
static const dtEntity::StringId TYPE;
static const dtEntity::StringId PathId;
TextComponent();
dtEntity::ComponentType GetType() const override { return TYPE; }
virtual bool IsInstanceOf(dtEntity::ComponentType id) const
{
return ((id == TYPE));
}
std::string GetText() const;
void SetText(const std::string& text);
std::string GetDisText() const;
void SetDisText(const std::string& text);
osg::Vec4 GetColor() const { return mColor; }
void SetColor(const osg::Vec4&);
dtEntity::Vec3d GetTranslation() const override;
void SetTranslation(const dtEntity::Vec3d&) override;
dtEntity::Vec3d GetScale() const override;
void SetScale(const dtEntity::Vec3d&) override;
dtEntity::Quat GetRotation() const override;
void SetRotation(const dtEntity::Quat&) override;
bool GetShowSelection() const;
void SetShowSelection(bool v);
void SetVisible(bool v);
bool GetVisible() const { return mVisible; }
private:
void Rebuild();
dtEntity::DynamicStringProperty mPath;
std::string mText;
std::string mDisText;
osg::Vec4 mColor;
bool mSelected = false;
bool mVisible = false;
};
///////////////////////////////////////////////
// iterates over MovementComponents and updates the translation of the entity
// after applying forces
class TextSystem final
: public dtEntity::DefaultEntitySystem<TextComponent>
{
public:
explicit TextSystem(dtEntity::EntityManager& em);
};
}
@@ -0,0 +1,66 @@
#include "videocomponent.h"
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/entity.h>
#include <dtEntity/stringid.h>
#include <dtEntityOSG/cameracomponent.h>
#include "windowcapturecallback.h"
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////
const dtEntity::StringId VideoSystem::TYPE(dtEntity::SID("Video"));
////////////////////////////////////////////////////////////////////////////
bool VideoSystem::StartVideoRecording(unsigned int contextid, const std::string &path, int w, int h, int framerate, int quality)
{
if (mWindowCaptureCallback.valid())
{
LOG_ERROR("Cannot start video recording, already started!");
return false;
}
StopVideoRecording(contextid);
dtEntityOSG::CameraSystem *cs;
GetEntityManager().GetES(cs);
dtEntity::EntityId camid = cs ? cs->GetCameraEntityByContextId(contextid) : 0;
dtEntityOSG::CameraComponent *camcomp;
if (camid == 0 || !GetEntityManager().GetComponent(camid, camcomp))
{
LOG_ERROR("Cannot set up video stream, camera not found");
return false;
}
mWindowCaptureCallback = new WindowCaptureCallback(GL_BACK, contextid, path, w, h, framerate, quality);
camcomp->GetCamera()->setFinalDrawCallback(mWindowCaptureCallback);
return true;
}
////////////////////////////////////////////////////////////////////////////
bool VideoSystem::StopVideoRecording(unsigned int contextid)
{
if (mWindowCaptureCallback.valid())
{
dtEntityOSG::CameraSystem *camsys;
if (GetEntityManager().GetES(camsys))
{
dtEntity::EntityId camid = camsys->GetCameraEntityByContextId(contextid);
if (camid != 0)
{
dtEntityOSG::CameraComponent *cam;
if (GetEntityManager().GetComponent(camid, cam))
cam->GetCamera()->setFinalDrawCallback(nullptr);
}
}
mWindowCaptureCallback = nullptr;
}
return true;
}
}
@@ -0,0 +1,36 @@
#pragma once
#include <dtEntity/component.h>
#include <dtEntity/defaultentitysystem.h>
#include <dtEntity/property.h>
#include <dtEntity/debugdrawinterface.h>
#include "windowcapturecallback.h"
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
class VideoSystem final
: public dtEntity::EntitySystem
{
using BaseClass = dtEntity::EntitySystem;
public:
static const dtEntity::ComponentType TYPE;
using dtEntity::EntitySystem::EntitySystem;
dtEntity::ComponentType GetComponentType() const override { return TYPE; }
bool StartVideoRecording(unsigned int contextid, const std::string &path, int w, int h, int framerate, int quality);
bool StopVideoRecording(unsigned int contextid);
private:
osg::ref_ptr<WindowCaptureCallback> mWindowCaptureCallback;
};
}
@@ -0,0 +1,695 @@
#pragma once
#if defined(_MSC_VER)
#include <winsock2.h>
#endif
#include <vector>
#include <map>
#include <string>
#include <QJsonValue>
#include <QList>
#include <QString>
#include <exccommands.h>
class QWidget;
namespace VCtrl
{
#if defined(_MSC_VER)
using Timer_t = __int64;
#else
using Timer_t = unsigned long long;
#endif
/**
* Class representing 2-dimensional float vector
*/
struct Vec2
{
Vec2() = default;
Vec2(float _x, float _y) : x(_x) , y(_y) { }
float x = 0;
float y = 0;
};
/**
* Class representing 3-dimensional float vector
*/
struct Vec3
{
Vec3() = default;
Vec3(float _x, float _y, float _z) : x(_x) , y(_y) , z(_z) { }
float x = 0;
float y = 0;
float z = 0;
};
/**
* Class representing 3-dimensional double vector
*/
struct Vec3d
{
Vec3d() = default;
Vec3d(double _x, double _y, double _z) : x(_x) , y(_y) , z(_z) { }
double x = 0;
double y = 0;
double z = 0;
};
/**
* Class representing a color value.
* Colors are encoded with 0.0 - 1.0 values for each channel.
* w component represents alpha / transparency.
*/
struct Color
{
Color() = default;
Color(float _x, float _y, float _z, float _w) : x(_x) , y(_y) , z(_z) , w(_w) { }
float x = 0;
float y = 0;
float z = 0;
float w = 0;
};
/**
* Class representing a quaternion.
* Used for representing rotations.
*/
struct Quat
{
Quat() = default;
Quat(double _x, double _y, double _z, double _w) : x(_x) , y(_y) , z(_z) , w(_w) { }
double x = 0;
double y = 0;
double z = 0;
double w = 1;
};
/**
* How to treat the z value
*/
enum class ZValue
{
AboveMsl, //!< treat z as above msl
RelativeBuildings, //!< the z position is relative to the buildings
};
/**
* Enumerates view modes for 2d building displays
*/
enum class ViewMode
{
ISOMETRIC,
ORTHOGRAPHIC
};
/**
* Enumerates view modes for 2d building displays
*/
enum class PlayerDisplayMode
{
Icons,
Dots
};
/**
* Callback class for receiving events from viewer side.
* Use with ViewerInterface::SetViewerCallback()
*/
class ViewerCallback
{
public:
virtual ~ViewerCallback() = default;
/**
* Gets called when building position map has finished loading and
* system is ready for use
*/
virtual void SystemReady() = 0;
/**
* Gets called when the position of an entity has changed
* @param id Id of moving entity
* @param pos Position of entity relative to terrain origin in meters
* @param attitude rotation of entity relative to posititive y axis
*/
virtual void TransformChanged(const std::string &id, const Vec3d &pos, const Quat &attitude) = 0;
/**
* Gets called when entity moves from one navmesh group (building or outside mesh)
* to the next
* @param id Id of moving entity
* @param grpname Name of navmesh group
*/
virtual void NavMeshGroupChanged(const std::string &id, const std::string &grpname) = 0;
/**
* Player has clicked on an entity symbol with the left mouse button.
* @param id Id of picked entity
*/
virtual void PlayerPicked(const std::string &id) = 0;
/**
* Player has clicked on an displayName with the left mouse button.
* @param buildingid Id of picked entity
* @param roomname roomname of picked entity
*/
virtual void DisplayNamePicked(const std::string& buildingid, const std::string& roomname) = 0;
/**
* A building view was opened.
* @param contextId id of graphics context. Can be used to close the view.
* @param viewmode Initial view mode of view
*/
virtual void ViewCreated(unsigned int contextId, ViewMode viewmode) = 0;
/**
* View mode of view was changed. This was either triggered by a call to
* ViewerInterface::ChangeViewMode or a click on the view mode buttons in the GUI
* @param contextId id of graphics context.
* @param viewmode New view mode of view
*/
virtual void ViewModeChanged(unsigned int contextId, ViewMode viewmode) = 0;
/**
* Line mode of view was changed. This was either triggered by a call to
* ViewerInterface::ChangeLineMode or a click on the line mode buttons in the GUI
* @param contextId id of graphics context.
* @param line Is line on or off
*/
virtual void ViewLineModeChanged(unsigned int contextId, bool line) = 0;
/**
* Name mode of view was changed. This was either triggered by a call to
* ViewerInterface::ChangeNameMode or a click on the name mode buttons in the GUI
* @param contextId id of graphics context.
* @param name Is name on or off
*/
virtual void ViewNameModeChanged(unsigned int contextId, bool name) = 0;
/**
* Lock ViewTransparencyChanged mode of view was changed. Triggered by slider
*/
virtual void ViewTransparencyChanged() = 0;
/**
* Lock Rotation mode of view was changed. This was either triggered by a call to
* ViewerInterface::LockViewRotationToMapRotation or a click on
* the lock checkbox in the GUI
* @param contextId id of graphics context.
* @param lock Is lock on or off
*/
virtual void ViewLockRotationChanged(unsigned int contextId, bool lock) = 0;
/**
* Player display mode of view was changed. This was either triggered by a call to
* ViewerInterface::SetViewerDisplayMode or a click on
* the display mode checkbox in the GUI
* @param contextId id of graphics context.
* @param mode Mode enumerator
*/
virtual void PlayerDisplayModeChanged(unsigned int contextId, PlayerDisplayMode mode) = 0;
/**
* View was closed via ViewerInterface::CloseView or click on window
* close GUI element
* @param contextId id of graphics context.
*/
virtual void ViewClosed(unsigned int contextId) = 0;
virtual void HandleViewerEvent(BuildingViewer::BgViewerEvents event,
const std::vector<std::string> &args) = 0;
virtual void ViewZoomChanged(const std::string &buildingId,
double top, double left, double bottom, double right) = 0;
enum class Severity
{
Always,
Debug,
Info,
Warning,
Error,
Fatal
};
/**
* Receives error and other log messages from viewer
* @param severity The severity of the message
* @param filename The file that the log command was called from
* @param methodname The name of the method containing the log command
* @param linenumber The line number the log command was issued from
* @param msg Text of the log message
*/
virtual void LogMessage(Severity &severity, const std::string &filename,
const std::string &methodname,
int linenumber, const std::string &msg) = 0;
};
class ViewerInterface
{
public:
virtual ~ViewerInterface() = default;
/**
* Register object for receiving viewer event callbacks
*/
virtual void SetViewerCallback(ViewerCallback *) = 0;
virtual void RemoveViewerCallback() = 0;
/**
* Is used to set location of project specific terrain and building data.
* Example: "/home/martin/ProjectAssetsBremen"
*/
virtual void SetProjectDataPaths(const std::vector<std::string> &paths) = 0;
/**
* Open 3d view of whole terrain - for debugging purposes only!
*/
virtual void OpenOverview() = 0;
virtual QWidget* getMainWindow() = 0;
virtual quintptr requestMainWindowHandle() = 0;
virtual void reloadPlayerIcons() = 0;
virtual void UpdatePlayerPartyColors(const std::map<std::string, VCtrl::Color>& mapPlayerColors) = 0;
/**
* @brief true if positioningsystem gets exact position of player. Will be used for all opened views (GLOBAL FLAG)
* @param exactPos
*/
virtual void UseExactPositioning(bool exactPos) = 0;
/**
* Open a new display showing the building identified by buildingid.
* @param buildingid ID of the building. Use GetBuildingIds() to get all building ids
* @param windowtitle Title to display on window top
* @param bgcolor Background color of window
* @param viewmode The perspective mode to show building in
* @param screennum Number of screen to open display on
* @param fullscreen Ignore width and position and display as fullscreen instead
* @param x X-Position of window
* @param y Y-Position of window
* @param width Width of display in pixels
* @param height Height of display in pixels
* @param contextId receives context ID of the new view. Use it to close the view programmatically.
* @param exactPos true if positioningsystem gets exact position of player
* @return true if success
*/
virtual bool OpenView(const std::string &buildingid, const std::string &windowtitle, const Color &bgcolor, ViewMode viewmode,
int screennum, bool fullscreen, int x, int y, int width, int height,
unsigned int &contextId, bool exactPos = true) = 0;
virtual void openViews(const std::vector<std::string> &bldIds, bool exactPos) = 0;
/**
* Is a certain view opened?
* @param bldId ID of the building.
*/
virtual bool isViewOpen(const std::string &bldId) const = 0;
/**
* Close display previously opened with OpenView
* @param contextid context id of view, as returned from OpenView()
*/
virtual void CloseView(unsigned int contextid) = 0;
virtual void closeViews(const std::vector<std::string> &bldIds) = 0;
/**
* Change view mode of an existing view.
* @param contextId context id of view, as returned from OpenView()
* @param viewmode Viewmode enum value
*/
virtual void ChangeViewMode(unsigned int contextId, ViewMode viewmode) = 0;
virtual void setViewMode(ViewMode m) = 0;
/**
* Change view mode of an existing view.
* @param contextId context id of view, as returned from OpenView()
* @param line true if view should show lines outside , false if not
*/
virtual void ChangeLineMode(unsigned int contextId, bool line) = 0;
/**
* Change view mode of an existing view.
* @param contextId context id of view, as returned from OpenView()
* @param name true if view should show names, false if not
*/
virtual void ChangeNameMode(unsigned int contextId, bool name) = 0;
/**
* Set if view should rotate in accord with map rotation
* @param contextId context id of view, as returned from OpenView()
* @param lock true if view should rotate, false if it should remain static
*/
virtual void LockViewRotationToMapRotation(unsigned int contextId, bool lock) = 0;
/**
* Set if view should display movable players as dots or as icons
* @param contextId context id of view, as returned from OpenView()
* @param mode Display mode enumerator
*/
virtual void SetPlayerDisplayMode(unsigned int contextId, PlayerDisplayMode mode) = 0;
virtual void setDisplayMode(PlayerDisplayMode m) = 0;
/**
* Set wall transparency for a building window.
* @param contextId context id of view, as returned from OpenView()
* @param transparency 0 equals opaque, 1 equals invisible
*/
virtual void SetWallTransparency(unsigned int contextId, float transparency) = 0;
virtual void setTransparency(double percent) = 0;
/**
* All views with "LockViewRotationToMapRotation" enabled will rotate their camera
* to have a camera angle looking towards north, rotated by input angle.
* @returnRotation angle in degrees from north CCW
*/
virtual float GetMapRotation() const = 0;
/**
* All views with "LockViewRotationToMapRotation" enabled will rotate their camera
* to have a camera angle looking towards north, rotated by input angle.
* @param angle Rotation angle in degrees from north CCW
*/
virtual void SetMapRotation(float angle) = 0;
/**
* add buildings to scene and recalculate navigation meshes
* @param path Load map from this path. example: "Projections/data.xml"
*/
virtual bool LoadBuildingPositionMap(const std::string &path, bool loadAllAvailableBuildings) = 0;
/**
* Create new player at (0,0,0). Player is initially invisible!
* @param id a unique string that can later be used to reference the player
* @param iconpath system file path to player icon. Can be relative to ProjectAssets folder root.
* @param color Initial color of the player
*/
virtual void CreatePlayer(const std::string &id, const std::string &iconpath, const Color &color) = 0;
/**
* Delete player with given id
* @param seconds Delete player n seconds from now
*/
virtual void DeletePlayer(const std::string &id, float seconds = 0) = 0;
/**
* This color is added to the player texture color.
*/
virtual void SetPlayerColor(const std::string &id, const Color &color) = 0;
/**
* Set icon path for existing player
* @param path system file path to player icon. Can be relative to ProjectAssets folder root.
* If path is to current icon path then icon is reloaded from file.
*/
virtual void SetPlayerIcon(const std::string &id, const std::string &path) = 0;
/**
* Return number of soldier instances
*/
virtual size_t GetNumPlayers() const = 0;
/**
* Fill vector with ids of all existing players
*/
virtual void GetPlayerIds(std::vector<std::string> &toFill) = 0;
/**
* Hide or unhide player with given id
* @param show true to show, false to hide
* @param when simulation time when show or hide should be executed - < 0 --> show immediatelly
*/
virtual void SetPlayerShown(const std::string &id, bool show, double when = -1) = 0;
/**
* Return number of building instances
*/
virtual size_t GetNumBuildings() const = 0;
/**
* Fill vector with ids of all existing buildings
*/
virtual void GetBuildingIds(std::vector<std::string> &toFill) const = 0;
/**
* Add or remove visible bounding box around entity
* @param id unique id of entity
* @param show set true to show box, false to make invisible
* @param duration If non-negative, remove box after duration seconds
*/
virtual void SetShowSelectionBox(const std::string &id,
bool show,
float duration = -1) = 0;
/**
* Add a line from start to end
* Line is deleted after duration seconds.
* If duration is 0 then line is never deleted
*/
virtual void Shoot(const int id,
const std::string &shooterId,
const std::string &targetId,
const Vec3d &shooterPos,
const Vec3d &targetPos,
int buildingIdSrc,
int roomNumberSrc,
int buildingIdDst,
int roomNumberDst,
int lineType,
double when) = 0;
/**
* Add a line from start to end where end is a room in the given building
* Line is deleted after duration seconds.
* If duration is 0 then line is never deleted
*/
virtual void Shoot(const int id,
const std::string &shooterId,
const std::string &targetBuildingId,
const std::string &targetRoomId,
const Vec3d &shooterPos,
int lineType,
double when) = 0;
/**
* Remove a line
*/
virtual void removeShoot(const int id) = 0;
/**
* Directly move player to target position, do not use pathfinding. Cancels current path following activity.
* @param id Id of player
* @param when Simulation time when teleport should happen
* @param target position to teleport to
* @param bldgname name of building containing position, empty string to ignore
* @param roomname name of room containing position, empty string to ignore
*/
virtual void Teleport(const std::string &id,
double when,
const Vec3d &target,
const std::string &bldgname,
int roomNumber,
const std::string &roomname,
ZValue zval) = 0;
/**
* Get names of all rooms in building
* @param id Id of building player
* @param names will be filled with room names
*/
virtual void GetRoomNames(const std::string &id, std::vector<std::string> &names) = 0;
/**
* Sets destruction value for room of a building.
* @param id Id of building player
* @param roomnumber number of room to set (ex: "2001")
* @param value destruction value. 0: not destroyed, 1: fully destroyed
* @return true if room was found
*/
virtual bool SetRoomDestructionValue(const std::string &id,
const std::string &roomname,
float value) = 0;
/**
* Sets destruction value for all rooms of a building.
* @param id Id of building player
* @param value destruction value. 0: not destroyed, 1: fully destroyed
* @return true if room was found
*/
virtual bool SetBuildingDestructionValue(const std::string &id, float value) = 0;
/**
* Get names of all cameras, loudspeakers and other devices in building
* @param buildingid Id of building player
* @param names will be filled with device names
*/
virtual void GetDeviceNames(const std::string &buildingid, std::vector<std::string> &names) = 0;
/**
* Show an icon at center position of device node
* @param id unique id for entity that can be used to hide it at a later point
* @param buildingid id of building containing the device
* @param devicename name of device node to show icon at
* @param iconpath absolute path to icon to show at device position
* @return true if device was found in building
*/
virtual bool ShowDeviceIcon(const std::string &id, const std::string &buildingid,
const std::string &devicename, const std::string &iconpath) = 0;
/**
* Show an icon at center position of device node
* @param id unique id for entity that can be used to hide it at a later point
* @param buildingid id of building containing the device
* @param position Position of camera relative to building
* @param iconpath absolute path to icon to show at device position
* @return true if device was found in building
*/
virtual bool ShowDeviceIcon(const std::string &id, const std::string &buildingid,
const Vec3d &position, const std::string &iconpath) = 0;
/**
* Hide device icon created with ShowDevice
* @param id Id used in call to ShowDevice
* @return true if device entity was found and successfully removed
*/
virtual bool HideDeviceIcon(const std::string &id) = 0;
/**
* Set the displayName of the given room in a given building
* @param buildingid id of building
* @param roomname
* @param strDisplayName
* @return true if room was found in building
*/
virtual bool SetDisplayName(const std::string& buildingid, const std::string& roomname,
const std::string& strDisplayName) = 0;
/**
* Show the displayName in a given building
* @param buildingid id of building
* @param show set true to show displayNames, false to make invisible
*/
virtual void ShowDisplayNames(const std::string& buildingid, bool show) = 0;
/**
* Add or remove visible bounding box around displayName entity
* @param buildingid unique id of building
* @param id id of room
* @param show set true to show box, false to make invisible
* @param duration If non-negative, remove box after duration seconds
*/
virtual void SetShowDisplayNamesSelectionBox(const std::string& buildingid,
const std::string& id,
bool show,
float duration = -1) = 0;
/**
* Get time scale. Scale 1 is normal, scale 2 is double normal speed
*/
virtual float GetTimeScale() const = 0;
/**
* Scale time. Scale 1 is normal, scale 2 is double normal speed
*/
virtual void SetTimeScale(float scale) = 0;
/**
* Set current simulation time in seconds
*/
virtual void SetSimulationTime(double t) = 0;
/**
* Get current simulation time in seconds
*/
virtual double GetSimulationTime() const = 0;
/**
* Pause simulation time and all events
*/
virtual void SetPaused(bool) = 0;
virtual bool GetPaused() const = 0;
/**
* Switch on or off non realtime mode.
* Non realtime mode is used for recording videos at faster than real time speed.
* Frames are rendered and compressed as fast as possible, simulation time
* does not correspond to real time.
*/
virtual void SetNonRealtimeMode(bool on) = 0;
/**
* Is non-realtime mode on or off?
*/
virtual bool GetNonRealtimeMode() const = 0;
/**
* Advance simulation until given simulation time is reached
*/
virtual void FastForwardSimulationTo(double t) = 0;
/**
* Remove all queued commands for soldiers
*/
virtual void DeleteQueuedCommands() = 0;
/**
* Start recording an mpeg video of the view.
* @param contextid context id of the view to record.
* @param path Record to this file. Extension should be .mpg
* @param w width of recorded video file (input is rescaled)
* @param h height of recorded video file (input is rescaled)
* @param framerate frames per second to record. Reasonable value: 15 - 30
* @param quality Compression quality in percent.
*/
virtual bool StartVideoRecording(unsigned int contextid, const std::string &path,
int w, int h, int framerate, int quality) = 0;
virtual bool StartVideoRecording(const std::string &buildingId, const std::string &path,
int w, int h, int framerate, int quality) = 0;
/**
* Stop recording
* @param contextid context id of the view to record.
*/
virtual bool StopVideoRecording(unsigned int contextid) = 0;
virtual bool StopVideoRecording(const std::string &buildingId) = 0;
virtual QJsonValue getViewState() const = 0;
virtual void setViewState(const QJsonValue &val) = 0;
virtual void highlightView(const std::string &buildingId) = 0;
virtual void setBuildingDisplayName(const std::string &buildingId, const std::string &displayName) = 0;
virtual void setHitLineDuration(uint32_t durationSec) = 0;
struct MountingPointDescription
{
std::string buildingId;
std::string mountingPointId;
Vec3d position;
BuildingViewer::AssetTypes assetType;
};
virtual void setMountingPointAsset(const MountingPointDescription &asset) = 0;
struct BuildingState
{
std::string buildingId;
std::string description;
int entityId = 0;
bool isShown = false;
};
virtual std::vector<BuildingState> getBuildingState() const = 0;
};
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,524 @@
#pragma once
#include "viewerinterface.h"
#include "viewwidgetcontainer.h"
#include <dtEntity/mapcomponent.h>
#include <map>
#include <string>
#include <algorithm>
#include <QPointer>
#include <QWidget>
#include <dtEntity/mapcomponent.h>
#include <dtEntity/core.h>
#include <dtEntity/commandmessages.h>
#include <dtEntity/systemmessages.h>
#include <dtEntity/windowinterface.h>
#include <dtEntityOSG/cameracomponent.h>
#include <dtEntityOSG/layercomponent.h>
#include <dtEntityOSG/positionattitudetransformcomponent.h>
#include <dtEntityOSG/osgsysteminterface.h>
#include <dtEntityOSG/staticmeshcomponent.h>
#include <osg/io_utils>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osg/ComputeBoundsVisitor>
#include <osgViewer/CompositeViewer>
#include "buildingmanager.h"
#include "exccommands.h"
#include "viewwidgetstate.h"
#include "logger.h"
namespace dtEntity
{
class EntityManager;
class MapSystem;
class Message;
}
namespace VCtrl
{
class PlayerSystem;
class BuildingManager;
class ViewWidget;
class LogHandler;
class CtrlMainWindow;
class CtrlImpl : public QObject, public ViewerInterface
{
Q_OBJECT
public:
CtrlImpl(dtEntity::EntityManager &em, QWidget *parentWidget);
~CtrlImpl();
void SetViewerCallback(ViewerCallback *) override;
void RemoveViewerCallback() override;
/**
* Is used to set location of project specific terrain and building data.
* Example: "/home/martin/ProjectAssetsBremen"
*/
void SetProjectDataPaths(const std::vector<std::string> &paths) override;
QWidget* getMainWindow() override;
quintptr requestMainWindowHandle() override;
void openViews(const std::vector<std::string> &bldIds, bool exactPos) override;
bool isViewOpen(const std::string &strBldId) const override;
void closeViews(const std::vector<std::string> &vecFeatureIDs) override;
void closeAllViews();
void UseExactPositioning(bool exactPos) override;
/**
* Open a new display showing the building identified by buildingid.
* @param buildingid ID of the building. Use GetBuildingIds() to get all building ids
* @param windowtitle Title to display on window top
* @param bgcolor Window background color
* @param viewmode The perspective mode to show building in
* @param screennum Number of screen to open display on
* @param fullscreen Ignore width and position and display as fullscreen instead
* @param x X-Position of window
* @param y Y-Position of window
* @param width Width of display in pixels
* @param height Height of display in pixels
* @param contextId receives context ID of the new view. Use it to close the view programmatically.
* @param exactPos true if positioningsystem gets exact position of player
* @return true if success
*/
bool OpenView(const std::string &buildingid, const std::string &windowtitle, const Color &col,
ViewMode viewmode, int screennum,
bool fullscreen, int x, int y, int w, int h, unsigned int &contextid, bool exactPos = true) override;
/**
* Close display previously opened with OpenView
* @param contextid context id of view, as returned from OpenView()
*/
void CloseView(unsigned int contextid) override;
/**
* Change view mode of an existing view.
* @param contextId context id of view, as returned from OpenView()
* @param viewmode Viewmode enum value
*/
void ChangeViewMode(unsigned int contextId, ViewMode viewmode) override;
/**
* Set if view should rotate in accord with map rotation
* @param contextId context id of view, as returned from OpenView()
* @param lock true if view should rotate, false if it should remain static
*/
void LockViewRotationToMapRotation(unsigned int contextId, bool lock) override;
/**
* Set if view should display movable players as dots or as icons
* @param contextId context id of view, as returned from OpenView()
* @param mode Display mode enumerator
*/
void SetPlayerDisplayMode(unsigned int contextId, PlayerDisplayMode mode) override;
/**
* Set wall transparency for a building window.
* @param contextId context id of view, as returned from OpenView()
* @param transparency 0 equals opaque, 1 equals invisible
*/
void SetWallTransparency(unsigned int contextId, float transparency) override;
/**
* All views with "LockViewRotationToMapRotation" enabled will rotate their camera
* to have a camera angle looking towards north, rotated by input angle.
* @returnRotation angle in degrees from north CCW
*/
float GetMapRotation() const override;
/**
* All views with "LockViewRotationToMapRotation" enabled will rotate their camera
* to have a camera angle looking towards north, rotated by input angle.
* @param angle Rotation angle in degrees from north CCW
*/
void SetMapRotation(float angle) override;
/**
* Open 3d view of whole terrain - for debugging purposes only!
*/
void OpenOverview() override;
/**
* add buildings to scene and recalculate navigation meshes
* @param path Load map from this path. example: "Projections/data.xml"
* @param loadAllAvailableBuildings If true, the path variable (=XML file with building configuration) will be ignored)
*/
bool LoadBuildingPositionMap(const std::string &path, bool loadAllAvailableBuildings) override;
void LoadAllBuildings();
/**
* Create new player at (0,0,0). Player is initially invisible!
* @param id a unique string that can later be used to reference the player
* @param iconpath system file path to player icon. Can be relative to ProjectAssets folder root.
* @param color Initial color of the player
*/
void CreatePlayer(const std::string &id, const std::string &iconpath, const Color &color) override;
/**
* Delete player with given id
* @param seconds Delete player n seconds from now
*/
void DeletePlayer(const std::string &id, float seconds = 0) override;
/**
* This color is added to the player texture color.
*/
void SetPlayerColor(const std::string &id, const Color &color) override;
/**
* Set icon path for existing player
* @param path system file path to player icon. Can be relative to ProjectAssets folder root.
* If path is to current icon path then icon is reloaded from file.
*/
void SetPlayerIcon(const std::string &id, const std::string &path) override;
void reloadPlayerIcons() override;
void UpdatePlayerPartyColors(const std::map<std::string, VCtrl::Color>& mapPlayerColors) override;
/**
* Return number of soldier instances
*/
size_t GetNumPlayers() const override;
/**
* Fill vector with ids of all existing players
*/
void GetPlayerIds(std::vector<std::string> &toFill) override;
/**
* Hide or unhide player with given id
* @param show true to show, false to hide
* @param when simulation time when show or hide should be executed
*/
void SetPlayerShown(const std::string &id, bool show, double when = -1) override;
/**
* Return number of building instances
*/
size_t GetNumBuildings() const override;
/**
* Fill vector with ids of all existing buildings
*/
void GetBuildingIds(std::vector<std::string> &toFill) const override;
/**
* Add or remove visible bounding box around entity
* @param id unique id of entity
* @param show set true to show box, false to make invisible
* @param duration If non-negative, remove box after duration seconds
*/
void SetShowSelectionBox(const std::string &id,
bool show,
float duration = -1) override;
/**
* Add a line from start to end
* Line is displayed by an array of sprites, placed
* in equal intervals.
* Sprites move toward target with given speed in m/s
* Line is deleted after duration seconds.
* If duration is 0 then line is never deleted
*/
void Shoot(const int32_t id,
const std::string &shooter,
const std::string &target,
const Vec3d &shooterPos,
const Vec3d &targetPos,
int buildingIdSrc, int roomNumberSrc, int buildingIdDst, int roomNumberDst,
int lineType,
double when) override;
void Shoot(const int32_t id,
const std::string &shooter,
const std::string &targetBuildingId,
const std::string &targetRoomId,
const Vec3d &shooterPos, int lineType,
double when) override;
void removeShoot(const int32_t id) override;
/**
* Directly move player to target position, do not use pathfinding. Cancels current path following activity.
* @param id Id of player
* @param when Simulation time when teleport should happen
* @param target position to teleport to
* @param bldgname name of building containing position, empty string to ignore
* @param roomname name of room containing position, empty string to ignore
*/
void Teleport(const std::string &id,
double when,
const Vec3d &target,
const std::string &bldgname,
int roomNumber,
const std::string &roomname,
ZValue zval) override;
/**
* Get names of all rooms in building
* @param id Id of building player
* @param names will be filled with room names
*/
void GetRoomNames(const std::string &id, std::vector<std::string> &names) override;
/**
* Sets destruction value for room of a building.
* @param id Id of building player
* @param roomnumber number of room to set (ex: "2001")
* @param value destruction value. 0: not destroyed, 1: fully destroyed
* @return true if room was found
*/
bool SetRoomDestructionValue(const std::string &id,
const std::string &roomname,
float value) override;
/**
* Sets destruction value for all rooms of a building.
* @param id Id of building player
* @param value destruction value. 0: not destroyed, 1: fully destroyed
* @return true if room was found
*/
bool SetBuildingDestructionValue(const std::string &id, float value) override;
/**
* Get names of all cameras, loudspeakers and other devices in building
* @param buildingid Id of building player
* @param names will be filled with device names
*/
void GetDeviceNames(const std::string &buildingId, std::vector<std::string> &names) override;
/**
* Show an icon at center position of device node
* @param id unique id for entity that can be used to hide it at a later point
* @param buildingid id of building containing the device
* @param devicename name of device node to show icon at
* @param iconpath absolute path to icon to show at device position
* @return true if device was found in building
*/
bool ShowDeviceIcon(const std::string &id, const std::string &buildingid,
const std::string &devicename, const std::string &iconpath) override;
/**
* Show an icon at center position of device node
* @param id unique id for entity that can be used to hide it at a later point
* @param buildingid id of building containing the device
* @param position Position of camera relative to building
* @param iconpath absolute path to icon to show at device position
* @return true if device was found in building
*/
bool ShowDeviceIcon(const std::string &id, const std::string &buildingid,
const Vec3d &position, const std::string &iconpath) override;
void ChangeLineMode(unsigned int contextId, bool line) override;
void ChangeNameMode(unsigned int contextId, bool name) override;
bool SetDisplayName(const std::string& buildingid, const std::string& roomname, const std::string& strDisplayName) override;
void ShowDisplayNames(const std::string& buildingid, bool show) override;
void SetShowDisplayNamesSelectionBox(const std::string& buildingid, const std::string& id, bool show, float duration = -1) override;
void setHitLineDuration(uint32_t durationSec) override;
void setMountingPointAsset(const MountingPointDescription &asset) override;
std::vector<BuildingState> getBuildingState() const override;
/**
* Hide device icon created with ShowDevice
* @param id Id used in call to ShowDevice
* @return true if device entity was found and successfully removed
*/
bool HideDeviceIcon(const std::string &id) override;
/**
* Get time scale. Scale 1 is normal, scale 2 is double normal speed
*/
float GetTimeScale() const override;
/**
* Scale time. Scale 1 is normal, scale 2 is double normal speed
*/
void SetTimeScale(float scale) override;
/**
* Set current simulation time in seconds
*/
void SetSimulationTime(double t) override;
/**
* Get current simulation time in seconds
*/
double GetSimulationTime() const override;
/**
* Pause simulation time and all events
*/
void SetPaused(bool) override;
/**
* Is simulation currently paused?
*/
bool GetPaused() const override;
/**
* Advance simulation until given simulation time is reached
*/
void FastForwardSimulationTo(double t) override;
/**
* Remove all queued commands for soldiers
*/
void DeleteQueuedCommands() override;
/**
* Switch on or off non realtime mode.
* Non realtime mode is used for recording videos at faster than real time speed.
* Frames are rendered and compressed as fast as possible, simulation time
* does not correspond to real time.
*/
void SetNonRealtimeMode(bool on) override;
/**
* Is non-realtime mode on or off?
*/
bool GetNonRealtimeMode() const override;
/**
* Start recording an mpeg video of the view.
* @param contextid context id of the view to record.
* @param path Record to this file. Extension should be .mpg
* @param w width of recorded video file (input is rescaled)
* @param h height of recorded video file (input is rescaled)
* @param framerate frames per second to record. Reasonable value: 15 - 30
* @param quality Compression quality in percent.
*/
bool StartVideoRecording(unsigned int contextid, const std::string &path,
int w, int h, int framerate, int quality) override;
bool StartVideoRecording(const std::string &buildingId, const std::string &path,
int w, int h, int framerate, int quality) override;
/**
* Stop recording
* @param contextid context id of the view to record.
*/
bool StopVideoRecording(unsigned int contextid) override;
bool StopVideoRecording(const std::string &buildingId) override;
void setTransparency(double percent) override;
void setViewMode(ViewMode m) override;
void setDisplayMode(PlayerDisplayMode m) override;
int GetFrameRate() const { return mFrameRate; }
void OnShowMsgBox(const std::string &strText);
bool allViewWindowsExposed() const
{
for (auto *vw : m_openedViewWidgets.getViewWidgets())
{
if (!vw->isOpenGlWindowExposed())
return false;
}
return !m_openedViewWidgets.getViewWidgets().empty();
}
private:
bool open(const std::string& strFeatureID, bool exactPos);
bool open(const std::vector<std::string> &vecFeatureIDs, bool exactPos);
bool openAll(bool exactPos);
void onEXCOpen(const QString& strIDs, bool exactPos);
void onEXCClose(const QString& strIDs);
void convertAssetsToPngFiles();
void OnTransformSend(const dtEntity::Message &m);
void OnMapLoaded(const dtEntity::Message &m);
void OnMapUnloaded(const dtEntity::Message &m);
void OnNavMeshGroupChanged(const dtEntity::Message &m);
void OnPlayerPicked(const dtEntity::Message &m);
void OnHideSelection(const dtEntity::Message &m);
//void OnRemoveShoot(const dtEntity::Message &m);
void OnShoot(const dtEntity::Message &m);
void OnShowHidePlayer(const dtEntity::Message &m);
void OnDisplayNameClicked(const dtEntity::Message& m);
bool SpawnBuilding(const BuildingData &b, bool useStaticMeshesFolder = true);
void LoadBuilding(BuildingData& bd, bool useStaticMeshesFolder);
void deleteAllBuildings();
bool getBuildingString(const std::string &strFeatureID, std::string *strBuildingNameID);
bool OpenView(unsigned int contextId);
bool CreateView(dtEntity::EntityId bid, const std::string &windowtitle, const Color &col, ViewMode viewmode,
int screennum, bool fullscreen, int x, int y, int w, int h,
unsigned int &contextid, bool exactPos);
QPointer<CtrlMainWindow> m_pMainWindow;
dtEntity::EntityManager *mEntityManager;
ViewerCallback *mViewerCallback;
LogHandler* mLogHandler = nullptr;
dtEntity::MapSystem *mMapSystem;
PlayerSystem *mPlayerSystem;
BuildingManager *mBuildingManager;
float mTimeScale;
double mSimTime;
bool mPaused;
bool mNonRealtimeMode;
int mFrameRate; // only for non realtime mode
std::map<unsigned int, ViewWidget *> mViewWidgets; // contextIDs to ViewWidgets
ViewWidget *GetViewWidget(unsigned int contextid);
void storeWidget(ViewWidget *pWidget, const std::string &strBuildingNameID, unsigned int contextid, VCtrl::ViewMode vmode, VCtrl::PlayerDisplayMode displayMode);
const std::size_t m_maxParallelViewWidgets = 8;
// Global setting for all ViewWidgets
unsigned int m_hitlineDuration_s = 10;
double m_desiredTransparencyValue = 0.75;
bool m_showHitLines = true;
ViewWidget *CreateMainWindowView(dtEntity::EntityId bid, const std::string &featureId, unsigned int &contextid, bool exactPos);
std::unordered_map<std::string, BuildingData> m_loadedBuildings; // Feature_IDs
ViewWidgetContainer m_openedViewWidgets;
bool m_isInFullscreenMode = false;
// Global Settings valid for all newly opened widgets
ViewMode m_desiredViewMode = ViewMode::ORTHOGRAPHIC;
VCtrl::PlayerDisplayMode m_desiredPlayerDisplayMode = VCtrl::PlayerDisplayMode::Icons;
void CloseView(ViewWidget *pWidget);
void onExcRestoreViewState(const std::string &strFeatureID);
void restoreViewWidgetStates(const std::vector<BuildingViewer::ViewWidgetState> &vecStates);
void restoreViewWidgetStateDeferred(ViewWidget *pViewWidget);
std::unordered_map<std::string, BuildingViewer::ViewWidgetState> m_deferredViewStates;
QJsonValue getViewState() const override;
void setViewState(const QJsonValue &val) override;
void highlightView(const std::string &buildingId) override;
void setBuildingDisplayName(const std::string &buildingId, const std::string &displayName) override;
//NGL::INGLLogger &m_logger;
private slots:
void onViewWidget_MaximizeRequest(ViewWidget *pWidget);
void onViewWidget_MinimizeRequest(ViewWidget *pWidget);
void onViewWidget_CloseRequest(ViewWidget *pWidget);
void onViewWidget_FocusRequest(ViewWidget *pWidget);
void onViewWidget_Zoom(ViewWidget *pWidget, bool zoomIn);
};
}
@@ -0,0 +1,149 @@
#include "viewermainwindow.h"
#include "viewwidget.h"
#include "viewerinterfaceimpl.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
TransparencyDialog::TransparencyDialog(QWidget *parent)
: QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint)
{
setWindowTitle(tr("BgViewer - Set Global Transparency"));
auto plabel = new QLabel(tr("Set transparency value:"));
m_pSlider = new QSlider(Qt::Horizontal);
m_pSlider->setMinimum(0);
m_pSlider->setMaximum(100);
m_pSlider->setValue(50);
m_pSlider->setMinimumWidth(200);
auto pButton = new QPushButton(tr("Apply"));
connect(pButton, &QPushButton::clicked, this, &VCtrl::TransparencyDialog::accept);
auto pLayout = new QHBoxLayout(this);
pLayout->addWidget(plabel);
pLayout->addWidget(m_pSlider);
pLayout->addWidget(pButton);
pLayout->setSizeConstraint(QLayout::SetFixedSize);
}
////////////////////////////////////////////////////////////////////////////////
CtrlMainWindow::CtrlMainWindow(QWidget *parent)
: QWidget(parent)
{
connect(&m_highlighterTimer, &QTimer::timeout,
this, &CtrlMainWindow::onHighlighterTimerTimeout);
setWindowTitle(tr("BgViewer"));
// Remove minimize/maximize and close button
setWindowFlags(Qt::Window | Qt::CustomizeWindowHint);
new QGridLayout(this);
}
////////////////////////////////////////////////////////////////////////////////
void CtrlMainWindow::updateHighlightThreads(ViewWidget *pWidget)
{
m_highlighterCounter[pWidget] = 6;
if (!m_highlighterTimer.isActive())
m_highlighterTimer.start(500);
}
////////////////////////////////////////////////////////////////////////////////
void CtrlMainWindow::onHighlighterTimerTimeout()
{
auto it = m_highlighterCounter.begin();
while (it != m_highlighterCounter.end())
{
ViewWidget *ww = it.key();
ww->highlightBorder(it.value() % 2 == 0);
it.value() = it.value() - 1;
if (it.value() <= 0)
it = m_highlighterCounter.erase(it);
else
++it;
}
if (m_highlighterCounter.isEmpty())
m_highlighterTimer.stop();
}
////////////////////////////////////////////////////////////////////////////////
void CtrlMainWindow::openView(ViewWidget *pViewWidget)
{
openViews({pViewWidget});
}
////////////////////////////////////////////////////////////////////////////////
void CtrlMainWindow::openViews(const std::vector<ViewWidget *> &vecMainWindowSubWidgets)
{
constexpr int maxViewsPerCol = 4;
// Append where we stopped last time
QGridLayout *gridLayout = static_cast<QGridLayout *>(layout());
int row = gridLayout->count() / maxViewsPerCol, col = gridLayout->count() % maxViewsPerCol;
// Add all requested ViewWidgets which are actually new
for (auto &pWidget : vecMainWindowSubWidgets)
{
auto itm = gridLayout->itemAtPosition(row, col);
if (itm && itm->widget() == pWidget)
continue;
gridLayout->addWidget(pWidget, row, col);
pWidget->show();
if (++col >= maxViewsPerCol)
{
col = 0;
++row;
}
}
}
void CtrlMainWindow::closeView(ViewWidget *pViewWidget)
{
if (!pViewWidget)
return;
QGridLayout *gridLayout = dynamic_cast<QGridLayout *>(layout());
std::vector<ViewWidget*> currentViews;
currentViews.reserve(gridLayout->count());
for (int idx = 0; idx < gridLayout->count(); idx++)
{
QLayoutItem *item = gridLayout->itemAt(idx);
ViewWidget *vw = static_cast<ViewWidget*>(item->widget());
if (vw != pViewWidget)
currentViews.push_back(vw);
}
m_highlighterCounter.remove(pViewWidget);
pViewWidget->close();
delete gridLayout;
setLayout(new QGridLayout);
openViews(currentViews);
}
////////////////////////////////////////////////////////////////////////////////
void CtrlMainWindow::clearGridLayout()
{
QGridLayout *gridLayout = dynamic_cast<QGridLayout *>(layout());
for (int idx = 0; idx < gridLayout->count(); idx++)
{
QLayoutItem *item = gridLayout->itemAt(idx);
item->widget()->hide();
}
m_highlighterCounter.clear();
delete gridLayout;
setLayout(new QGridLayout);
}
}
@@ -0,0 +1,54 @@
#ifndef VCTRL_CTRLMAINWINDOW_H
#define VCTRL_CTRLMAINWINDOW_H
#include <QDialog>
#include <QSlider>
#include <QTimer>
#include <QHash>
#include "viewerinterface.h"
namespace VCtrl
{
class TransparencyDialog final : public QDialog
{
Q_OBJECT
public:
TransparencyDialog(QWidget *parent = nullptr);
double getTransparencyValue() const
{
return m_pSlider->value() / 100.0;
}
private:
QSlider *m_pSlider;
};
class ViewWidget;
class CtrlImpl;
class CtrlMainWindow final : public QWidget
{
Q_OBJECT
public:
explicit CtrlMainWindow(QWidget *parent);
void openView(ViewWidget *pViewWidget);
void openViews(const std::vector<ViewWidget *> &vecMainWindowSubWidgets);
void closeView(ViewWidget *pViewWidget);
void updateHighlightThreads(ViewWidget *pWidget);
void clearGridLayout();
private:
void onHighlighterTimerTimeout();
private:
QTimer m_highlighterTimer;
QHash<ViewWidget *, int> m_highlighterCounter;
};
}
#endif // VCTRL_CTRLMAINWINDOW_H
@@ -0,0 +1,390 @@
#include "viewwidget.h"
#include "viewwidgetstate.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QEvent>
#include <QGLWidget>
#include <QWindow>
#include <dtEntity/log.h>
namespace BuildingViewer
{
ViewWidgetState::ViewWidgetState(VCtrl::ViewWidget* pView)
: m_featureID(pView->featureID())
, m_usedTransparencyValue(pView->transparency())
, m_windowWidth(pView->accessView()->width())
, m_windowHeight(pView->accessView()->height())
, m_lockActive(pView->lockedRotation())
, m_dotsActive(pView->dotModeActive())
, m_isMaximized(pView->isMaximized())
, m_namesActive(pView->nameModeActive())
, m_usesOrtho(pView->viewMode() == VCtrl::ViewMode::ORTHOGRAPHIC)
, m_usesExactPos(pView->exactPos())
{}
}
namespace VCtrl
{
const QColor ViewWidget::ColorBorder = QColor(48, 136, 209);
const QColor ViewWidget::ColorSelected = QColor(90, 200, 255);
const QColor ViewWidget::ColorHighlighted = Qt::green;
////////////////////////////////////////////////////////////////////////////////
ViewWidget::ViewWidget(unsigned int contextid, dtEntity::EntityId bid, const std::string &strFeatureID, bool usesExactPos, QWidget *parent)
: QFrame(parent),
m_locked(false),
m_useDotMode(false),
m_entityID(bid),
m_featureID(strFeatureID),
mContextId(contextid),
m_usesExactPos(usesExactPos),
mViewerInterface(nullptr),
mClosedByAPI(false),
m_pView(nullptr)
{
setupUi(this);
m_toolButton_maximize->setIcon(QIcon(QStringLiteral("icon:bgv_view_maximize.svg")));
m_toolButton_close->setIcon(QIcon(QStringLiteral("icon:bgv_view_close.svg")));
m_toolButton_viewmode->setIcon(QIcon(QStringLiteral("icon:bgv_view_iso.svg")));
m_toolButton_dots->setIcon(QIcon(QStringLiteral("icon:bgv_view_symbols.svg")));
m_toolButton_lockRotation->setIcon(QIcon(QStringLiteral("icon:bgv_view_unlock.svg")));
m_toolButton_rooms->setIcon(QIcon(QStringLiteral("icon:bgv_room_edit.svg")));
m_toolButton_viewmode->setChecked(m_viewmode != ViewMode::ISOMETRIC);
m_toolButton_dots->setChecked(m_useDotMode);
m_toolButton_lockRotation->setChecked(m_locked);
m_toolButton_ZoomOut->setIcon(QIcon(QStringLiteral("icon:bgv_zoom_out.svg")));
m_toolButton_ZoomIn->setIcon(QIcon(QStringLiteral("icon:bgv_zoom_in.svg")));
QIcon iconT(QStringLiteral("icon:bgv_transparency.svg"));
QPixmap image(iconT.pixmap(30,30));
m_label_transparency->setPixmap(image);
connect(m_toolButton_viewmode, &QToolButton::clicked, this, &ViewWidget::viewModeChanged);
connect(_transparency, &QSlider::valueChanged, this, &ViewWidget::transparencyChanged);
connect(m_toolButton_lockRotation, &QToolButton::clicked, this, &ViewWidget::lockRotationToggled);
connect(m_toolButton_dots, &QToolButton::clicked, this, &ViewWidget::dotModeToggled);
connect(m_toolButton_rooms, &QToolButton::clicked, this, &ViewWidget::nameModeToggled);
connect(m_toolButton_more, &QToolButton::clicked, this, &ViewWidget::slotShowMore);
connect(m_toolButton_maximize, &QToolButton::clicked, this, &ViewWidget::OnButtonMaximize);
connect(m_toolButton_close, &QToolButton::clicked, this, &ViewWidget::OnButtonClose);
connect(m_toolButton_ZoomOut, &QToolButton::clicked, this, [this](){
emit signal_Zoom(this, false);
});
connect(m_toolButton_ZoomIn, &QToolButton::clicked, this, [this](){
emit signal_Zoom(this, true);
});
m_toolButton_maximize->setEnabled(true);
setSelected(false);
setMouseTracking(true); // Otherwise ViewWidget::mouseMoveEvent would not receive any events
slotShowMore(false);
}
void ViewWidget::highlightBorder(bool highlight)
{
if (highlight)
drawBorder(ColorHighlighted);
else
drawBorder(isSelected() ? ColorSelected : ColorBorder);
}
void ViewWidget::dotModeToggled()
{
if (!mViewerInterface) return;
m_useDotMode ^= true;
mViewerInterface->SetPlayerDisplayMode(mContextId, m_useDotMode ? PlayerDisplayMode::Dots : PlayerDisplayMode::Icons);
}
void ViewWidget::drawBorder(const QColor &col)
{
setStyleSheet(QStringLiteral("#ViewWidget { border: 2px solid %1; }").arg(col.name()));
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::closeByAPI()
{
mClosedByAPI = true;
this->close();
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setText(const QString &strText)
{
m_label_description->setText(strText);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::closeEvent(QCloseEvent *e)
{
if (mViewerInterface && !mClosedByAPI)
mViewerInterface->CloseView(mContextId);
QFrame::closeEvent(e);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setDisplayedViewMode(ViewMode vm)
{
if (vm == ViewMode::ORTHOGRAPHIC)
{
m_toolButton_viewmode->setIcon(QIcon(QStringLiteral("icon:bgv_view_iso.svg")));
}
else if (vm == ViewMode::ISOMETRIC)
{
m_toolButton_viewmode->setIcon(QIcon(QStringLiteral("icon:bgv_view_ortho.svg")));
}
m_viewmode = vm;
m_toolButton_viewmode->setChecked(m_viewmode != ViewMode::ISOMETRIC);
m_toolButton_dots->setChecked(m_useDotMode);
m_toolButton_lockRotation->setChecked(m_locked);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::viewModeChanged()
{
if (!mViewerInterface) return;
if (m_viewmode == ViewMode::ORTHOGRAPHIC)
{
m_viewmode = ViewMode::ISOMETRIC;
m_toolButton_viewmode->setIcon(QIcon(QStringLiteral("icon:bgv_view_iso.svg")));
mViewerInterface->ChangeViewMode(mContextId, m_viewmode);
}
else if (m_viewmode == ViewMode::ISOMETRIC)
{
m_viewmode = ViewMode::ORTHOGRAPHIC;
m_toolButton_viewmode->setIcon(QIcon(QStringLiteral("icon:bgv_view_ortho.svg")));
mViewerInterface->ChangeViewMode(mContextId, m_viewmode);
}
m_toolButton_viewmode->setChecked(m_viewmode != ViewMode::ISOMETRIC);
}
bool ViewWidget::isOpenGlWindowExposed() const
{
QGLWidget *gl = qobject_cast<QGLWidget*>(m_pView);
if (!gl || !gl->windowHandle())
return false;
return gl->windowHandle()->isExposed();
}
void ViewWidget::setMaximized(bool maximized)
{
m_toolButton_maximize->setIcon(maximized ?
QIcon(QStringLiteral("icon:bgv_view_minimize.svg")) :
QIcon(QStringLiteral("icon:bgv_view_maximize.svg")));
m_isMaximized = maximized;
}
void ViewWidget::setSelected(bool selected)
{
m_isSelected = selected;
drawBorder(m_isSelected ? ColorSelected : ColorBorder);
}
double ViewWidget::transparency() const {
return static_cast<double>(_transparency->value()) / 100.0;
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setTransparency(float value)
{
_transparency->setValue(qRound(value * 100));
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::transparencyChanged(int v)
{
if (!mViewerInterface) return;
mViewerInterface->SetWallTransparency(mContextId, float(v) / 100.0f);
}
bool ViewWidget::lockedRotation() const
{
return m_locked;
}
bool ViewWidget::dotModeActive() const
{
return m_useDotMode;
}
bool ViewWidget::nameModeActive() const
{
return m_toolButton_rooms->isChecked();
}
ViewMode ViewWidget::viewMode() const {
return m_viewmode;
}
bool ViewWidget::exactPos() const
{
return m_usesExactPos;
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setLockRotationCheckbox(bool v)
{
m_locked = v;
m_toolButton_lockRotation->setIcon(m_locked ?
QIcon(QStringLiteral("icon:bgv_view_lock.svg")) :
QIcon(QStringLiteral("icon:bgv_view_unlock.svg")));
m_toolButton_lockRotation->setChecked(m_locked);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setDotModeCheckbox(bool v)
{
m_useDotMode = v;
m_toolButton_dots->setIcon(m_useDotMode ?
QIcon(QStringLiteral("icon:bgv_view_dots.svg")) :
QIcon(QStringLiteral("icon:bgv_view_symbols.svg")));
m_toolButton_dots->setChecked(m_useDotMode);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setNameModeCheckbox(bool v)
{
m_toolButton_rooms->setChecked(v);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::lockRotationToggled()
{
if (!mViewerInterface) return;
m_locked ^= true;
mViewerInterface->LockViewRotationToMapRotation(mContextId, m_locked);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::slotShowMore(bool v)
{
widget->setVisible(v);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::nameModeToggled(bool v)
{
if(!mViewerInterface) return;
mViewerInterface->ChangeNameMode(mContextId, v);
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::OnButtonMaximize(bool)
{
if (m_isMaximized)
{
emit signal_MinimizeRequest(this);
}
else
{
emit signal_MaximizeRequest(this);
}
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::OnButtonClose(bool)
{
emit signal_CloseRequest(this);
}
QWidget* ViewWidget::accessView()
{
return m_pView;
}
void ViewWidget::mouseMoveEvent(QMouseEvent *event)
{
emit signal_FocusRequest(this);
QFrame::mouseMoveEvent(event);
}
bool ViewWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
emit signal_FocusRequest(this);
if (obj == m_pView && event->type() == QEvent::Show)
emit signal_ViewIsShown(this);
return QFrame::eventFilter(obj, event);
}
void ViewWidget::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
updateTlwTransientParent();
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::setView(QWidget *view)
{
if (m_pView)
{
m_pView->removeEventFilter(this);
layout()->removeWidget(m_pView);
}
m_pView = view;
m_pView->installEventFilter(this);
QVBoxLayout *vLay = qobject_cast<QVBoxLayout*>(layout());
if (!vLay)
{
Q_ASSERT(false);
return;
}
vLay->addWidget(m_pView);
updateTlwTransientParent();
}
////////////////////////////////////////////////////////////////////////////////
void ViewWidget::updateTlwTransientParent()
{
// this is a workaround for Qt < 5.12 which does not set the correct blocking state for
// the toplevel widget where this ViewWidget lives in when there is a model dialog (which
// means all other TLWs are blocked) and a native window (like e.g. QGLWidget) is added as
// a child therefore we have to trigger and update of the blocking state of the complete
// hierarchy to make sure we don't get out of sync. It's fixed in at least 5.12, but could
// not find out the commit / bug report for it. If you want to debug,
// QGuiApplicationPrivate::updateBlockedStatus() is a good starting point for this.
if (QApplication::activeModalWidget())
{
QWidget *tlw = window();
if (tlw && tlw->windowHandle())
tlw->windowHandle()->setTransientParent(tlw->windowHandle()->transientParent());
}
}
}
@@ -0,0 +1,141 @@
#pragma once
#include <QFrame>
#include <QColor>
#include <QWidget>
#include <QDockWidget>
#include "ui_viewwidget.h"
#include "viewerinterface.h"
#include <string>
#include "dtEntity/entityid.h"
namespace osgViewer {
class View;
}
namespace VCtrl
{
class ViewWidget
: public QFrame, // QWidget, (Needs to be QFrame to set border properties such as color)
public Ui::ViewWidget
{
Q_OBJECT
public:
explicit ViewWidget(unsigned int contextid,
dtEntity::EntityId bid = 0,
const std::string &strFeatureID = std::string(),
bool usesExactPos = false,
QWidget *parent = nullptr);
static const QColor ColorBorder;
static const QColor ColorSelected;
static const QColor ColorHighlighted;
void setView(QWidget *view);
QWidget* accessView();
void setText(const QString &strText);
void closeEvent(QCloseEvent *e) override;
void setViewerInterface(ViewerInterface *v) { mViewerInterface = v; }
bool isOpenGlWindowExposed() const;
inline bool isMaximized() const
{
return m_isMaximized;
}
void setMaximized(bool maximized);
void setSelected(bool selected);
inline bool isSelected() const
{
return m_isSelected;
}
inline unsigned int contextID() const
{
return mContextId;
}
inline dtEntity::EntityId entityID() const
{
return m_entityID;
}
inline const std::string featureID() const
{
return m_featureID;
}
inline const std::string description() const
{
return m_label_description->text().toStdString();
}
double transparency() const;
bool lockedRotation() const;
bool dotModeActive() const;
bool nameModeActive() const;
ViewMode viewMode() const;
bool exactPos() const;
signals:
void signal_Zoom(ViewWidget *pWidget, bool zoomIn);
void signal_MaximizeRequest(ViewWidget *pWidget);
void signal_MinimizeRequest(ViewWidget *pWidget);
void signal_CloseRequest(ViewWidget *pWidget);
void signal_FocusRequest(ViewWidget *pWidget);
void signal_ViewIsShown(ViewWidget *pWidget);
public slots:
void setLockRotationCheckbox(bool);
void setDotModeCheckbox(bool);
void setNameModeCheckbox(bool);
void setDisplayedViewMode(ViewMode);
void setTransparency(float value);
void closeByAPI();
void highlightBorder(bool highlight);
protected slots:
void viewModeChanged();
void transparencyChanged(int);
void lockRotationToggled();
void dotModeToggled();
void nameModeToggled(bool);
void slotShowMore(bool);
void OnButtonMaximize(bool);
void OnButtonClose(bool);
private:
void updateTlwTransientParent();
void mouseMoveEvent(QMouseEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
void showEvent(QShowEvent *event) override;
bool m_isMaximized = false;
bool m_isSelected = false;
void drawBorder(const QColor &col);
bool m_locked, m_useDotMode;
ViewMode m_viewmode = ViewMode::ISOMETRIC;
dtEntity::EntityId m_entityID;
std::string m_featureID; // E.g., "House_11" (as specified within the xml files)
unsigned int mContextId;
bool m_usesExactPos;
ViewerInterface *mViewerInterface;
bool mClosedByAPI;
QWidget* m_pView;
};
}
@@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ViewWidget</class>
<widget class="QWidget" name="ViewWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>333</width>
<height>96</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>1</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_label_description">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_dots">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">Dots</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_viewmode">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">Ortho</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_toolButton_more">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">...</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_maximize">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">O</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_close">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">X</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonIconOnly</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>1</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="m_toolButton_lockRotation">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">Lock</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_rooms">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string notr="true">Name</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_ZoomOut">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string>ZOut</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="m_toolButton_ZoomIn">
<property name="minimumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>35</height>
</size>
</property>
<property name="text">
<string>ZoomIn</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_label_transparency">
<property name="text">
<string notr="true">Transparency: </string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="_transparency">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,59 @@
#include "viewwidgetcontainer.h"
#include <cassert>
namespace VCtrl
{
ViewWidget *ViewWidgetContainer::getViewWidget(unsigned int contextID) const
{
for (const auto &pView : m_vecViewWidgets)
{
if (pView->contextID() == contextID)
return pView;
}
return nullptr;
}
void ViewWidgetContainer::add(ViewWidget *pWidget)
{
m_vecViewWidgets.push_back(pWidget);
m_mapFeatureID_To_ViewWidget[pWidget->featureID()] = pWidget;
connect(pWidget, &QObject::destroyed, this, &ViewWidgetContainer::onWidgetDestroyed);
}
void ViewWidgetContainer::remove(const std::string &featureID)
{
auto it = m_mapFeatureID_To_ViewWidget.find(featureID);
if (it != m_mapFeatureID_To_ViewWidget.end())
{
ViewWidget *pWidget = it->second;
auto vecIt = std::find(m_vecViewWidgets.begin(), m_vecViewWidgets.end(), pWidget);
if (vecIt != m_vecViewWidgets.end())
m_vecViewWidgets.erase(vecIt);
m_mapFeatureID_To_ViewWidget.erase(it);
assert(m_vecViewWidgets.size() == m_mapFeatureID_To_ViewWidget.size());
}
}
void ViewWidgetContainer::onWidgetDestroyed(QObject *obj)
{
ViewWidget *pWidget = static_cast<ViewWidget*>(obj);
auto vecIt = std::find(m_vecViewWidgets.begin(), m_vecViewWidgets.end(), pWidget);
if (vecIt != m_vecViewWidgets.end())
m_vecViewWidgets.erase(vecIt);
for (auto it = m_mapFeatureID_To_ViewWidget.begin(); it != m_mapFeatureID_To_ViewWidget.end(); ++it)
{
if (it->second == pWidget)
{
m_mapFeatureID_To_ViewWidget.erase(it);
break;
}
}
}
}
@@ -0,0 +1,55 @@
#pragma once
#include <map>
#include <vector>
#include <string>
#include "viewwidget.h"
namespace VCtrl
{
class ViewWidgetContainer : public QObject
{
Q_OBJECT
public:
void add(ViewWidget *pWidget);
void remove(const std::string &featureID);
void clear()
{
m_vecViewWidgets.clear();
m_mapFeatureID_To_ViewWidget.clear();
}
bool exist(const std::string &featureID) const
{
return (m_mapFeatureID_To_ViewWidget.find(featureID) != m_mapFeatureID_To_ViewWidget.end());
}
ViewWidget *getViewWidget(const std::string &featureID) const
{
return exist(featureID) ? m_mapFeatureID_To_ViewWidget.at(featureID) : nullptr;
}
ViewWidget *getViewWidget(unsigned int contextID) const;
const std::vector<ViewWidget*> &getViewWidgets() const
{
return m_vecViewWidgets;
}
std::size_t size() const
{
return m_vecViewWidgets.size();
}
private Q_SLOTS:
void onWidgetDestroyed(QObject *obj);
private:
// Both containers will always have same size
std::vector<ViewWidget *> m_vecViewWidgets; // Keeps track of the ViewWidget ordering (used for the gridlayout)
std::map<std::string, ViewWidget *> m_mapFeatureID_To_ViewWidget; // Keeps track about the currently used FeatureIDs (respectively opened ViewWidgets)
};
}
@@ -0,0 +1,74 @@
#pragma once
#include <string>
#include <QString>
#include <QJsonObject>
#include "cameraviewposition.h"
namespace VCtrl
{
class ViewWidget;
}
namespace BuildingViewer
{
class ViewWidgetState
{
public:
explicit ViewWidgetState(VCtrl::ViewWidget *pView);
explicit ViewWidgetState(const QJsonObject &jsonObj)
{
m_featureID = jsonObj[QStringLiteral("featureID")].toString().toStdString();
m_usedTransparencyValue = jsonObj[QStringLiteral("usedTransparencyValue")].toDouble();
m_posCamera.m_top = jsonObj[QStringLiteral("posCameraTop")].toDouble();
m_posCamera.m_left = jsonObj[QStringLiteral("posCameraLeft")].toDouble();
m_posCamera.m_bottom = jsonObj[QStringLiteral("posCameraBottom")].toDouble();
m_posCamera.m_right = jsonObj[QStringLiteral("posCameraRight")].toDouble();
m_windowWidth = jsonObj[QStringLiteral("windowWidth")].toInt();
m_windowHeight = jsonObj[QStringLiteral("windowHeight")].toInt();
m_usesExactPos = jsonObj[QStringLiteral("usesExactPos")].toBool();
m_lockActive = jsonObj[QStringLiteral("lockActive")].toBool();
m_dotsActive = jsonObj[QStringLiteral("dotsActive")].toBool();
m_isMaximized = jsonObj[QStringLiteral("isMaximized")].toBool();
m_namesActive = jsonObj[QStringLiteral("namesActive")].toBool();
m_usesOrtho = jsonObj[QStringLiteral("usesOrtho")].toBool();
}
QJsonObject toJson() const
{
return {
{QStringLiteral("featureID"), QString::fromStdString(m_featureID)},
{QStringLiteral("usedTransparencyValue"), m_usedTransparencyValue},
{QStringLiteral("posCameraTop"), m_posCamera.m_top},
{QStringLiteral("posCameraLeft"), m_posCamera.m_left},
{QStringLiteral("posCameraBottom"), m_posCamera.m_bottom},
{QStringLiteral("posCameraRight"), m_posCamera.m_right},
{QStringLiteral("windowWidth"), m_windowWidth},
{QStringLiteral("windowHeight"), m_windowHeight},
{QStringLiteral("usesExactPos"), m_usesExactPos},
{QStringLiteral("lockActive"), m_lockActive},
{QStringLiteral("dotsActive"), m_dotsActive},
{QStringLiteral("namesActive"), m_namesActive},
{QStringLiteral("isMaximized"), m_isMaximized},
{QStringLiteral("usesOrtho"), m_usesOrtho},
};
}
std::string m_featureID; // We use featureID (manual string description of a building) since contextID may differ/change depending on implementation
double m_usedTransparencyValue = 0.0;
BuildingViewer::CameraViewPosition m_posCamera;
int m_windowWidth = -1, m_windowHeight = -1;
bool m_lockActive = false;
bool m_dotsActive = false;
bool m_isMaximized = false;
bool m_namesActive = false;
bool m_usesOrtho = false;
bool m_usesExactPos = false;
};
}
@@ -0,0 +1,180 @@
#include "visitors.h"
#include <dtEntity/property.h>
#include <osg/Material>
#include <osg/BlendFunc>
#include <osg/BlendColor>
#include <QStringRef>
#include <QVector>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////
void FindByNameVisitor::apply(osg::Node &node)
{
const QString grpName(QString::fromStdString(node.getName()));
if (grpName.contains(mName, Qt::CaseInsensitive))
mNodes.push_back(&node);
traverse(node);
}
////////////////////////////////////////////////////////////////////////////
void FindExactNameVisitor::apply(osg::Node &node)
{
auto it = mNamesToSearch.find(node.getName());
if (it != mNamesToSearch.end())
{
mNamesToSearch.erase(it);
mNodes.push_back(&node);
}
if (mNamesToSearch.size())
traverse(node);
}
////////////////////////////////////////////////////////////////////////////
void FindRoomNamesVisitor::apply(osg::Node &n)
{
const std::string &nm = n.getName();
if (nm.size() > 8 && nm.substr(0, 8) == "SW_room_")
{
if (n.getNumDescriptions() > 0)
{
std::string desc = n.getDescription(0);
size_t pos = desc.find('@');
if (pos != std::string::npos)
mNames.push_back(desc.substr(pos + 1, desc.size()));
}
else
{
std::string roomName = "2" + nm.substr(8, nm.size());
mNames.push_back(roomName);
std::vector<std::string> descList;
descList.push_back(nm + "@" + roomName);
n.setDescriptions(descList);
}
}
traverse(n);
}
////////////////////////////////////////////////////////////////////////////
void ClearVertexColorsVisitor::apply(osg::Geode &geode)
{
for (unsigned int i = 0; i < geode.getNumDrawables(); ++i)
{
osg::Geometry *geo = geode.getDrawable(i)->asGeometry();
if (geo && geo->getColorArray() != nullptr)
{
geo->setColorArray(nullptr);
geo->setColorBinding(osg::Geometry::BIND_OFF);
}
}
traverse(geode);
}
////////////////////////////////////////////////////////////////////////////
void SplitVisitor::apply(osg::Group &node)
{
static const std::string floorPrefix("floor_");
const std::string &nodename = node.getName();
if (nodename.size() >= floorPrefix.size() &&
std::equal(floorPrefix.begin(), floorPrefix.end(), nodename.begin()))
{
_parts.emplace_back(&node);
float h = 0;
for (unsigned int i = 0; i < node.getNumDescriptions(); ++i)
{
QString descr = QString::fromStdString(node.getDescription(i));
const QVector<QStringRef> descprt = descr.splitRef(QLatin1Char(';'));
for (const QStringRef &prt : descprt)
{
const QVector<QStringRef> items = prt.split(QLatin1Char('='));
if (items.size() == 2 && items[0] == QLatin1String("base_height"))
h = items[1].toFloat();
}
}
_heights.push_back(h);
}
traverse(node);
}
////////////////////////////////////////////////////////////////////////////
void FindRoomComponentsVisitor::apply(osg::Group &node)
{
static const std::string roomPrefix("undest_room_");
const std::string &nodename = node.getName();
if (nodename.size() >= roomPrefix.size() &&
std::equal(roomPrefix.begin(), roomPrefix.end(), nodename.begin()))
{
//parts.push_back(&node);
//float h = 0;
for (unsigned int i = 0; i < node.getNumDescriptions(); ++i)
{
const std::string &descr = node.getDescription(i);
std::istringstream f(descr);
std::string s;
while (getline(f, s, ';'))
{
if (s.size() != 0)
mNamesFound.insert(s);
}
}
}
traverse(node);
}
////////////////////////////////////////////////////////////////////////////
void FindRoomByNumberVisitor::apply(osg::Node &searchNode)
{
if (searchNode.getNumDescriptions() > 0)
{
const std::string &desc = searchNode.getDescription(0);
size_t pos = desc.find('@');
if (pos != std::string::npos && desc.substr(pos + 1, desc.size()) == searchForName)
foundNodeList.push_back(&searchNode);
}
traverse(searchNode);
}
////////////////////////////////////////////////////////////////////////////
void SetWallsTransparentVisitor::SetAlpha(osg::Node *node, float alpha)
{
node->setNodeMask(0xFFFFFFFF);
osg::StateSet *ss = node->getOrCreateStateSet();
if (alpha > 0.99f)
{
ss->removeMode(GL_BLEND);
ss->setRenderingHint(osg::StateSet::DEFAULT_BIN);
/*osg::Material* mat = new osg::Material();
mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
ss->setAttributeAndModes(mat, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
mat->setAlpha(osg::Material::FRONT_AND_BACK, 1);*/
ss->removeUniform("wall_color");
}
else if (alpha < 0.01f)
node->setNodeMask(0x0);
else
{
ss->setMode(GL_BLEND, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
osg::BlendFunc *bf = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
ss->setAttributeAndModes(bf, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
ss->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
ss->addUniform(new osg::Uniform("wall_color", osg::Vec4(1, 1, 1, alpha)));
}
}
////////////////////////////////////////////////////////////////////////////
void SetWallsTransparentVisitor::apply(osg::Node &node)
{
std::string nm = node.getName();
if (nm.size() > 4 && nm.substr(0, 4) == "wall")
SetAlpha(&node, mTransparency);
traverse(node);
}
}
@@ -0,0 +1,169 @@
#pragma once
#include <osg/Group>
#include <osg/NodeVisitor>
#include <osg/Geode>
#include <osg/Geometry>
#include <QtCore/QString>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
class FindByNameVisitor final : public osg::NodeVisitor
{
public:
std::vector<osg::Node *> mNodes;
QString mName;
explicit FindByNameVisitor(const QString &name)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mName(name)
{}
void apply(osg::Node &node) override;
};
////////////////////////////////////////////////////////////////////////////
class FindExactNameVisitor final : public osg::NodeVisitor
{
public:
std::vector<osg::Node *> mNodes;
std::set<std::string> mNamesToSearch;
explicit FindExactNameVisitor(const std::set<std::string> &namesToSearch)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mNamesToSearch(namesToSearch)
{}
void apply(osg::Node &node) override;
};
////////////////////////////////////////////////////////////////////////////
class SplitVisitor final : public osg::NodeVisitor
{
public:
std::vector<osg::ref_ptr<osg::Node> > _parts;
std::vector<float> _heights;
SplitVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
void apply(osg::Group &node) override;
};
////////////////////////////////////////////////////////////////////////////////
class FindRoomComponentsVisitor final : public osg::NodeVisitor
{
public:
std::set<std::string> mNamesFound;
FindRoomComponentsVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
void apply(osg::Group &node) override;
};
////////////////////////////////////////////////////////////////////////////////
class FindRoomNamesVisitor final : public osg::NodeVisitor
{
public:
std::vector<std::string> mNames;
// Default constructor - initialize searchForName to "" and
// set the traversal mode to TRAVERSE_ALL_CHILDREN
FindRoomNamesVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{}
void apply(osg::Node &n) override;
};
////////////////////////////////////////////////////////////////////////////////
class FindRoomByNumberVisitor final : public osg::NodeVisitor
{
public:
// Default constructor - initialize searchForName to "" and
// set the traversal mode to TRAVERSE_ALL_CHILDREN
FindRoomByNumberVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
searchForName()
{}
// Constructor that accepts string argument
// Initializes searchForName to user string
// set the traversal mode to TRAVERSE_ALL_CHILDREN
explicit FindRoomByNumberVisitor(const std::string &searchName) :
osg::NodeVisitor(TRAVERSE_ALL_CHILDREN),
searchForName(searchName)
{
}
void apply(osg::Node &searchNode) override;
// Set the searchForName to user-defined string
void setNameToFind(const std::string &searchName)
{
searchForName = searchName;
foundNodeList.clear();
}
// Return a pointer to the first node in the list
// with a matching name
osg::Node *getFirst()
{
return *(foundNodeList.begin());
}
// typedef a vector of node pointers for convenience
using NodeList = std::vector<osg::Node *>;
// return a reference to the list of nodes we found
NodeList &getNodeList() { return foundNodeList; }
private:
// the name we are looking for
std::string searchForName;
// List of nodes with names that match the searchForName string
NodeList foundNodeList;
};
////////////////////////////////////////////////////////////////////////////////
class ClearVertexColorsVisitor final : public osg::NodeVisitor
{
public:
ClearVertexColorsVisitor()
: osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{}
void apply(osg::Geode &geode) override;
};
////////////////////////////////////////////////////////////////////////////////
class SetWallsTransparentVisitor final : public osg::NodeVisitor
{
float mTransparency;
public:
explicit SetWallsTransparentVisitor(float transparency)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mTransparency(transparency)
{
setNodeMaskOverride(0xFFFFFFFF);
}
void SetAlpha(osg::Node *node, float alpha);
void apply(osg::Node &node) override;
};
}
@@ -0,0 +1,338 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial applications,
* as long as this copyright notice is maintained.
*
* This application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/* -*-c++-*-
*
* Copyright (C) 2009 Cedric Pinson
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Cedric Pinson <cedric.pinson@plopbyte.net>
*
*/
#include <osg/RenderInfo>
#include <osg/GL>
#include <osg/GLExtensions>
#include <sstream>
#include "windowcapturecallback.h"
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
#include <dtEntity/property.h>
#include <dtEntity/core.h>
#include <dtEntity/windowinterface.h>
namespace VCtrl
{
////////////////////////////////////////////////////////////////////////////////
void WindowCaptureCallback::operator()(osg::RenderInfo &renderInfo) const
{
glReadBuffer(_readBuffer);
osg::GraphicsContext *gc = renderInfo.getState()->getGraphicsContext();
osg::ref_ptr<ContextData> cd = getContextData(gc);
cd->read();
dtEntity::GetWindowInterface()->RequestRedraw(_contextId);
}
////////////////////////////////////////////////////////////////////////////////
WindowCaptureCallback::WindowCaptureCallback(GLenum readBuffer, unsigned int contextid, const std::string &path, int w, int h, int framerate, int quality):
_readBuffer(readBuffer),
_contextId(contextid),
_filename(path),
_w(w),
_h(h),
_framerate(framerate),
_quality(quality)
{
dtEntity::GetWindowInterface()->RequestRedraw(_contextId);
}
////////////////////////////////////////////////////////////////////////////////
WindowCaptureCallback::ContextData *WindowCaptureCallback::createContextData(osg::GraphicsContext *gc) const
{
return new ContextData(gc, _readBuffer, _filename, _w, _h, _framerate, _quality);
}
////////////////////////////////////////////////////////////////////////////////
WindowCaptureCallback::ContextData *WindowCaptureCallback::getContextData(osg::GraphicsContext *gc) const
{
osg::ref_ptr<ContextData> &data = _contextDataMap[gc];
if (!data) data = createContextData(gc);
return data.get();
}
////////////////////////////////////////////////////////////////////////////////
static gboolean bus_message(GstBus *, GstMessage *message, WindowCaptureCallback *)
{
switch (GST_MESSAGE_TYPE(message))
{
case GST_MESSAGE_WARNING:
{
GError *err = nullptr;
gchar *dbg_info = nullptr;
gst_message_parse_warning(message, &err, &dbg_info);
g_printerr("WARN from element %s: %s\n",
GST_OBJECT_NAME(message->src), err->message);
g_printerr("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
g_error_free(err);
g_free(dbg_info);
break;
}
case GST_MESSAGE_ERROR:
{
GError *err = nullptr;
gchar *dbg_info = nullptr;
gst_message_parse_error(message, &err, &dbg_info);
g_printerr("ERROR from element %s: %s\n",
GST_OBJECT_NAME(message->src), err->message);
g_printerr("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
g_error_free(err);
g_free(dbg_info);
break;
}
#ifdef LTS_DEBUG
case GST_MESSAGE_PROGRESS:
{
GstProgressType type;
gchar *code, *text;
bool in_progress = false;
gst_message_parse_progress (message, &type, &code, &text);
switch (type) {
case GST_PROGRESS_TYPE_START:
case GST_PROGRESS_TYPE_CONTINUE:
in_progress = true;
break;
case GST_PROGRESS_TYPE_COMPLETE:
case GST_PROGRESS_TYPE_CANCELED:
case GST_PROGRESS_TYPE_ERROR:
in_progress = false;
break;
default:
break;
}
g_printerr("Progress: (%s) %s, is in progress: %d\n", code, text, in_progress);
g_free (code);
g_free (text);
break;
}
case GST_MESSAGE_QOS:
{
gboolean live;
guint64 running_time, stream_time, time_stamp, duration;
gst_message_parse_qos(message, &live, &running_time, &stream_time, &time_stamp, &duration);
g_printerr("QOS message: %d, %ld, %ld, %ld, %ld\n", live, running_time, stream_time, time_stamp, duration);
break;
}
case GST_MESSAGE_EOS:
g_printerr("End-Of-Stream received!n");
break;
case GST_MESSAGE_STATE_CHANGED:
{
GstState oldState, newState, pendingState;
gst_message_parse_state_changed(message, &oldState, &newState, &pendingState);
g_printerr("State change from %d to %d (pending: %d)\n", oldState, newState, pendingState);
break;
}
default:
g_printerr("got message %s\n",
gst_message_type_get_name(GST_MESSAGE_TYPE(message)));
break;
#else
default:
g_print("got message %s\n",
gst_message_type_get_name(GST_MESSAGE_TYPE(message)));
break;
#endif
}
return GST_BUS_PASS;
}
////////////////////////////////////////////////////////////////////////////////
WindowCaptureCallback::ContextData::ContextData(osg::GraphicsContext *gc, GLenum readBuffer,
const std::string &path, int w, int h, int framerate, int quality):
_gc(gc),
_readBuffer(readBuffer),
_fileName(path),
_width(0),
_height(0)
{
(void)quality;
_startTick = _previousFrameTick = osg::Timer::instance()->tick();
_pboBuffer.push_back(0);
getSize(gc, _width, _height);
osg::notify(osg::INFO) << this << " Window size " << _width << ", " << _height << std::endl;
GstBus *bus;
/* Initialize GStreamer */
gst_init(nullptr, nullptr);
std::ostringstream gstpipeline;
gstpipeline << "appsrc name=\"inputsrc\" ";
gstpipeline << "! videorate ";
gstpipeline << "! videoscale ";
gstpipeline << "! videoconvert ";
gstpipeline << "! video/x-raw, width=" << w << ", height=" << h << ", framerate=" << framerate << "/1 ";
gstpipeline << "! videoflip method=5 ";
//#define SHOW_DIRECTLY
#ifdef SHOW_DIRECTLY
gstpipeline << "! xvimagesink ";
#else
gstpipeline << " ! vp9enc end-usage=cbr";
gstpipeline << " ! webmmux ";
gstpipeline << " ! filesink location=" << path;
#endif
// g_warning("pipeline: '%s'\n", gstpipeline.str().c_str());
/* Build the pipeline */
_pipeline = gst_parse_launch(gstpipeline.str().c_str(), nullptr);
_app_source = gst_bin_get_by_name((GstBin *) _pipeline, "inputsrc");
bus = gst_pipeline_get_bus(GST_PIPELINE(_pipeline));
g_assert(bus);
gst_bus_add_watch(bus, (GstBusFunc) bus_message, this);
gst_object_unref(bus);
GstCaps *video_caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "RGBA",
"width", G_TYPE_INT, _width,
"height", G_TYPE_INT, _height,
"framerate", GST_TYPE_FRACTION, framerate, 1,
nullptr);
gst_app_src_set_caps(GST_APP_SRC(_app_source), video_caps);
g_object_set(GST_APP_SRC(_app_source), "format", GST_FORMAT_TIME, nullptr);
gst_caps_unref(video_caps);
// make gstreamer more verbose:
g_signal_connect( _pipeline, "deep-notify", G_CALLBACK(gst_object_default_deep_notify ), nullptr );
/* Start playing */
gst_element_set_state(_pipeline, GST_STATE_PLAYING);
}
////////////////////////////////////////////////////////////////////////////////
void WindowCaptureCallback::ContextData::getSize(osg::GraphicsContext *gc, int &width, int &height)
{
if (gc->getTraits())
{
width = gc->getTraits()->width;
height = gc->getTraits()->height;
}
}
////////////////////////////////////////////////////////////////////////////////
void WindowCaptureCallback::ContextData::read()
{
osg::GLExtensions *ext = osg::GLExtensions::Get(_gc->getState()->getContextID(), true);
int width = 0, height = 0;
getSize(_gc, width, height);
if (width != _width || _height != height)
{
osg::notify(osg::INFO) << this << " Window resized " << width << ", " << height << std::endl;
_width = width;
_height = height;
}
unsigned int size = _width * _height * 4;
GLuint &pbo = _pboBuffer[0];
if (pbo == 0)
{
ext->glGenBuffers(1, &pbo);
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
ext->glBufferData(GL_PIXEL_PACK_BUFFER_ARB, size, nullptr, GL_STREAM_READ);
osg::notify(osg::INFO) << this << " Generating pbo " << pbo << std::endl;
}
else
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
osg::Timer_t tick_now = osg::Timer::instance()->tick();
glReadPixels(0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
GLubyte *src = (GLubyte *)ext->glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB,
GL_READ_ONLY_ARB);
if (src)
{
guint64 timestamp = (tick_now - _startTick) * 1000;
guint64 duration = (tick_now - _previousFrameTick) * 1000;
GstBuffer *buffer = gst_buffer_new_allocate(nullptr, size, nullptr);
GstMapInfo info;
gst_buffer_map(buffer, &info, GST_MAP_WRITE);
memcpy(info.data, src, size);
gst_buffer_unmap(buffer, &info);
GST_BUFFER_PTS(buffer) = timestamp;
GST_BUFFER_DTS(buffer) = timestamp;
GST_BUFFER_DURATION(buffer) = duration;
_previousFrameTick = tick_now;
GstFlowReturn ret;
g_signal_emit_by_name(_app_source, "push-buffer", buffer, &ret);
gst_buffer_unref(buffer);
if (ret != GST_FLOW_OK)
{
// some error, stop sending data
GST_DEBUG("some error");
}
ext->glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
}
ext->glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
}
////////////////////////////////////////////////////////////////////////////////
WindowCaptureCallback::ContextData::~ContextData()
{
gboolean ret = gst_element_send_event(_pipeline, gst_event_new_eos());
if (ret)
{
GstMessageType types = GST_MESSAGE_EOS;
GstMessage *msg = gst_bus_timed_pop_filtered(GST_ELEMENT_BUS(_pipeline), GST_CLOCK_TIME_NONE, types);
gst_message_unref(msg);
}
gst_element_set_state(_pipeline, GST_STATE_NULL);
gst_object_unref(_pipeline);
}
}
@@ -0,0 +1,91 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This application is open source and may be redistributed and/or modified
* freely and without restriction, both in commericial and non commericial applications,
* as long as this copyright notice is maintained.
*
* This application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/* -*-c++-*-
*
* Copyright (C) 2009 Cedric Pinson
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Cedric Pinson <cedric.pinson@plopbyte.net>
*
*/
#pragma once
#include <osg/Camera>
// fwd decl for gstreamer objects
struct _GstElement;
namespace VCtrl
{
class WindowCaptureCallback : public osg::Camera::DrawCallback
{
public:
struct ContextData : public osg::Referenced
{
ContextData(osg::GraphicsContext *gc, GLenum readBuffer, const std::string &path, int w, int h, int framerate, int quality);
~ContextData();
static void getSize(osg::GraphicsContext *gc, int &width, int &height);
void read();
osg::GraphicsContext *_gc;
GLenum _readBuffer;
std::string _fileName;
int _width;
int _height;
std::vector< GLuint > _pboBuffer;
osg::Timer_t _previousFrameTick;
osg::Timer_t _startTick;
_GstElement *_pipeline;
_GstElement *_app_source;
};
WindowCaptureCallback(GLenum readBuffer, unsigned int contextid, const std::string &path, int w, int h, int framerate, int quality);
~WindowCaptureCallback() = default;
ContextData *createContextData(osg::GraphicsContext *gc) const;
ContextData *getContextData(osg::GraphicsContext *gc) const;
void operator()(osg::RenderInfo &renderInfo) const override;
using ContextDataMap = std::map<osg::GraphicsContext *, osg::ref_ptr<ContextData> >;
GLenum _readBuffer;
unsigned int _contextId;
std::string _filename;
int _w;
int _h;
int _framerate;
int _quality;
mutable ContextDataMap _contextDataMap;
};
}