From 9bb75a6f2e4822b57e73b13ff1f3950554f67607 Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Tue, 16 Oct 2018 16:29:32 +0200 Subject: [PATCH] Rotate camera in follow plane view only if space key is pressed This commits merges the two orbit plane functions together in CTraffic. The separation was necessary since XSwiftBus needed to be started manually and until started, the pointer to CTraffic was invalid. Since XSwiftBus is started automatically, it can be merged into one function again. This commit also adds the feature to rotate the camera only if the space key is pressed. This is equal to how FSX/P3D do it. Using the right mouse was not possible, since X-Plane SDK does not offer that option. ref T360 --- src/xswiftbus/plugin.cpp | 61 ++-------------------- src/xswiftbus/plugin.h | 6 --- src/xswiftbus/traffic.cpp | 107 ++++++++++++++++++++++++++------------ src/xswiftbus/traffic.h | 15 +++++- 4 files changed, 93 insertions(+), 96 deletions(-) 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);