mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-18 03:15:34 +08:00
Issue #17 Restore aircraft labels with math and logic cribbed from LiveTraffic's XPMP2
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <XPLM/XPLMDataAccess.h>
|
||||
#include <XPLM/XPLMUtilities.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
@@ -65,10 +65,10 @@ namespace XSwiftBus
|
||||
bool isValid() const { return m_ref; }
|
||||
|
||||
template <typename T>
|
||||
void implSetAll(std::vector<T> const &);
|
||||
void implSetAll(T* const);
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> implGetAll() const;
|
||||
void implGetAll(T*) const;
|
||||
|
||||
template <typename T>
|
||||
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<DataRefType> const &a) { static_assert(DataRefTraits::writable, "read-only dataref"); ArrayDataRefImpl::implSetAll(a); }
|
||||
void setAll(std::array<DataRefType, DataRefSize> const &a) { static_assert(DataRefTraits::writable, "read-only dataref"); ArrayDataRefImpl::implSetAll<DataRefType>(a.data()); }
|
||||
|
||||
//! Get the value of the whole array
|
||||
std::vector<DataRefType> getAll() const { return ArrayDataRefImpl::implGetAll<DataRefType>(); }
|
||||
std::array<DataRefType, DataRefSize> getAll() const { std::array<DataRefType, DataRefSize> result; ArrayDataRefImpl::implGetAll<DataRefType>(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<double>() const { return XPLMGetDatad(m_ref); }
|
||||
|
||||
template <>
|
||||
inline void ArrayDataRefImpl::implSetAll<int>(std::vector<int> const &v) { assert((int)v.size() <= m_size); XPLMSetDatavi(m_ref, const_cast<int *>(&v[0]), 0, (int)v.size()); }
|
||||
inline void ArrayDataRefImpl::implSetAll(int const *v) { XPLMSetDatavi(m_ref, const_cast<int *>(v), 0, m_size); }
|
||||
template <>
|
||||
inline void ArrayDataRefImpl::implSetAll<float>(std::vector<float> const &v) { assert((int)v.size() <= m_size); XPLMSetDatavf(m_ref, const_cast<float *>(&v[0]), 0, (int)v.size()); }
|
||||
inline void ArrayDataRefImpl::implSetAll(float const *v) { XPLMSetDatavf(m_ref, const_cast<float *>(v), 0, m_size); }
|
||||
template <>
|
||||
inline std::vector<int> ArrayDataRefImpl::implGetAll<int>() const { std::vector<int> 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<float> ArrayDataRefImpl::implGetAll<float>() const { std::vector<float> 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>(int i, int d) { assert(i <= m_size); XPLMSetDatavi(m_ref, &d, i, 1); }
|
||||
|
||||
@@ -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<void*>(this));
|
||||
}
|
||||
|
||||
//! Unregister the draw callback.
|
||||
void hide()
|
||||
{
|
||||
m_visible = false;
|
||||
XPLMUnregisterDrawCallback(callback, m_phase, m_before, static_cast<void*>(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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
{
|
||||
|
||||
@@ -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<float, 16> worldMat = m_worldMat.getAll();
|
||||
std::array<float, 16> projMat = m_projMat.getAll();
|
||||
double windowWidth = static_cast<double>(m_windowWidth.get());
|
||||
double windowHeight = static_cast<double>(m_windowHeight.get());
|
||||
XPLMCameraPosition_t camPos {};
|
||||
XPLMReadCameraPosition(&camPos);
|
||||
|
||||
for (const auto pair : m_traffic->m_planesById)
|
||||
{
|
||||
char *text = const_cast<char *>(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<int>(std::lround(windowWidth * (windowPos[0] * 0.5 + 0.5))),
|
||||
static_cast<int>(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;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "command.h"
|
||||
#include "datarefs.h"
|
||||
#include "terrainprobe.h"
|
||||
#include "drawable.h"
|
||||
#include "menus.h"
|
||||
#include "XPMPMultiplayer.h"
|
||||
#include <XPLM/XPLMCamera.h>
|
||||
@@ -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<xplane::data::sim::graphics::view::world_matrix> m_worldMat;
|
||||
ArrayDataRef<xplane::data::sim::graphics::view::projection_matrix_3d> m_projMat;
|
||||
DataRef<xplane::data::sim::graphics::view::window_width> m_windowWidth;
|
||||
DataRef<xplane::data::sim::graphics::view::window_height> m_windowHeight;
|
||||
DataRef<xplane::data::sim::graphics::view::visibility_effective_m> 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<xplane::data::sim::graphics::view::world_render_type> m_worldRenderType;
|
||||
DataRef<xplane::data::sim::flightmodel::position::local_x> m_ownAircraftPositionX;
|
||||
DataRef<xplane::data::sim::flightmodel::position::local_y> m_ownAircraftPositionY;
|
||||
DataRef<xplane::data::sim::flightmodel::position::local_z> m_ownAircraftPositionZ;
|
||||
|
||||
Reference in New Issue
Block a user