From 19d88d17403c3f7a5c36845579d5e25c645c9ff3 Mon Sep 17 00:00:00 2001 From: Mat Sutcliffe Date: Wed, 12 Aug 2020 20:09:23 +0100 Subject: [PATCH] Issue #17 Restore aircraft labels with math and logic cribbed from LiveTraffic's XPMP2 --- .../simulator/xplane/xswiftbustrafficproxy.h | 4 +- src/xswiftbus/datarefs.h | 21 +++-- src/xswiftbus/drawable.h | 10 ++- src/xswiftbus/plugin.cpp | 4 + src/xswiftbus/traffic.cpp | 85 ++++++++++++++++++- src/xswiftbus/traffic.h | 26 +++++- 6 files changed, 134 insertions(+), 16 deletions(-) diff --git a/src/plugins/simulator/xplane/xswiftbustrafficproxy.h b/src/plugins/simulator/xplane/xswiftbustrafficproxy.h index fbd351aa8..39d07a02d 100644 --- a/src/plugins/simulator/xplane/xswiftbustrafficproxy.h +++ b/src/plugins/simulator/xplane/xswiftbustrafficproxy.h @@ -213,10 +213,10 @@ namespace BlackSimPlugin //! \copydoc XSwiftBus::CTraffic::setDefaultIcao void setDefaultIcao(const QString &defaultIcao); - //! deprecated + //! \copydoc XSwiftBus::CTraffic::setDrawingLabels void setDrawingLabels(bool drawing); - //! deprecated + //! \copydoc XSwiftBus::CTraffic::isDrawingLabels bool isDrawingLabels() const; //! \copydoc XSwiftBus::CTraffic::setMaxPlanes diff --git a/src/xswiftbus/datarefs.h b/src/xswiftbus/datarefs.h index 16c226b16..009baecc2 100644 --- a/src/xswiftbus/datarefs.h +++ b/src/xswiftbus/datarefs.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include @@ -65,10 +65,10 @@ namespace XSwiftBus bool isValid() const { return m_ref; } template - void implSetAll(std::vector const &); + void implSetAll(T* const); template - std::vector implGetAll() const; + void implGetAll(T*) const; template void implSetAt(int index, T); @@ -136,11 +136,14 @@ namespace XSwiftBus //! Dataref type using DataRefType = typename DataRefTraits::type; + //! Array dataref size + static constexpr auto DataRefSize = DataRefTraits::size; + //! Set the value of the whole array (if it is writable) - void setAll(std::vector const &a) { static_assert(DataRefTraits::writable, "read-only dataref"); ArrayDataRefImpl::implSetAll(a); } + void setAll(std::array const &a) { static_assert(DataRefTraits::writable, "read-only dataref"); ArrayDataRefImpl::implSetAll(a.data()); } //! Get the value of the whole array - std::vector getAll() const { return ArrayDataRefImpl::implGetAll(); } + std::array getAll() const { std::array result; ArrayDataRefImpl::implGetAll(result.data()); return result; } //! Set the value of a single element (if it is writable) void setAt(int index, DataRefType d) { static_assert(DataRefTraits::writable, "read-only dataref"); ArrayDataRefImpl::implSetAt(index, d); } @@ -218,13 +221,13 @@ namespace XSwiftBus inline double DataRefImpl::implGet() const { return XPLMGetDatad(m_ref); } template <> - inline void ArrayDataRefImpl::implSetAll(std::vector const &v) { assert((int)v.size() <= m_size); XPLMSetDatavi(m_ref, const_cast(&v[0]), 0, (int)v.size()); } + inline void ArrayDataRefImpl::implSetAll(int const *v) { XPLMSetDatavi(m_ref, const_cast(v), 0, m_size); } template <> - inline void ArrayDataRefImpl::implSetAll(std::vector const &v) { assert((int)v.size() <= m_size); XPLMSetDatavf(m_ref, const_cast(&v[0]), 0, (int)v.size()); } + inline void ArrayDataRefImpl::implSetAll(float const *v) { XPLMSetDatavf(m_ref, const_cast(v), 0, m_size); } template <> - inline std::vector ArrayDataRefImpl::implGetAll() const { std::vector v(m_size); XPLMGetDatavi(m_ref, &v[0], 0, m_size); return v; } + inline void ArrayDataRefImpl::implGetAll(int *v) const { XPLMGetDatavi(m_ref, &v[0], 0, m_size); } template <> - inline std::vector ArrayDataRefImpl::implGetAll() const { std::vector v(m_size); XPLMGetDatavf(m_ref, &v[0], 0, m_size); return v; } + inline void ArrayDataRefImpl::implGetAll(float *v) const { XPLMGetDatavf(m_ref, &v[0], 0, m_size); } template <> inline void ArrayDataRefImpl::implSetAt(int i, int d) { assert(i <= m_size); XPLMSetDatavi(m_ref, &d, i, 1); } diff --git a/src/xswiftbus/drawable.h b/src/xswiftbus/drawable.h index d88ba5262..33fc00803 100644 --- a/src/xswiftbus/drawable.h +++ b/src/xswiftbus/drawable.h @@ -28,15 +28,20 @@ namespace XSwiftBus //! Destructor. virtual ~CDrawable() { hide(); } + //! Is currently shown. + bool isVisible() const { return m_visible; } + //! Register the draw callback. void show() { + m_visible = true; XPLMRegisterDrawCallback(callback, m_phase, m_before, static_cast(this)); } //! Unregister the draw callback. void hide() { + m_visible = false; XPLMUnregisterDrawCallback(callback, m_phase, m_before, static_cast(this)); } @@ -51,8 +56,9 @@ namespace XSwiftBus return 1; } - const XPLMDrawingPhase m_phase; - const bool m_before; + XPLMDrawingPhase m_phase; + bool m_before = false; + bool m_visible = false; }; } diff --git a/src/xswiftbus/plugin.cpp b/src/xswiftbus/plugin.cpp index 70a552d1d..13f027da1 100644 --- a/src/xswiftbus/plugin.cpp +++ b/src/xswiftbus/plugin.cpp @@ -31,6 +31,10 @@ namespace XSwiftBus { // m_startServerMenuItem = m_menu.item("Start XSwiftBus", [this]{ startServer(CDBusConnection::SessionBus); }); + m_showHideLabelsMenuItem = m_menu.item("Show/Hide Aircraft Labels", [this] + { + m_traffic->setDrawingLabels(!m_traffic->isDrawingLabels()); + }); m_messageWindowSubMenu = m_menu.subMenu("Message Window"); m_toggleMessageWindowMenuItem = m_messageWindowSubMenu.item("Show/Hide", [this] { diff --git a/src/xswiftbus/traffic.cpp b/src/xswiftbus/traffic.cpp index 3252eab2f..0431dd4bb 100644 --- a/src/xswiftbus/traffic.cpp +++ b/src/xswiftbus/traffic.cpp @@ -65,6 +65,9 @@ namespace XSwiftBus assert(!s_instance); s_instance = this; XPLMRegisterKeySniffer(followAircraftKeySniffer, 1, this); + + // init labels + this->setDrawingLabels(this->getSettings().isDrawingLabels()); } // *INDENT-ON* @@ -257,6 +260,30 @@ namespace XSwiftBus XPMPSetDefaultPlaneICAO(defaultIcao.c_str()); } + void CTraffic::setDrawingLabels(bool drawing) + { + CSettings s = this->getSettings(); + if (s.isDrawingLabels() != drawing) + { + s.setDrawingLabels(drawing); + this->setSettings(s); + } + + if (drawing) + { + m_labels.show(); + } + else + { + m_labels.hide(); + } + } + + bool CTraffic::isDrawingLabels() const + { + return m_labels.isVisible(); + } + void CTraffic::setMaxPlanes(int planes) { CSettings s = this->getSettings(); @@ -581,13 +608,19 @@ namespace XSwiftBus else if (message.getMethodName() == "setDrawingLabels") { maybeSendEmptyDBusReply(wantsReply, sender, serial); - // removed in xpmp2 + bool drawing = true; + message.beginArgumentRead(); + message.getArgument(drawing); + queueDBusCall([ = ]() + { + setDrawingLabels(drawing); + }); } else if (message.getMethodName() == "isDrawingLabels") { queueDBusCall([ = ]() { - sendDBusReply(sender, serial, false); // always false in xpmp2 + sendDBusReply(sender, serial, isDrawingLabels()); }); } else if (message.getMethodName() == "setMaxPlanes") @@ -843,6 +876,7 @@ namespace XSwiftBus void CTraffic::interpolatePosition(Plane *plane) { std::memcpy(&plane->positions[3], &plane->positions[2], sizeof(plane->positions[2])); + return; const auto now = std::chrono::steady_clock::now(); const auto t1 = plane->positionTimes[2] - plane->positionTimes[0]; @@ -879,6 +913,53 @@ namespace XSwiftBus plane->prevSurfacesLerpTime = now; } + void CTraffic::Labels::draw() + { + static const double metersPerFt = 0.3048; + static float color[3]{ 1.0f, 0.75f, 0.0f }; + std::array worldMat = m_worldMat.getAll(); + std::array projMat = m_projMat.getAll(); + double windowWidth = static_cast(m_windowWidth.get()); + double windowHeight = static_cast(m_windowHeight.get()); + XPLMCameraPosition_t camPos {}; + XPLMReadCameraPosition(&camPos); + + for (const auto pair : m_traffic->m_planesById) + { + char *text = const_cast(pair.second->label); + const XPMPPlanePosition_t &planePos = pair.second->positions[3]; + + double worldPos[4]{ 0, 0, 0, 1 }; + double localPos[4]{}; + double windowPos[4]{}; + XPLMWorldToLocal(planePos.lat, planePos.lon, planePos.elevation * metersPerFt, &worldPos[0], &worldPos[1], &worldPos[2]); + matrixMultVec(localPos, worldMat.data(), worldPos); + matrixMultVec(windowPos, projMat.data(), localPos); + + windowPos[3] = 1.0 / windowPos[3]; + windowPos[0] *= windowPos[3]; + windowPos[1] *= windowPos[3]; + windowPos[2] *= windowPos[3]; + + if (windowPos[2] < 0.0 || windowPos[2] > 1.0) + { + continue; // plane is behind camera + } + XPLMDrawString(color, + static_cast(std::lround(windowWidth * (windowPos[0] * 0.5 + 0.5))), + static_cast(std::lround(windowHeight * (windowPos[1] * 0.5 + 0.5))), + text, nullptr, xplmFont_Basic); + } + } + + void CTraffic::Labels::matrixMultVec(double out[4], const float m[16], const double v[4]) + { + out[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + v[3] * m[12]; + out[1] = v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + v[3] * m[13]; + out[2] = v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + v[3] * m[14]; + out[3] = v[0] * m[3] + v[1] * m[7] + v[2] * m[11] + v[3] * m[15]; + } + int CTraffic::orbitPlaneFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon) { constexpr bool DEBUG = false; diff --git a/src/xswiftbus/traffic.h b/src/xswiftbus/traffic.h index 8502e1c02..8737bd8a3 100644 --- a/src/xswiftbus/traffic.h +++ b/src/xswiftbus/traffic.h @@ -16,6 +16,7 @@ #include "command.h" #include "datarefs.h" #include "terrainprobe.h" +#include "drawable.h" #include "menus.h" #include "XPMPMultiplayer.h" #include @@ -74,6 +75,12 @@ namespace XSwiftBus //! Set the ICAO code to use for aircraft without a model match void setDefaultIcao(const std::string &defaultIcao); + //! Set whether the plugin draws type and callsign labels above aircraft + void setDrawingLabels(bool drawing); + + //! Get whether the plugin draws type and callsign labels above aircraft + bool isDrawingLabels() const; + //! Set the maximum number of aircraft. void setMaxPlanes(int planes); @@ -182,6 +189,24 @@ namespace XSwiftBus const std::string &livery_, const std::string &modelName_); }; + //! Label renderer + class Labels : public CDrawable + { + public: + Labels(CTraffic *traffic) : CDrawable(xplm_Phase_Window, false), m_traffic(traffic) {} + protected: + virtual void draw() override; + private: + static void matrixMultVec(double out[4], const float m[16], const double v[4]); + CTraffic *m_traffic = nullptr; + ArrayDataRef m_worldMat; + ArrayDataRef m_projMat; + DataRef m_windowWidth; + DataRef m_windowHeight; + DataRef m_visibilityM; + }; + Labels m_labels { this }; + //! Check functions //! @{ static bool isPlusMinus180(float v); @@ -220,7 +245,6 @@ namespace XSwiftBus CCommand m_followPlaneViewNextCommand; CCommand m_followPlaneViewPreviousCommand; - DataRef m_worldRenderType; DataRef m_ownAircraftPositionX; DataRef m_ownAircraftPositionY; DataRef m_ownAircraftPositionZ;