From 743066c46dce5e4036630ad1386854b7222545ea Mon Sep 17 00:00:00 2001 From: Kristian Duske Date: Sat, 13 Oct 2018 08:46:01 +0200 Subject: [PATCH] 2344: Shortcut to moving faces in 2D (#2350) * 2344: Store drag faces by their normals in resize tool. * 2344: Implement face moving in resize tool. * 2344: Update manual for quick face moving. * 2344: Add missing includes. * 2344: Use correct plane type. --- .../manual/images/ResizeTool2DFaceMoving.gif | Bin 0 -> 65375 bytes app/resources/documentation/manual/index.md | 8 + common/src/View/ResizeBrushesTool.cpp | 213 ++++++++++++------ common/src/View/ResizeBrushesTool.h | 25 +- .../src/View/ResizeBrushesToolController.cpp | 43 +++- common/src/View/ResizeBrushesToolController.h | 9 + 6 files changed, 213 insertions(+), 85 deletions(-) create mode 100644 app/resources/documentation/manual/images/ResizeTool2DFaceMoving.gif diff --git a/app/resources/documentation/manual/images/ResizeTool2DFaceMoving.gif b/app/resources/documentation/manual/images/ResizeTool2DFaceMoving.gif new file mode 100644 index 0000000000000000000000000000000000000000..97d974e22671f74fd6cf78e889807da524da9edf GIT binary patch literal 65375 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
!%8?Ip`ajO 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 H0K)$ZFWgBf literal 0 HcmV?d00001 diff --git a/app/resources/documentation/manual/index.md b/app/resources/documentation/manual/index.md index 8c8c3a7ad0..d4200c17b1 100644 --- a/app/resources/documentation/manual/index.md +++ b/app/resources/documentation/manual/index.md @@ -614,6 +614,14 @@ The resize tool also works in the 2D viewports, of course, but the ability to mo Both snap modes are used simultaneously. There may be situations when you have to move the camera closer to a face in order to have sufficient precision when dragging the face. +#### Moving Faces Instead of Resizing + +The brush resize tool offers a quick way to move an individual face of a brush in 2D views. Hold #key(307) in addition to #key(306) when starting to drag a face in a 2D view to enable this mode. You will notice that a face is highlighted as usual, but when you start dragging the mouse, the face will just be moved in the direction you are dragging. The move is not restricted by the face normal, and other faces will be affected as well. + +![Resizing multiple brushes](ResizeTool2DFaceMoving.gif) + +The distance is snapped to the current grid size. Moving multiple faces is possible if the faces lie on the same plane. + ### Clipping Clipping is the most basic operation for Quake maps due to how brushes are [constructed from planes](#brush_geometry). In essence, all that clipping does is adding a new plane to a brush and, depending on the brush's shape, removing other planes from it if they become superfluous. In TrenchBroom, clipping is done using the clip tool, which you can activate by choosing #menu(Menu/Edit/Tools/Clip Tool). The clip tool lets you define a clip plane in various ways, and the lets you apply that plane to the selected brushes. diff --git a/common/src/View/ResizeBrushesTool.cpp b/common/src/View/ResizeBrushesTool.cpp index f0fa3768eb..91ece01388 100644 --- a/common/src/View/ResizeBrushesTool.cpp +++ b/common/src/View/ResizeBrushesTool.cpp @@ -37,9 +37,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -54,7 +56,7 @@ namespace TrenchBroom { Tool(true), m_document(document), m_splitBrushes(false), - m_resizing(false) { + m_dragging(false) { bindObservers(); } @@ -63,24 +65,28 @@ namespace TrenchBroom { } bool ResizeBrushesTool::applies() const { - MapDocumentSPtr document = lock(m_document); + auto document = lock(m_document); return document->selectedNodes().hasBrushes(); } Model::Hit ResizeBrushesTool::pick2D(const vm::ray3& pickRay, const Model::PickResult& pickResult) { - MapDocumentSPtr document = lock(m_document); - const Model::Hit& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().selected().first(); - if (hit.isMatch()) + auto document = lock(m_document); + const auto& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().selected().first(); + if (hit.isMatch()) { return Model::Hit::NoHit; - return pickProximateFace(ResizeHit2D, pickRay); + } else { + return pickProximateFace(ResizeHit2D, pickRay); + } } Model::Hit ResizeBrushesTool::pick3D(const vm::ray3& pickRay, const Model::PickResult& pickResult) { - MapDocumentSPtr document = lock(m_document); - const Model::Hit& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().selected().first(); - if (hit.isMatch()) + auto document = lock(m_document); + const auto& hit = pickResult.query().pickable().type(Model::Brush::BrushHit).occluded().selected().first(); + if (hit.isMatch()) { return Model::Hit(ResizeHit3D, hit.distance(), hit.hitPoint(), Model::hitToFace(hit)); - return pickProximateFace(ResizeHit3D, pickRay); + } else { + return pickProximateFace(ResizeHit3D, pickRay); + } } class ResizeBrushesTool::PickProximateFace : public Model::ConstNodeVisitor, public Model::NodeQuery { @@ -154,25 +160,38 @@ namespace TrenchBroom { } bool ResizeBrushesTool::hasDragFaces() const { - return !m_dragFaces.empty(); + return !m_dragHandles.empty(); } - const Model::BrushFaceList& ResizeBrushesTool::dragFaces() const { - return m_dragFaces; + Model::BrushFaceList ResizeBrushesTool::dragFaces() const { + Model::BrushFaceList result; + for (const auto& handle : m_dragHandles) { + const auto* brush = std::get<0>(handle); + const auto& normal = std::get<1>(handle); + auto* face = brush->findFace(normal); + assert(face != nullptr); + result.push_back(face); + } + return result; } void ResizeBrushesTool::updateDragFaces(const Model::PickResult& pickResult) { - const Model::Hit& hit = pickResult.query().type(ResizeHit2D | ResizeHit3D).occluded().first(); - Model::BrushFaceList newDragFaces = getDragFaces(hit); - if (newDragFaces != m_dragFaces) + const auto& hit = pickResult.query().type(ResizeHit2D | ResizeHit3D).occluded().first(); + auto newDragHandles = getDragHandles(hit); + if (newDragHandles != m_dragHandles) { refreshViews(); - + } + using std::swap; - swap(m_dragFaces, newDragFaces); + swap(m_dragHandles, newDragHandles); } - - Model::BrushFaceList ResizeBrushesTool::getDragFaces(const Model::Hit& hit) const { - return !hit.isMatch() ? Model::EmptyBrushFaceList : collectDragFaces(hit); + + std::vector ResizeBrushesTool::getDragHandles(const Model::Hit& hit) const { + if (hit.isMatch()) { + return collectDragHandles(hit); + } else { + return std::vector(0); + } } class ResizeBrushesTool::MatchFaceBoundary { @@ -188,8 +207,8 @@ namespace TrenchBroom { return face != m_reference && isEqual(face->boundary(), m_reference->boundary(), vm::C::almostZero()); } }; - - Model::BrushFaceList ResizeBrushesTool::collectDragFaces(const Model::Hit& hit) const { + + std::vector ResizeBrushesTool::collectDragHandles(const Model::Hit& hit) const { assert(hit.isMatch()); assert(hit.type() == ResizeHit2D || hit.type() == ResizeHit3D); @@ -199,15 +218,16 @@ namespace TrenchBroom { assert(!faces.empty()); VectorUtils::append(result, faces); VectorUtils::append(result, collectDragFaces(faces[0])); - if (faces.size() > 1) + if (faces.size() > 1) { VectorUtils::append(result, collectDragFaces(faces[1])); + } } else { Model::BrushFace* face = hit.target(); result.push_back(face); VectorUtils::append(result, collectDragFaces(face)); } - return result; + return getDragHandles(result); } Model::BrushFaceList ResizeBrushesTool::collectDragFaces(Model::BrushFace* face) const { @@ -219,25 +239,34 @@ namespace TrenchBroom { return visitor.faces(); } + std::vector ResizeBrushesTool::getDragHandles(const Model::BrushFaceList& faces) const { + std::vector result; + for (auto* face : faces) { + result.push_back(std::make_tuple(face->brush(), face->boundary().normal)); + } + return result; + } + bool ResizeBrushesTool::beginResize(const Model::PickResult& pickResult, const bool split) { - const Model::Hit& hit = pickResult.query().type(ResizeHit2D | ResizeHit3D).occluded().first(); - if (!hit.isMatch()) + const auto& hit = pickResult.query().type(ResizeHit2D | ResizeHit3D).occluded().first(); + if (!hit.isMatch()) { return false; - + } + m_dragOrigin = hit.hitPoint(); m_totalDelta = vm::vec3::zero; m_splitBrushes = split; - MapDocumentSPtr document = lock(m_document); + auto document = lock(m_document); document->beginTransaction("Resize Brushes"); - m_resizing = true; + m_dragging = true; return true; } - + bool ResizeBrushesTool::resize(const vm::ray3& pickRay, const Renderer::Camera& camera) { - assert(!m_dragFaces.empty()); + assert(hasDragFaces()); - auto* dragFace = m_dragFaces.front(); + auto* dragFace = dragFaces().front(); const auto& faceNormal = dragFace->boundary().normal; const auto dist = vm::distance(pickRay, vm::line3(m_dragOrigin, faceNormal)); @@ -275,63 +304,109 @@ namespace TrenchBroom { vm::vec3 ResizeBrushesTool::selectDelta(const vm::vec3& relativeDelta, const vm::vec3& absoluteDelta, const FloatType mouseDistance) const { // select the delta that is closest to the actual delta indicated by the mouse cursor - const FloatType mouseDistance2 = mouseDistance * mouseDistance; + const auto mouseDistance2 = mouseDistance * mouseDistance; return (vm::abs(squaredLength(relativeDelta) - mouseDistance2) < vm::abs(squaredLength(absoluteDelta) - mouseDistance2) ? relativeDelta : absoluteDelta); } - void ResizeBrushesTool::commitResize() { - MapDocumentSPtr document = lock(m_document); + bool ResizeBrushesTool::beginMove(const Model::PickResult& pickResult) { + const auto& hit = pickResult.query().type(ResizeHit2D).occluded().first(); + if (!hit.isMatch()) { + return false; + } + + m_dragOrigin = m_lastPoint = hit.hitPoint(); + m_totalDelta = vm::vec3::zero; + m_splitBrushes = false; + + auto document = lock(m_document); + document->beginTransaction("Move Faces"); + m_dragging = true; + return true; + } + + bool ResizeBrushesTool::move(const vm::ray3& pickRay, const Renderer::Camera& camera) { + const auto dragPlane = vm::plane3(m_dragOrigin, vm::vec3(camera.direction())); + const auto hitDist = vm::intersect(pickRay, dragPlane); + if (vm::isnan(hitDist)) { + return true; + } + + const auto hitPoint = pickRay.pointAtDistance(hitDist); + + auto document = lock(m_document); + const auto& grid = document->grid(); + const auto delta = grid.snap(hitPoint - m_lastPoint); + if (vm::isZero(delta, vm::C::almostZero())) { + return true; + } + + std::map brushMap; + for (const auto* face : dragFaces()) { + brushMap[face->polygon()].insert(face->brush()); + } + + if (document->moveFaces(brushMap, delta)) { + m_lastPoint = m_lastPoint + delta; + m_totalDelta = m_totalDelta + delta; + } + + return true; + } + + void ResizeBrushesTool::commit() { + auto document = lock(m_document); if (isZero(m_totalDelta, vm::C::almostZero())) { document->cancelTransaction(); } else { document->commitTransaction(); } - m_dragFaces.clear(); - m_resizing = false; + m_dragHandles.clear(); + m_dragging = false; } - void ResizeBrushesTool::cancelResize() { - MapDocumentSPtr document = lock(m_document); + void ResizeBrushesTool::cancel() { + auto document = lock(m_document); document->cancelTransaction(); - m_dragFaces.clear(); - m_resizing = false; + m_dragHandles.clear(); + m_dragging = false; } bool ResizeBrushesTool::splitBrushes(const vm::vec3& delta) { - MapDocumentSPtr document = lock(m_document); + auto document = lock(m_document); const vm::bbox3& worldBounds = document->worldBounds(); const bool lockTextures = pref(Preferences::TextureLock); - // First ensure that the drag can be applied at all. For this, check whether each drag faces is moved + // First ensure that the drag can be applied at all. For this, check whether each drag handle is moved // "up" along its normal. - if (!std::all_of(std::begin(m_dragFaces), std::end(m_dragFaces), - [&delta](const Model::BrushFace* face) { - return dot(face->boundary().normal, delta) > FloatType(0.0); })) { + if (!std::all_of(std::begin(m_dragHandles), std::end(m_dragHandles), [&delta](const auto& handle) { + const auto& normal = std::get<1>(handle); + return dot(normal, delta) > FloatType(0.0); + })) { return false; } Model::BrushList newBrushes; - Model::BrushFaceList newDragFaces; + std::vector newDragHandles; Model::ParentChildrenMap newNodes; - for (Model::BrushFace* dragFace : m_dragFaces) { - Model::Brush* brush = dragFace->brush(); + for (auto* dragFace : dragFaces()) { + auto* brush = dragFace->brush(); - Model::Brush* newBrush = brush->clone(worldBounds); - Model::BrushFace* newDragFace = findMatchingFace(newBrush, dragFace); + auto* newBrush = brush->clone(worldBounds); + auto* newDragFace = findMatchingFace(newBrush, dragFace); newBrushes.push_back(newBrush); - newDragFaces.push_back(newDragFace); + newDragHandles.push_back(std::make_tuple(newDragFace->brush(), newDragFace->boundary().normal)); if (!newBrush->canMoveBoundary(worldBounds, newDragFace, delta)) { // There is a brush for which the move is not applicable. Abort. VectorUtils::deleteAll(newBrushes); return false; } else { - Model::BrushFace* clipFace = newDragFace->clone(); + auto* clipFace = newDragFace->clone(); clipFace->invert(); newBrush->moveBoundary(worldBounds, newDragFace, delta, lockTextures); @@ -348,9 +423,9 @@ namespace TrenchBroom { } document->deselectAll(); - const Model::NodeList addedNodes = document->addNodes(newNodes); + const auto addedNodes = document->addNodes(newNodes); document->select(addedNodes); - m_dragFaces = newDragFaces; + m_dragHandles = newDragHandles; return true; } @@ -358,20 +433,24 @@ namespace TrenchBroom { Model::BrushFace* ResizeBrushesTool::findMatchingFace(Model::Brush* brush, const Model::BrushFace* reference) const { Model::FindMatchingBrushFaceVisitor visitor((MatchFaceBoundary(reference))); visitor.visit(brush); - if (!visitor.hasResult()) + if (!visitor.hasResult()) { return nullptr; - return visitor.result(); + } else { + return visitor.result(); + } } std::vector ResizeBrushesTool::dragFaceDescriptors() const { + const auto dragFaces = this->dragFaces(); + std::vector result; - result.reserve(m_dragFaces.size()); - std::transform(std::begin(m_dragFaces), std::end(m_dragFaces), std::back_inserter(result), [](const Model::BrushFace* face) { return face->polygon(); }); + result.reserve(dragFaces.size()); + std::transform(std::begin(dragFaces), std::end(dragFaces), std::back_inserter(result), [](const Model::BrushFace* face) { return face->polygon(); }); return result; } void ResizeBrushesTool::bindObservers() { - MapDocumentSPtr document = lock(m_document); + auto document = lock(m_document); document->nodesWereAddedNotifier.addObserver(this, &ResizeBrushesTool::nodesDidChange); document->nodesWillChangeNotifier.addObserver(this, &ResizeBrushesTool::nodesDidChange); document->nodesWillBeRemovedNotifier.addObserver(this, &ResizeBrushesTool::nodesDidChange); @@ -380,7 +459,7 @@ namespace TrenchBroom { void ResizeBrushesTool::unbindObservers() { if (!expired(m_document)) { - MapDocumentSPtr document = lock(m_document); + auto document = lock(m_document); document->nodesWereAddedNotifier.removeObserver(this, &ResizeBrushesTool::nodesDidChange); document->nodesWillChangeNotifier.removeObserver(this, &ResizeBrushesTool::nodesDidChange); document->nodesWillBeRemovedNotifier.removeObserver(this, &ResizeBrushesTool::nodesDidChange); @@ -389,13 +468,15 @@ namespace TrenchBroom { } void ResizeBrushesTool::nodesDidChange(const Model::NodeList& nodes) { - if (!m_resizing) - m_dragFaces.clear(); + if (!m_dragging) { + m_dragHandles.clear(); + } } void ResizeBrushesTool::selectionDidChange(const Selection& selection) { - if (!m_resizing) - m_dragFaces.clear(); + if (!m_dragging) { + m_dragHandles.clear(); + } } } } diff --git a/common/src/View/ResizeBrushesTool.h b/common/src/View/ResizeBrushesTool.h index 07cd9caa44..5d43921083 100644 --- a/common/src/View/ResizeBrushesTool.h +++ b/common/src/View/ResizeBrushesTool.h @@ -29,6 +29,8 @@ #include #include +#include + namespace TrenchBroom { namespace Model { class PickResult; @@ -46,12 +48,15 @@ namespace TrenchBroom { static const Model::Hit::HitType ResizeHit3D; static const Model::Hit::HitType ResizeHit2D; + using FaceHandle = std::tuple; + MapDocumentWPtr m_document; - Model::BrushFaceList m_dragFaces; + std::vector m_dragHandles; vm::vec3 m_dragOrigin; - vm::vec3 m_totalDelta; + vm::vec3 m_lastPoint; bool m_splitBrushes; - bool m_resizing; + vm::vec3 m_totalDelta; + bool m_dragging; public: explicit ResizeBrushesTool(MapDocumentWPtr document); ~ResizeBrushesTool() override; @@ -65,20 +70,24 @@ namespace TrenchBroom { Model::Hit pickProximateFace(Model::Hit::HitType hitType, const vm::ray3& pickRay) const; public: bool hasDragFaces() const; - const Model::BrushFaceList& dragFaces() const; + Model::BrushFaceList dragFaces() const; void updateDragFaces(const Model::PickResult& pickResult); private: - Model::BrushFaceList getDragFaces(const Model::Hit& hit) const; + std::vector getDragHandles(const Model::Hit& hit) const; class MatchFaceBoundary; - Model::BrushFaceList collectDragFaces(const Model::Hit& hit) const; + std::vector collectDragHandles(const Model::Hit& hit) const; Model::BrushFaceList collectDragFaces(Model::BrushFace* face) const; + std::vector getDragHandles(const Model::BrushFaceList& faces) const; public: bool beginResize(const Model::PickResult& pickResult, bool split); bool resize(const vm::ray3& pickRay, const Renderer::Camera& camera); vm::vec3 selectDelta(const vm::vec3& relativeDelta, const vm::vec3& absoluteDelta, FloatType mouseDistance) const; - void commitResize(); - void cancelResize(); + bool beginMove(const Model::PickResult& pickResult); + bool move(const vm::ray3& pickRay, const Renderer::Camera& camera); + + void commit(); + void cancel(); private: bool splitBrushes(const vm::vec3& delta); Model::BrushFace* findMatchingFace(Model::Brush* brush, const Model::BrushFace* reference) const; diff --git a/common/src/View/ResizeBrushesToolController.cpp b/common/src/View/ResizeBrushesToolController.cpp index 8861c8b65a..9e18a67ae2 100644 --- a/common/src/View/ResizeBrushesToolController.cpp +++ b/common/src/View/ResizeBrushesToolController.cpp @@ -70,25 +70,37 @@ namespace TrenchBroom { return false; m_tool->updateDragFaces(inputState.pickResult()); - const bool split = inputState.modifierKeysDown(ModifierKeys::MKCtrlCmd); - if (m_tool->beginResize(inputState.pickResult(), split)) { - m_tool->updateDragFaces(inputState.pickResult()); - return true; + m_mode = inputState.modifierKeysDown(ModifierKeys::MKAlt) ? Mode::MoveFace : Mode::Resize; + if (m_mode == Mode::Resize) { + const auto split = inputState.modifierKeysDown(ModifierKeys::MKCtrlCmd); + if (m_tool->beginResize(inputState.pickResult(), split)) { + m_tool->updateDragFaces(inputState.pickResult()); + return true; + } + } else { + if (m_tool->beginMove(inputState.pickResult())) { + m_tool->updateDragFaces(inputState.pickResult()); + return true; + } } return false; } bool ResizeBrushesToolController::doMouseDrag(const InputState& inputState) { - return m_tool->resize(inputState.pickRay(), inputState.camera()); + if (m_mode == Mode::Resize) { + return m_tool->resize(inputState.pickRay(), inputState.camera()); + } else { + return m_tool->move(inputState.pickRay(), inputState.camera()); + } } void ResizeBrushesToolController::doEndMouseDrag(const InputState& inputState) { - m_tool->commitResize(); + m_tool->commit(); m_tool->updateDragFaces(inputState.pickResult()); } void ResizeBrushesToolController::doCancelMouseDrag() { - m_tool->cancelResize(); + m_tool->cancel(); } void ResizeBrushesToolController::doSetRenderOptions(const InputState& inputState, Renderer::RenderContext& renderContext) const { @@ -123,9 +135,7 @@ namespace TrenchBroom { } bool ResizeBrushesToolController::handleInput(const InputState& inputState) const { - return ((inputState.modifierKeysPressed(ModifierKeys::MKShift) || - inputState.modifierKeysPressed(ModifierKeys::MKShift | ModifierKeys::MKCtrlCmd)) && - m_tool->applies()); + return (doHandleInput(inputState) && m_tool->applies()); } ResizeBrushesToolController2D::ResizeBrushesToolController2D(ResizeBrushesTool* tool) : @@ -134,12 +144,23 @@ namespace TrenchBroom { Model::Hit ResizeBrushesToolController2D::doPick(const vm::ray3& pickRay, const Model::PickResult& pickResult) { return m_tool->pick2D(pickRay, pickResult); } - + + bool ResizeBrushesToolController2D::doHandleInput(const InputState& inputState) const { + return (inputState.modifierKeysPressed(ModifierKeys::MKShift) || + inputState.modifierKeysPressed(ModifierKeys::MKShift | ModifierKeys::MKCtrlCmd) || + inputState.modifierKeysPressed(ModifierKeys::MKShift | ModifierKeys::MKAlt)); + } + ResizeBrushesToolController3D::ResizeBrushesToolController3D(ResizeBrushesTool* tool) : ResizeBrushesToolController(tool) {} Model::Hit ResizeBrushesToolController3D::doPick(const vm::ray3& pickRay, const Model::PickResult& pickResult) { return m_tool->pick3D(pickRay, pickResult); } + + bool ResizeBrushesToolController3D::doHandleInput(const InputState& inputState) const { + return (inputState.modifierKeysPressed(ModifierKeys::MKShift) || + inputState.modifierKeysPressed(ModifierKeys::MKShift | ModifierKeys::MKCtrlCmd)); + } } } diff --git a/common/src/View/ResizeBrushesToolController.h b/common/src/View/ResizeBrushesToolController.h index 8c0c5d9ffe..1074b4aafe 100644 --- a/common/src/View/ResizeBrushesToolController.h +++ b/common/src/View/ResizeBrushesToolController.h @@ -41,6 +41,12 @@ namespace TrenchBroom { class ResizeBrushesToolController : public ToolControllerBase { protected: ResizeBrushesTool* m_tool; + private: + enum class Mode { + Resize, + MoveFace + }; + Mode m_mode; protected: ResizeBrushesToolController(ResizeBrushesTool* tool); public: @@ -66,6 +72,7 @@ namespace TrenchBroom { bool doCancel() override; bool handleInput(const InputState& inputState) const; + virtual bool doHandleInput(const InputState& inputState) const = 0; private: virtual Model::Hit doPick(const vm::ray3& pickRay, const Model::PickResult& pickResult) = 0; }; @@ -75,6 +82,7 @@ namespace TrenchBroom { ResizeBrushesToolController2D(ResizeBrushesTool* tool); private: Model::Hit doPick(const vm::ray3& pickRay, const Model::PickResult& pickResult) override; + bool doHandleInput(const InputState& inputState) const override; }; class ResizeBrushesToolController3D : public ResizeBrushesToolController { @@ -82,6 +90,7 @@ namespace TrenchBroom { ResizeBrushesToolController3D(ResizeBrushesTool* tool); private: Model::Hit doPick(const vm::ray3& pickRay, const Model::PickResult& pickResult) override; + bool doHandleInput(const InputState& inputState) const override; }; } }