From 716eebe61628ba7a6a96de239388fba0c61dd5f9 Mon Sep 17 00:00:00 2001 From: psi29a Date: Sun, 22 Aug 2021 19:22:13 +0000 Subject: [PATCH] Merge branch 'terrainselectioncrashfix' into 'openmw-47' Fix terrain selection crash See merge request OpenMW/openmw!1165 (cherry picked from commit ec4e3b04a7b394acaaa8319b89ce1237e9d4d6e6) b84e41bd Avoid storing ref, dynamic cast worldspacewidget for safety d62ddc00 Use QPointer to detect object existence, less verbose debug messages cb42b528 Remove friend, make getEditMode public to allow editmode testing. 4b148180 Restucture code 08f7c73e Fix text --- apps/opencs/view/render/commands.cpp | 33 ++++++++++++++++--- apps/opencs/view/render/commands.hpp | 11 +++++-- apps/opencs/view/render/terrainshapemode.cpp | 13 +++++--- apps/opencs/view/render/terrainshapemode.hpp | 4 ++- .../opencs/view/render/terraintexturemode.cpp | 5 +++ .../opencs/view/render/terraintexturemode.hpp | 4 ++- apps/opencs/view/render/worldspacewidget.cpp | 10 +++--- apps/opencs/view/render/worldspacewidget.hpp | 4 +-- 8 files changed, 65 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/render/commands.cpp b/apps/opencs/view/render/commands.cpp index 7b37602961..699bf5d016 100644 --- a/apps/opencs/view/render/commands.cpp +++ b/apps/opencs/view/render/commands.cpp @@ -1,19 +1,44 @@ #include "commands.hpp" +#include + +#include #include +#include "editmode.hpp" #include "terrainselection.hpp" +#include "terrainshapemode.hpp" +#include "terraintexturemode.hpp" +#include "worldspacewidget.hpp" -CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent) - : mTerrainSelection(terrainSelection) +CSVRender::DrawTerrainSelectionCommand::DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent) + : mWorldspaceWidget(worldspaceWidget) { } void CSVRender::DrawTerrainSelectionCommand::redo() { - mTerrainSelection.update(); + tryUpdate(); } void CSVRender::DrawTerrainSelectionCommand::undo() { - mTerrainSelection.update(); + tryUpdate(); +} + +void CSVRender::DrawTerrainSelectionCommand::tryUpdate() +{ + if (!mWorldspaceWidget) + { + Log(Debug::Verbose) << "Can't update terrain selection, no WorldspaceWidget found!"; + return; + } + + auto terrainMode = dynamic_cast(mWorldspaceWidget->getEditMode()); + if (!terrainMode) + { + Log(Debug::Verbose) << "Can't update terrain selection in current EditMode"; + return; + } + + terrainMode->getTerrainSelection()->update(); } diff --git a/apps/opencs/view/render/commands.hpp b/apps/opencs/view/render/commands.hpp index cdc389e33a..62b7fbfdcd 100644 --- a/apps/opencs/view/render/commands.hpp +++ b/apps/opencs/view/render/commands.hpp @@ -1,8 +1,12 @@ #ifndef CSV_RENDER_COMMANDS_HPP #define CSV_RENDER_COMMANDS_HPP +#include + #include +#include "worldspacewidget.hpp" + namespace CSVRender { class TerrainSelection; @@ -21,14 +25,17 @@ namespace CSVRender */ class DrawTerrainSelectionCommand : public QUndoCommand { + private: - TerrainSelection& mTerrainSelection; + QPointer mWorldspaceWidget; public: - DrawTerrainSelectionCommand(TerrainSelection& terrainSelection, QUndoCommand* parent = nullptr); + DrawTerrainSelectionCommand(WorldspaceWidget* worldspaceWidget, QUndoCommand* parent = nullptr); void redo() override; void undo() override; + + void tryUpdate(); }; } diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 866ff69cde..0504944954 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -287,7 +287,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() undoStack.beginMacro ("Edit shape and normal records"); // One command at the beginning of the macro for redrawing the terrain-selection grid when undoing the changes. - undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); + undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget())); for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells) { @@ -358,7 +358,7 @@ void CSVRender::TerrainShapeMode::applyTerrainEditChanges() pushNormalsEditToCommand(landNormalsNew, document, landTable, cellId); } // One command at the end of the macro for redrawing the terrain-selection grid when redoing the changes. - undoStack.push(new DrawTerrainSelectionCommand(*mTerrainShapeSelection)); + undoStack.push(new DrawTerrainSelectionCommand(&getWorldspaceWidget())); undoStack.endMacro(); clearTransientEdits(); @@ -1049,7 +1049,7 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob */ if (xIsAtCellBorder && yIsAtCellBorder) { - /* + /* Handle the NW, NE, and SE corner vertices. NW corner: (+1, -1) offset to reach current cell. NE corner: (-1, -1) offset to reach current cell. @@ -1132,7 +1132,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString(); else selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString(); - + if (selectAction == "Select only") mTerrainShapeSelection->onlySelect(selections); else if (selectAction == "Add to selection") @@ -1444,6 +1444,11 @@ void CSVRender::TerrainShapeMode::mouseMoveEvent (QMouseEvent *event) mBrushDraw->hide(); } +std::shared_ptr CSVRender::TerrainShapeMode::getTerrainSelection() +{ + return mTerrainShapeSelection; +} + void CSVRender::TerrainShapeMode::setBrushSize(int brushSize) { mBrushSize = brushSize; diff --git a/apps/opencs/view/render/terrainshapemode.hpp b/apps/opencs/view/render/terrainshapemode.hpp index a88e60c9c4..abc4b8aba8 100644 --- a/apps/opencs/view/render/terrainshapemode.hpp +++ b/apps/opencs/view/render/terrainshapemode.hpp @@ -92,6 +92,8 @@ namespace CSVRender void dragMoveEvent (QDragMoveEvent *event) override; void mouseMoveEvent (QMouseEvent *event) override; + std::shared_ptr getTerrainSelection(); + private: /// Remove duplicates and sort mAlteredCells, then limitAlteredHeights forward and reverse @@ -176,7 +178,7 @@ namespace CSVRender int mDragMode = InteractionType_None; osg::Group* mParentNode; bool mIsEditing = false; - std::unique_ptr mTerrainShapeSelection; + std::shared_ptr mTerrainShapeSelection; int mTotalDiffY = 0; std::vector mAlteredCells; osg::Vec3d mEditingPos; diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 4e267e9426..dfcc29ae01 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -712,6 +712,11 @@ void CSVRender::TerrainTextureMode::mouseMoveEvent (QMouseEvent *event) mBrushDraw->hide(); } +std::shared_ptr CSVRender::TerrainTextureMode::getTerrainSelection() +{ + return mTerrainTextureSelection; +} + void CSVRender::TerrainTextureMode::setBrushSize(int brushSize) { diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index 31932df217..e0c6e4b40f 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -85,6 +85,8 @@ namespace CSVRender void mouseMoveEvent (QMouseEvent *event) override; + std::shared_ptr getTerrainSelection(); + private: /// \brief Handle brush mechanics, maths regarding worldspace hit etc. void editTerrainTextureGrid (const WorldspaceHitResult& hit); @@ -115,7 +117,7 @@ namespace CSVRender int mDragMode; osg::Group* mParentNode; bool mIsEditing; - std::unique_ptr mTerrainTextureSelection; + std::shared_ptr mTerrainTextureSelection; const int cellSize {ESM::Land::REAL_SIZE}; const int landTextureSize {ESM::Land::LAND_TEXTURE_SIZE}; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index b14b7953ab..c51479f897 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -452,6 +452,11 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo return hit; } +CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode() +{ + return dynamic_cast (mEditMode->getCurrent()); +} + void CSVRender::WorldspaceWidget::abortDrag() { if (mDragging) @@ -697,11 +702,6 @@ void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitRes editMode.primaryOpenPressed (hit); } -CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode() -{ - return dynamic_cast (mEditMode->getCurrent()); -} - void CSVRender::WorldspaceWidget::primaryOpen(bool activate) { handleInteraction(InteractionType_PrimaryOpen, activate); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 5e224b3803..cf244ce712 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -189,6 +189,8 @@ namespace CSVRender /// Erase all overrides and restore the visual representation to its true state. virtual void reset (unsigned int elementMask) = 0; + EditMode *getEditMode(); + protected: /// Visual elements in a scene @@ -215,8 +217,6 @@ namespace CSVRender void settingChanged (const CSMPrefs::Setting *setting) override; - EditMode *getEditMode(); - bool getSpeedMode(); private: