From d155a709d026bf93354282c49d88435e158c47df Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Wed, 2 Sep 2020 16:05:08 -0400 Subject: [PATCH 1/3] Refactor view control API - Rename InteractionController->ViewController - Use Body's flag mechanism to exclude bodies from drawing - Pave the way for non-ShipView ViewControllers via SetViewController() --- src/Body.h | 17 +++++++++++++++-- src/Camera.cpp | 4 ++++ src/WorldView.cpp | 29 +++++++++++++---------------- src/WorldView.h | 4 ++++ src/ship/InteractionController.h | 18 ------------------ src/ship/ShipViewController.cpp | 13 ++++++++++++- src/ship/ShipViewController.h | 7 ++++--- src/ship/ViewController.h | 28 ++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 40 deletions(-) delete mode 100644 src/ship/InteractionController.h create mode 100644 src/ship/ViewController.h diff --git a/src/Body.h b/src/Body.h index 6505eada37b..6177a4ecb3f 100644 --- a/src/Body.h +++ b/src/Body.h @@ -80,7 +80,17 @@ class Body : public Object, public PropertiedObject { virtual void SetLabel(const std::string &label); const std::string &GetLabel() const { return m_label; } + unsigned int GetFlags() const { return m_flags; } + // TODO(sturnclaw) use this sparingly, the flags interface is rather fragile and needs work + void SetFlag(unsigned int flag, bool enable) + { + if (enable) + m_flags |= flag; + else + m_flags &= ~flag; + } + // Only Space::KillBody() should call this method. void MarkDead() { m_dead = true; } bool IsDead() const { return m_dead; } @@ -108,9 +118,12 @@ class Body : public Object, public PropertiedObject { // Usually equal to the center of the body == vector3d(0, 0, 0) virtual vector3d GetTargetIndicatorPosition() const; - enum { FLAG_CAN_MOVE_FRAME = (1 << 0), + enum { + FLAG_CAN_MOVE_FRAME = (1 << 0), FLAG_LABEL_HIDDEN = (1 << 1), - FLAG_DRAW_LAST = (1 << 2) }; // causes the body drawn after other bodies in the z-sort + FLAG_DRAW_LAST = (1 << 2), // causes the body drawn after other bodies in the z-sort + FLAG_DRAW_EXCLUDE = (1 << 3) // do not draw this body, intended for e.g. when camera is inside + }; protected: virtual void SaveToJson(Json &jsonObj, Space *space); diff --git a/src/Camera.cpp b/src/Camera.cpp index e27974a2c98..9fb0c38f743 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -143,6 +143,10 @@ void Camera::Update() attrs.body = b; attrs.billboard = false; // false by default + // If the body wishes to be excluded from the draw, skip it. + if (b->GetFlags() & Body::FLAG_DRAW_EXCLUDE) + continue; + // determine position and transform for draw // Frame::GetFrameTransform(b->GetFrame(), camFrame, attrs.viewTransform); // doesn't use interp coords, so breaks in some cases Frame *f = Frame::GetFrame(b->GetFrame()); diff --git a/src/WorldView.cpp b/src/WorldView.cpp index aba846436b9..5ec237730a7 100644 --- a/src/WorldView.cpp +++ b/src/WorldView.cpp @@ -106,6 +106,7 @@ void WorldView::InitObject() shipView.reset(new ShipViewController(this)); shipView->Init(); + SetViewController(shipView.get()); m_onToggleHudModeCon = InputBindings.toggleHudMode->onPress.connect(sigc::mem_fun(this, &WorldView::OnToggleLabels)); m_onIncTimeAccelCon = InputBindings.increaseTimeAcceleration->onPress.connect(sigc::mem_fun(this, &WorldView::OnRequestTimeAccelInc)); @@ -140,6 +141,11 @@ void WorldView::OnRequestTimeAccelDec() Pi::game->RequestTimeAccelDec(); } +void WorldView::SetViewController(ViewController *newView) +{ + m_viewController = newView; +} + void WorldView::Draw3D() { PROFILE_SCOPED() @@ -149,22 +155,11 @@ void WorldView::Draw3D() m_cameraContext->ApplyDrawTransforms(m_renderer); - Body *excludeBody = nullptr; - ShipCockpit *cockpit = nullptr; - if (shipView->GetCamType() == ShipViewController::CAM_INTERNAL) { - excludeBody = Pi::player; - if (shipView->m_internalCameraController->GetMode() == InternalCameraController::MODE_FRONT) - cockpit = Pi::player->GetCockpit(); - } - m_camera->Draw(excludeBody); + m_camera->Draw(); // NB: Do any screen space rendering after here: // Things like the cockpit and AR features like hudtrails, space dust etc. - - // Render cockpit - // XXX camera should rotate inside cockpit, not rotate the cockpit around in the world - if (cockpit) - cockpit->RenderCockpit(m_renderer, m_camera.get(), m_camera->GetContext()->GetTempFrame()); + m_viewController->Draw(m_camera.get()); // Draw 3D HUD // Speed lines @@ -201,7 +196,7 @@ void WorldView::Update() assert(Pi::player); assert(!Pi::player->IsDead()); - shipView->Update(); + m_viewController->Update(); m_cameraContext->BeginFrame(); m_camera->Update(); @@ -242,12 +237,14 @@ void WorldView::Update() void WorldView::OnSwitchTo() { - shipView->Activated(); + if (m_viewController) + m_viewController->Activated(); } void WorldView::OnSwitchFrom() { - shipView->Deactivated(); + if (m_viewController) + m_viewController->Deactivated(); Pi::DrawGUI = true; } diff --git a/src/WorldView.h b/src/WorldView.h index 9799d7fa0bf..af02d5664f9 100644 --- a/src/WorldView.h +++ b/src/WorldView.h @@ -57,6 +57,9 @@ class WorldView : public PiGuiView { RefCountedPtr GetCameraContext() const { return m_cameraContext; } + ViewController *GetViewController() const { return m_viewController; } + void SetViewController(ViewController *newView); + std::unique_ptr shipView; int GetActiveWeapon() const; @@ -118,6 +121,7 @@ class WorldView : public PiGuiView { void SelectBody(Body *, bool reselectIsDeselect); Game *m_game; + ViewController *m_viewController; NavTunnelWidget *m_navTunnel; std::unique_ptr m_speedLines; diff --git a/src/ship/InteractionController.h b/src/ship/InteractionController.h deleted file mode 100644 index 44485b6844b..00000000000 --- a/src/ship/InteractionController.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details -// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt - -#pragma once - -class WorldView; - -class InteractionController { -public: - InteractionController(WorldView *v) : - parentView(v) {} - - virtual void Activated() = 0; - virtual void Deactivated() = 0; - virtual void Update() = 0; - - WorldView *parentView; -}; diff --git a/src/ship/ShipViewController.cpp b/src/ship/ShipViewController.cpp index 02b01bd8422..7f08b615d7b 100644 --- a/src/ship/ShipViewController.cpp +++ b/src/ship/ShipViewController.cpp @@ -85,7 +85,7 @@ void ShipViewController::SaveToJson(Json &jsonObj) void ShipViewController::Init() { - RefCountedPtr m_cameraContext = parentView->GetCameraContext(); + RefCountedPtr m_cameraContext = m_parentView->GetCameraContext(); m_internalCameraController.reset(new InternalCameraController(m_cameraContext, Pi::player)); m_externalCameraController.reset(new ExternalCameraController(m_cameraContext, Pi::player)); m_siderealCameraController.reset(new SiderealCameraController(m_cameraContext, Pi::player)); @@ -101,10 +101,12 @@ void ShipViewController::Activated() Pi::input->onMouseWheel.connect(sigc::mem_fun(this, &ShipViewController::MouseWheel)); Pi::player->GetPlayerController()->SetMouseForRearView(GetCamType() == CAM_INTERNAL && m_internalCameraController->GetMode() == InternalCameraController::MODE_REAR); + Pi::player->SetFlag(Body::FLAG_DRAW_EXCLUDE, !IsExteriorView()); } void ShipViewController::Deactivated() { + Pi::player->SetFlag(Body::FLAG_DRAW_EXCLUDE, false); Pi::input->RemoveInputFrame(&InputBindings); m_onMouseWheelCon.disconnect(); @@ -137,6 +139,7 @@ void ShipViewController::SetCamType(enum CamType c) headtracker_input_priority = false; } + Pi::player->SetFlag(Body::FLAG_DRAW_EXCLUDE, !IsExteriorView()); Pi::player->GetPlayerController()->SetMouseForRearView(m_camType == CAM_INTERNAL && m_internalCameraController->GetMode() == InternalCameraController::MODE_REAR); m_activeCameraController->Reset(); @@ -238,6 +241,14 @@ void ShipViewController::Update() m_activeCameraController->Update(); } +void ShipViewController::Draw(Camera *camera) +{ + // Render cockpit + // XXX camera should rotate inside cockpit, not rotate the cockpit around in the world + if (!IsExteriorView() && m_internalCameraController->GetMode() == InternalCameraController::MODE_FRONT) + Pi::player->GetCockpit()->RenderCockpit(Pi::renderer, camera, camera->GetContext()->GetTempFrame()); +} + void ShipViewController::MouseWheel(bool up) { if (m_activeCameraController->IsExternal()) { diff --git a/src/ship/ShipViewController.h b/src/ship/ShipViewController.h index e9e3275261d..7cb9284ad26 100644 --- a/src/ship/ShipViewController.h +++ b/src/ship/ShipViewController.h @@ -5,20 +5,21 @@ #include "CameraController.h" #include "Input.h" -#include "InteractionController.h" #include "KeyBindings.h" +#include "ViewController.h" #include "utils.h" -class ShipViewController : public InteractionController { +class ShipViewController : public ViewController { public: ShipViewController(WorldView *v) : - InteractionController(v), + ViewController(v), m_camType(CAM_INTERNAL), headtracker_input_priority(false) {} void Update() override; void Activated() override; void Deactivated() override; + void Draw(Camera *camera) override; enum CamType { CAM_INTERNAL, diff --git a/src/ship/ViewController.h b/src/ship/ViewController.h new file mode 100644 index 00000000000..fbed4447277 --- /dev/null +++ b/src/ship/ViewController.h @@ -0,0 +1,28 @@ +// Copyright © 2008-2020 Pioneer Developers. See AUTHORS.txt for details +// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt + +#pragma once + +class Camera; +class WorldView; + +class ViewController { +public: + ViewController(WorldView *v) : + m_parentView(v) {} + + // Called when the view owning this controller becomes active + virtual void Activated() = 0; + + // Called when the view owning this controller becomes inactive + virtual void Deactivated() = 0; + + // Called every frame to update the controller before the camera is updated + virtual void Update() = 0; + + // Do view-specific drawing here, called after the camera has drawn the world + virtual void Draw(Camera *camera) = 0; + +protected: + WorldView *m_parentView; +}; From f87b94636adaf8cf0869f48c135cd16495589555 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Fri, 4 Sep 2020 12:29:12 -0400 Subject: [PATCH 2/3] Move CameraController.h to ship/ --- src/ShipCockpit.cpp | 2 +- src/{ship => }/ViewController.h | 0 src/{ => ship}/CameraController.cpp | 0 src/{ => ship}/CameraController.h | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename src/{ship => }/ViewController.h (100%) rename src/{ => ship}/CameraController.cpp (100%) rename src/{ => ship}/CameraController.h (100%) diff --git a/src/ShipCockpit.cpp b/src/ShipCockpit.cpp index cb6b430889d..ad6cecd2399 100644 --- a/src/ShipCockpit.cpp +++ b/src/ShipCockpit.cpp @@ -3,13 +3,13 @@ #include "ShipCockpit.h" -#include "CameraController.h" #include "Easing.h" #include "Game.h" #include "Pi.h" #include "Player.h" #include "WorldView.h" #include "graphics/Renderer.h" +#include "ship/CameraController.h" ShipCockpit::ShipCockpit(const std::string &modelName) : m_shipDir(0.0), diff --git a/src/ship/ViewController.h b/src/ViewController.h similarity index 100% rename from src/ship/ViewController.h rename to src/ViewController.h diff --git a/src/CameraController.cpp b/src/ship/CameraController.cpp similarity index 100% rename from src/CameraController.cpp rename to src/ship/CameraController.cpp diff --git a/src/CameraController.h b/src/ship/CameraController.h similarity index 100% rename from src/CameraController.h rename to src/ship/CameraController.h From 85f2b66182a219dc72b54d1fd2013720b92edf1a Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Sun, 6 Sep 2020 19:02:00 -0400 Subject: [PATCH 3/3] Fix segfault when cockpits are disabled --- src/ship/ShipViewController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ship/ShipViewController.cpp b/src/ship/ShipViewController.cpp index 7f08b615d7b..161171b1b9d 100644 --- a/src/ship/ShipViewController.cpp +++ b/src/ship/ShipViewController.cpp @@ -245,7 +245,7 @@ void ShipViewController::Draw(Camera *camera) { // Render cockpit // XXX camera should rotate inside cockpit, not rotate the cockpit around in the world - if (!IsExteriorView() && m_internalCameraController->GetMode() == InternalCameraController::MODE_FRONT) + if (!IsExteriorView() && Pi::player->GetCockpit() && m_internalCameraController->GetMode() == InternalCameraController::MODE_FRONT) Pi::player->GetCockpit()->RenderCockpit(Pi::renderer, camera, camera->GetContext()->GetTempFrame()); }