diff --git a/src/xswiftbus/plugin.cpp b/src/xswiftbus/plugin.cpp index 3cb04d308..f30b3acf0 100644 --- a/src/xswiftbus/plugin.cpp +++ b/src/xswiftbus/plugin.cpp @@ -51,7 +51,10 @@ namespace XSwiftBus m_service->setDisappearMessageWindow(!checked); }); m_planeViewSubMenu = m_menu.subMenu("Follow Plane View"); - planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item("Own Aircraft", [this] { switchToOwnAircraftView(); }); + planeViewOwnAircraftMenuItem = m_planeViewSubMenu.item("Own Aircraft", [this] + { + m_traffic->setFollowedAircraft(m_traffic->ownAircraftString()); + }); /*m_dbusThread = std::thread([this]() { @@ -141,18 +144,6 @@ namespace XSwiftBus INFO_LOG("XSwiftBus started."); } - void CPlugin::switchToOwnAircraftView() - { - /* This is the hotkey callback. First we simulate a joystick press and - * release to put us in 'free view 1'. This guarantees that no panels - * are showing and we are an external view. */ - XPLMCommandButtonPress(xplm_joy_v_fr1); - XPLMCommandButtonRelease(xplm_joy_v_fr1); - - /* Now we control the camera until the view changes. */ - XPLMControlCamera(xplm_ControlCameraUntilViewChanges, orbitOwnAircraftFunc, this); - } - void CPlugin::onAircraftModelChanged() { if (m_service) @@ -190,48 +181,4 @@ namespace XSwiftBus if (plugin->m_traffic) { plugin->m_traffic->process(); } return -1; } - - int CPlugin::orbitOwnAircraftFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon) - { - auto *plugin = static_cast(refcon); - - if (isLosingControl == 1) { return 0; } - - if (cameraPosition) - { - int w, h, x, y; - // First get the screen size and mouse location. We will use this to decide - // what part of the orbit we are in. The mouse will move us up-down and around. - // fixme: In a future update, change the orbit only while right mouse button is pressed. - XPLMGetScreenSize(&w, &h); - XPLMGetMouseLocation(&x, &y); - double heading = 360.0 * static_cast(x) / static_cast(w); - double pitch = 20.0 * ((static_cast(y) / static_cast(h)) * 2.0 - 1.0); - - // Now calculate where the camera should be positioned to be 200 - // meters from the plane and pointing at the plane at the pitch and - // heading we wanted above. - static const double PI = std::acos(-1); - double dx = -50.0 * sin(heading * PI / 180.0); - double dz = 50.0 * cos(heading * PI / 180.0); - double dy = -50.0 * tan(pitch * PI / 180.0); - - double lx, ly, lz; - - lx = plugin->m_ownAircraftPositionX.get(); - ly = plugin->m_ownAircraftPositionY.get(); - lz = plugin->m_ownAircraftPositionZ.get(); - - // Fill out the camera position info. - cameraPosition->x = static_cast(lx + dx); - cameraPosition->y = static_cast(ly + dy); - cameraPosition->z = static_cast(lz + dz); - cameraPosition->pitch = static_cast(pitch); - cameraPosition->heading = static_cast(heading); - cameraPosition->roll = 0; - } - - // Return 1 to indicate we want to keep controlling the camera. - return 1; - } } diff --git a/src/xswiftbus/plugin.h b/src/xswiftbus/plugin.h index 02c3b8536..ca48e1878 100644 --- a/src/xswiftbus/plugin.h +++ b/src/xswiftbus/plugin.h @@ -73,21 +73,15 @@ namespace XSwiftBus CMenu m_planeViewSubMenu; CMenuItem planeViewOwnAircraftMenuItem; - DataRef m_ownAircraftPositionX; - DataRef m_ownAircraftPositionY; - DataRef m_ownAircraftPositionZ; - std::thread m_dbusThread; bool m_isRunning = false; bool m_shouldStop = false; void readConfig(); void startServer(); - void switchToOwnAircraftView(); static float startServerDeferred(float, float, int, void *refcon); static float flightLoopCallback(float, float, int, void *refcon); - static int orbitOwnAircraftFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon); }; } diff --git a/src/xswiftbus/traffic.cpp b/src/xswiftbus/traffic.cpp index 2b59c03a5..bbf8fd274 100644 --- a/src/xswiftbus/traffic.cpp +++ b/src/xswiftbus/traffic.cpp @@ -49,6 +49,7 @@ namespace XSwiftBus m_followPlaneViewPreviousCommand("org/swift-project/xswiftbus/follow_previous_plane", "Changes plane view to follow previous plane in sequence", [this] { followPreviousPlane(); }) { XPLMRegisterDrawCallback(drawCallback, xplm_Phase_Airplanes, 1, this); + XPLMRegisterKeySniffer(spaceKeySniffer, 1, this); } CTraffic::~CTraffic() @@ -133,7 +134,7 @@ namespace XSwiftBus sendDBusMessage(signalPlaneAddingFailed); } - void CTraffic::enableFollowPlaneView(const std::string &callsign) + void CTraffic::switchToFollowPlaneView(const std::string &callsign) { m_followPlaneViewCallsign = callsign; @@ -268,7 +269,7 @@ namespace XSwiftBus m_planesById[id] = plane; // Create view menu item - CMenuItem planeViewMenuItem = m_followPlaneViewSubMenu.item(callsign, [this, callsign] { enableFollowPlaneView(callsign); }); + CMenuItem planeViewMenuItem = m_followPlaneViewSubMenu.item(callsign, [this, callsign] { switchToFollowPlaneView(callsign); }); m_followPlaneViewMenuItems[callsign] = planeViewMenuItem; m_followPlaneViewSequence.push_back(callsign); } @@ -439,10 +440,12 @@ namespace XSwiftBus void CTraffic::setFollowedAircraft(const std::string &callsign) { - auto planeIt = m_planesByCallsign.find(callsign); - if (planeIt == m_planesByCallsign.end()) { return; } - - enableFollowPlaneView(callsign); + if (callsign != ownAircraftString()) + { + auto planeIt = m_planesByCallsign.find(callsign); + if (planeIt == m_planesByCallsign.end()) { return; } + } + switchToFollowPlaneView(callsign); } void CTraffic::dbusDisconnectedHandler() @@ -827,37 +830,59 @@ namespace XSwiftBus if (cameraPosition) { - int w, h, x, y; - // First get the screen size and mouse location. We will use this to decide - // what part of the orbit we are in. The mouse will move us up-down and around. - // fixme: In a future update, change the orbit only while right mouse button is pressed. - XPLMGetScreenSize(&w, &h); - XPLMGetMouseLocation(&x, &y); - double heading = 360.0 * static_cast(x) / static_cast(w); - double pitch = 20.0 * ((static_cast(y) / static_cast(h)) * 2.0 - 1.0); + // Ideally we would like to test against right mouse button, but X-Plane SDK does not + // allow that. + if (traffic->m_isSpacePressed) + { + int w, h, x, y; + // First get the screen size and mouse location. We will use this to decide + // what part of the orbit we are in. The mouse will move us up-down and around. + // fixme: In a future update, change the orbit only while right mouse button is pressed. + XPLMGetScreenSize(&w, &h); + XPLMGetMouseLocation(&x, &y); + double heading = 360.0 * static_cast(x) / static_cast(w); + double pitch = 20.0 * ((static_cast(y) / static_cast(h)) * 2.0 - 1.0); - // Now calculate where the camera should be positioned to be 200 - // meters from the plane and pointing at the plane at the pitch and - // heading we wanted above. - static const double PI = std::acos(-1); - double dx = -50.0 * sin(heading * PI / 180.0); - double dz = 50.0 * cos(heading * PI / 180.0); - double dy = -50.0 * tan(pitch * PI / 180.0); + // Now calculate where the camera should be positioned to be 200 + // meters from the plane and pointing at the plane at the pitch and + // heading we wanted above. + static const double PI = std::acos(-1); + double dx = -50.0 * sin(heading * PI / 180.0); + double dz = 50.0 * cos(heading * PI / 180.0); + double dy = -50.0 * tan(pitch * PI / 180.0); - auto planeIt = traffic->m_planesByCallsign.find(traffic->m_followPlaneViewCallsign); - if (planeIt == traffic->m_planesByCallsign.end()) { return 0; } - Plane *plane = planeIt->second; + double lx, ly, lz; + static const double kFtToMeters = 0.3048; - double lx, ly, lz; - static const double kFtToMeters = 0.3048; - XPLMWorldToLocal(plane->position.lat, plane->position.lon, plane->position.elevation * kFtToMeters, &lx, &ly, &lz); + if (traffic->m_followPlaneViewCallsign == traffic->ownAircraftString()) + { + lx = traffic->m_ownAircraftPositionX.get(); + ly = traffic->m_ownAircraftPositionY.get(); + lz = traffic->m_ownAircraftPositionZ.get(); + } + else + { + auto planeIt = traffic->m_planesByCallsign.find(traffic->m_followPlaneViewCallsign); + if (planeIt == traffic->m_planesByCallsign.end()) { return 0; } + Plane *plane = planeIt->second; + + XPLMWorldToLocal(plane->position.lat, plane->position.lon, plane->position.elevation * kFtToMeters, &lx, &ly, &lz); + } + + // Fill out the camera position info. + traffic->m_lastCameraPosition.x = static_cast(lx + dx); + traffic->m_lastCameraPosition.y = static_cast(ly + dy); + traffic->m_lastCameraPosition.z = static_cast(lz + dz); + traffic->m_lastCameraPosition.pitch = static_cast(pitch); + traffic->m_lastCameraPosition.heading = static_cast(heading); + } // Fill out the camera position info. - cameraPosition->x = static_cast(lx + dx); - cameraPosition->y = static_cast(ly + dy); - cameraPosition->z = static_cast(lz + dz); - cameraPosition->pitch = static_cast(pitch); - cameraPosition->heading = static_cast(heading); + cameraPosition->x = traffic->m_lastCameraPosition.x; + cameraPosition->y = traffic->m_lastCameraPosition.y; + cameraPosition->z = traffic->m_lastCameraPosition.z; + cameraPosition->pitch = traffic->m_lastCameraPosition.pitch; + cameraPosition->heading = traffic->m_lastCameraPosition.heading; cameraPosition->roll = 0; } @@ -879,6 +904,24 @@ namespace XSwiftBus return 1; } + + int CTraffic::spaceKeySniffer(char character, XPLMKeyFlags flags, char virtualKey, void *refcon) + { + (void) character; + (void) flags; + CTraffic *traffic = static_cast(refcon); + + // We are only interested in Space key + if (virtualKey == XPLM_VK_SPACE) + { + if (flags & xplm_DownFlag) { traffic->m_isSpacePressed = true; } + if (flags & xplm_UpFlag) { traffic->m_isSpacePressed = false; } + } + + /* Return 1 to pass the keystroke to plugin windows and X-Plane. + * Returning 0 would consume the keystroke. */ + return 1; + } } //! \endcond diff --git a/src/xswiftbus/traffic.h b/src/xswiftbus/traffic.h index 796985b6f..3469ff188 100644 --- a/src/xswiftbus/traffic.h +++ b/src/xswiftbus/traffic.h @@ -121,6 +121,9 @@ namespace XSwiftBus //! Perform generic processing int process(); + //! Returns the own aircraft string to be used as callsign for setFollowedAircraft() + std::string ownAircraftString() const { return "ownAircraft"; } + protected: virtual void dbusDisconnectedHandler() override; @@ -134,14 +137,16 @@ namespace XSwiftBus void emitSimFrame(); void emitPlaneAdded(const std::string &callsign); void emitPlaneAddingFailed(const std::string &callsign); - void enableFollowPlaneView(const std::string &callsign); + void switchToFollowPlaneView(const std::string &callsign); void followNextPlane(); void followPreviousPlane(); static int preferences(const char *section, const char *name, int def); static float preferences(const char *section, const char *name, float def); + static int orbitOwnAircraftFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon); static int orbitPlaneFunc(XPLMCameraPosition_t *cameraPosition, int isLosingControl, void *refcon); static int drawCallback(XPLMDrawingPhase phase, int isBefore, void *refcon); + static int spaceKeySniffer(char character, XPLMKeyFlags flags, char virtualKey, void *refcon); struct Plane { @@ -164,6 +169,7 @@ namespace XSwiftBus const std::string &livery_, const std::string &modelName_); }; + std::unordered_map m_planesByCallsign; std::unordered_map m_planesById; std::vector m_followPlaneViewSequence; @@ -176,6 +182,13 @@ namespace XSwiftBus CCommand m_followPlaneViewPreviousCommand; DataRef m_worldRenderType; + DataRef m_ownAircraftPositionX; + DataRef m_ownAircraftPositionY; + DataRef m_ownAircraftPositionZ; + + XPLMCameraPosition_t m_lastCameraPosition; + + bool m_isSpacePressed = false; bool m_emitSimFrame = true; int getPlaneData(void *id, int dataType, void *io_data);