From 9112c65afcfb8c9826a6a285ae72941fa94f14a7 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 18 Aug 2021 19:52:08 +0200 Subject: [PATCH 01/59] Use pathgrid path when destination is closer to different graph component node Partially revert d863267d5cb5f4062937f86c37af3b0c8f9479cf to restore 0.46 behaviour for pathgrid based pathfinding. --- apps/openmw/mwmechanics/pathfinding.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 2f8e830434..0e704cd466 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -206,9 +206,6 @@ namespace MWMechanics endPointInLocalCoords, startNode); - if (!endNode.second) - return; - // if it's shorter for actor to travel from start to end, than to travel from either // start or end to nearest pathgrid point, just travel from start to end. float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2(); @@ -279,7 +276,8 @@ namespace MWMechanics // unreachable pathgrid point. // // The AI routines will have to deal with such situations. - *out++ = endPoint; + if (endNode.second) + *out++ = endPoint; } float PathFinder::getZAngleToNext(float x, float y) const From b4486992f02757b871a3a469c1ba0b04485803bd Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sat, 28 Aug 2021 10:45:00 +0200 Subject: [PATCH 02/59] Allow Rieklings and Goblins to attack again --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 62c130b36e..ed26e2b9a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1653,7 +1653,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) MWRender::Animation::BlendMask_All, false, weapSpeed, startKey, stopKey, 0.0f, 0); - if(mAnimation->isPlaying(mCurrentWeapon)) + if(mAnimation->getCurrentTime(mCurrentWeapon) != -1.f) mUpperBodyState = UpperCharState_StartToMinAttack; } } From a6b1e38eab0fe9e96975834d26b68cfc70294b5e Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 14:12:14 +0200 Subject: [PATCH 03/59] Don't use comma where there is no need to. --- apps/openmw/mwgui/bookpage.cpp | 7 +++++-- apps/openmw/mwgui/mapwindow.cpp | 6 ++++-- apps/openmw/mwrender/terrainstorage.cpp | 5 ++++- apps/openmw/mwworld/store.cpp | 6 ++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 2bfec8105b..874d1d866b 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -491,7 +491,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { add_partial_text(); stream.consume (); - mLine = nullptr, mRun = nullptr; + mLine = nullptr; + mRun = nullptr; continue; } @@ -551,7 +552,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter if (left + space_width + word_width > mPageWidth) { - mLine = nullptr, mRun = nullptr, left = 0; + mLine = nullptr; + mRun = nullptr; + left = 0; } else { diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index e42808776c..388bbc7d48 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -988,7 +988,8 @@ namespace MWGui if (mInterior) { auto pos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition(); - x = pos.x(), y = pos.y(); + x = pos.x(); + y = pos.y(); } setGlobalMapPlayerPosition(x, y); @@ -1160,7 +1161,8 @@ namespace MWGui void MapWindow::worldPosToGlobalMapImageSpace(float x, float y, float& imageX, float& imageY) const { mGlobalMapRender->worldPosToImageSpace(x, y, imageX, imageY); - imageX *= mGlobalMapZoom, imageY *= mGlobalMapZoom; + imageX *= mGlobalMapZoom; + imageY *= mGlobalMapZoom; } void MapWindow::updateCustomMarkers() diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index 528ce70ea3..879a2ef68b 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -33,7 +33,10 @@ namespace MWRender void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY) { - minX = 0, minY = 0, maxX = 0, maxY = 0; + minX = 0; + minY = 0; + maxX = 0; + maxY = 0; const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index f6de1d485b..718cebd790 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -520,7 +520,8 @@ namespace MWWorld const ESM::Cell *Store::search(int x, int y) const { ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; + cell.mData.mX = x; + cell.mData.mY = y; std::pair key(x, y); DynamicExt::const_iterator it = mExt.find(key); @@ -538,7 +539,8 @@ namespace MWWorld const ESM::Cell *Store::searchStatic(int x, int y) const { ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; + cell.mData.mX = x; + cell.mData.mY = y; std::pair key(x, y); DynamicExt::const_iterator it = mExt.find(key); From a15cca5763fa32c3d1b66f288c3ebae196f72d5c Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 19:20:49 +0200 Subject: [PATCH 04/59] Use `reserve` on vectors for fixed loops This is a bit useless, but has the merit of appeasing clang-tiday --- apps/openmw/mwgui/class.cpp | 2 ++ apps/openmw/mwrender/screenshotmanager.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index ee5fe59399..1732bc24ea 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -517,6 +517,7 @@ namespace MWGui std::vector CreateClassDialog::getMajorSkills() const { std::vector v; + v.reserve(5); for(int i = 0; i < 5; i++) { v.push_back(mMajorSkill[i]->getSkillId()); @@ -527,6 +528,7 @@ namespace MWGui std::vector CreateClassDialog::getMinorSkills() const { std::vector v; + v.reserve(5); for(int i=0; i < 5; i++) { v.push_back(mMinorSkill[i]->getSkillId()); diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index b9ea5daacf..5a047a1566 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -191,6 +191,7 @@ namespace MWRender screenshotH = screenshotW; // use square resolution for planet mapping std::vector> images; + images.reserve(6); for (int i = 0; i < 6; ++i) images.push_back(new osg::Image); From deb2af6accb3d6c8063f618703a24f03e7681612 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 20:22:34 +0200 Subject: [PATCH 05/59] Dont copy-construct from a const-ref when used only as a const-ref This also makes clang-tiny a bit happier --- apps/opencs/view/tools/searchsubview.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 4 ++-- components/resource/bulletshape.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/tools/searchsubview.cpp b/apps/opencs/view/tools/searchsubview.cpp index 07ba7907e7..d687cbeb3f 100644 --- a/apps/opencs/view/tools/searchsubview.cpp +++ b/apps/opencs/view/tools/searchsubview.cpp @@ -36,7 +36,7 @@ void CSVTools::SearchSubView::replace (bool selection) // in a single string. for (std::vector::const_reverse_iterator iter (indices.rbegin()); iter!=indices.rend(); ++iter) { - CSMWorld::UniversalId id = model.getUniversalId (*iter); + const CSMWorld::UniversalId& id = model.getUniversalId (*iter); CSMWorld::UniversalId::Type type = CSMWorld::UniversalId::getParentType (id.getType()); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index eead3919e0..f53ba21f9f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -704,7 +704,7 @@ namespace MWGui if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory)) return; // make sure the object is of a type that can be picked up - std::string type = object.getTypeName(); + const std::string& type = object.getTypeName(); if ( (type != typeid(ESM::Apparatus).name()) && (type != typeid(ESM::Armor).name()) && (type != typeid(ESM::Book).name()) diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index d96447f87d..0b8af4463c 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -143,7 +143,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, if (allowAutoEquip && actorPtr != MWMechanics::getPlayer() && actorPtr.getClass().isNpc() && !actorPtr.getClass().getNpcStats(actorPtr).isWerewolf()) { - std::string type = itemPtr.getTypeName(); + const std::string& type = itemPtr.getTypeName(); if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actorPtr); } @@ -748,7 +748,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor if (equipReplacement && wasEquipped && (actor != MWMechanics::getPlayer()) && actor.getClass().isNpc() && !actor.getClass().getNpcStats(actor).isWerewolf()) { - std::string type = item.getTypeName(); + const std::string& type = item.getTypeName(); if (type == typeid(ESM::Armor).name() || type == typeid(ESM::Clothing).name()) autoEquip(actor); } diff --git a/components/resource/bulletshape.cpp b/components/resource/bulletshape.cpp index ce896610a9..798a6778e6 100644 --- a/components/resource/bulletshape.cpp +++ b/components/resource/bulletshape.cpp @@ -58,7 +58,7 @@ btCollisionShape* BulletShape::duplicateCollisionShape(const btCollisionShape *s for(int i = 0;i < numShapes;++i) { btCollisionShape *child = duplicateCollisionShape(comp->getChildShape(i)); - btTransform trans = comp->getChildTransform(i); + const btTransform& trans = comp->getChildTransform(i); newShape->addChildShape(trans, child); } From db4fe11a44cd4ddd232cf22c296dd7d83863f075 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 14:47:08 +0200 Subject: [PATCH 06/59] Don't pass a nullptr to a std::string constructor This is undefined behaviour. --- apps/openmw/mwworld/store.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 88edb71ddf..4b1d648703 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -428,7 +428,7 @@ namespace MWWorld const ESM::WeaponType *search(const int id) const; const ESM::WeaponType *find(const int id) const; - RecordId load(ESM::ESMReader &esm) override { return RecordId(nullptr, false); } + RecordId load(ESM::ESMReader &esm) override { return RecordId({}, false); } ESM::WeaponType* insert(const ESM::WeaponType &weaponType); From 33d4d884474d83951445283c58e094cb6043dd3a Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Tue, 31 Aug 2021 09:37:27 +0200 Subject: [PATCH 07/59] Function LuaUtil::toString --- apps/openmw_test_suite/lua/test_lua.cpp | 8 ++++++++ apps/openmw_test_suite/lua/test_utilpackage.cpp | 2 ++ components/lua/luastate.cpp | 10 ++++++++++ components/lua/luastate.hpp | 3 +++ 4 files changed, 23 insertions(+) diff --git a/apps/openmw_test_suite/lua/test_lua.cpp b/apps/openmw_test_suite/lua/test_lua.cpp index 69a326060c..9405dba4b2 100644 --- a/apps/openmw_test_suite/lua/test_lua.cpp +++ b/apps/openmw_test_suite/lua/test_lua.cpp @@ -77,6 +77,14 @@ return { EXPECT_EQ(LuaUtil::call(script1["get"]).get(), 45); } + TEST_F(LuaStateTest, ToString) + { + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), 3.14)), "3.14"); + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), true)), "true"); + EXPECT_EQ(LuaUtil::toString(sol::nil), "nil"); + EXPECT_EQ(LuaUtil::toString(sol::make_object(mLua.sol(), "something")), "\"something\""); + } + TEST_F(LuaStateTest, ErrorHandling) { EXPECT_ERROR(mLua.runInNewSandbox("invalid.lua"), "[string \"invalid.lua\"]:1:"); diff --git a/apps/openmw_test_suite/lua/test_utilpackage.cpp b/apps/openmw_test_suite/lua/test_utilpackage.cpp index afd9fa2d3c..fb8e48e461 100644 --- a/apps/openmw_test_suite/lua/test_utilpackage.cpp +++ b/apps/openmw_test_suite/lua/test_utilpackage.cpp @@ -1,6 +1,7 @@ #include "gmock/gmock.h" #include +#include #include #include "testing_util.hpp" @@ -45,6 +46,7 @@ namespace EXPECT_FLOAT_EQ(lua.safe_script("return v.y").get(), 12); EXPECT_FLOAT_EQ(lua.safe_script("return v.z").get(), 13); EXPECT_EQ(lua.safe_script("return tostring(v)").get(), "(5, 12, 13)"); + EXPECT_EQ(LuaUtil::toString(lua.safe_script("return v")), "(5, 12, 13)"); EXPECT_FLOAT_EQ(lua.safe_script("return util.vector3(4, 0, 3):length()").get(), 5); EXPECT_FLOAT_EQ(lua.safe_script("return util.vector3(4, 0, 3):length2()").get(), 25); EXPECT_FALSE(lua.safe_script("return util.vector3(1, 2, 3) == util.vector3(1, 3, 2)").get()); diff --git a/components/lua/luastate.cpp b/components/lua/luastate.cpp index 1b52db11ad..fd42aa7fb2 100644 --- a/components/lua/luastate.cpp +++ b/components/lua/luastate.cpp @@ -167,4 +167,14 @@ namespace LuaUtil #endif } + std::string toString(const sol::object& obj) + { + if (obj == sol::nil) + return "nil"; + else if (obj.get_type() == sol::type::string) + return "\"" + obj.as() + "\""; + else + return call(sol::state_view(obj.lua_state())["tostring"], obj); + } + } diff --git a/components/lua/luastate.hpp b/components/lua/luastate.hpp index 6bac1612e7..acaaadea76 100644 --- a/components/lua/luastate.hpp +++ b/components/lua/luastate.hpp @@ -103,6 +103,9 @@ namespace LuaUtil return getFieldOrNil(table.as()[first], str...); } + // String representation of a Lua object. Should be used for debugging/logging purposes only. + std::string toString(const sol::object&); + } #endif // COMPONENTS_LUA_LUASTATE_H From d1a5bc207b5d1a63d30bf3e3d5baf23f5b529155 Mon Sep 17 00:00:00 2001 From: fredzio Date: Tue, 31 Aug 2021 16:53:52 +0200 Subject: [PATCH 08/59] Iterate over mInactiveCells when unloading cells in TestCells / TestInteriorCells. Otherwise we dereference an invalid iterator after deactiveCell(). --- apps/openmw/mwworld/scene.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 5fa9be1be5..90e5bc265e 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -742,14 +742,12 @@ namespace MWWorld { loadingListener->setLabel("Testing exterior cells ("+std::to_string(i)+"/"+std::to_string(cells.getExtSize())+")..."); - CellStoreCollection::iterator iter = mActiveCells.begin(); - CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY); loadInactiveCell (cell, loadingListener, true); activateCell (cell, loadingListener, false, true); - iter = mActiveCells.begin(); - while (iter != mActiveCells.end()) + auto iter = mInactiveCells.begin(); + while (iter != mInactiveCells.end()) { if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() && it->mData.mY == (*iter)->getCell()->getGridY()) @@ -796,8 +794,8 @@ namespace MWWorld loadInactiveCell (cell, loadingListener, true); activateCell (cell, loadingListener, false, true); - CellStoreCollection::iterator iter = mActiveCells.begin(); - while (iter != mActiveCells.end()) + auto iter = mInactiveCells.begin(); + while (iter != mInactiveCells.end()) { assert (!(*iter)->getCell()->isExterior()); From 0d511da615991a332edc574763f9639fe1dfaaa2 Mon Sep 17 00:00:00 2001 From: unelsson Date: Mon, 30 Aug 2021 00:26:26 +0300 Subject: [PATCH 09/59] Test of basic mouse-plane use --- apps/opencs/view/render/instancemode.cpp | 35 ++++++------------------ apps/opencs/view/render/instancemode.hpp | 1 + 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 99ddce7f7d..d511523574 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -305,6 +305,9 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos) if (mSubModeId == "move") { objectTag->mObject->setEdited (Object::Override_Position); + mDragStart.x() = objectTag->mObject->getPosition().pos[0]; + mDragStart.y() = objectTag->mObject->getPosition().pos[1]; + mDragStart.z() = objectTag->mObject->getPosition().pos[2]; mDragMode = DragMode_Move; } else if (mSubModeId == "rotate") @@ -392,29 +395,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); - if (mDragMode == DragMode_Move) - { - osg::Vec3f eye, centre, up; - getWorldspaceWidget().getCamera()->getViewMatrix().getLookAt (eye, centre, up); - - if (diffY) - { - offset += up * diffY * speedFactor; - } - if (diffX) - { - offset += ((centre-eye) ^ up) * diffX * speedFactor; - } - - if (mDragAxis!=-1) - { - for (int i=0; i<3; ++i) - { - if (i!=mDragAxis) - offset[i] = 0; - } - } - } + if (mDragMode == DragMode_Move) {} else if (mDragMode == DragMode_Rotate) { osg::Vec3f eye, centre, up; @@ -522,10 +503,10 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou if (mDragMode == DragMode_Move) { ESM::Position position = objectTag->mObject->getPosition(); - for (int i=0; i<3; ++i) - { - position.pos[i] += offset[i]; - } + osg::Vec3d mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart)); + position.pos[0] = mousePos.x(); + position.pos[1] = mousePos.y(); + position.pos[2] = mousePos.z(); objectTag->mObject->setPosition(position.pos); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 73b7fff12a..3eb140a9af 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -45,6 +45,7 @@ namespace CSVRender bool mLocked; float mUnitScaleDist; osg::ref_ptr mParentNode; + osg::Vec3d mDragStart; int getSubModeFromId (const std::string& id) const; From 840e7615f5eaa27e1beb2d1b0f9e137e16dca1b7 Mon Sep 17 00:00:00 2001 From: unelsson Date: Wed, 1 Sep 2021 00:15:10 +0300 Subject: [PATCH 10/59] Store object origins and move difference --- apps/opencs/view/render/instancemode.cpp | 24 +++++++++++++++++------- apps/opencs/view/render/instancemode.hpp | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index d511523574..5d07bf1422 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -297,6 +297,8 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos) return false; } + mObjectsAtDragStart.clear(); + for (std::vector >::iterator iter (selection.begin()); iter!=selection.end(); ++iter) { @@ -305,9 +307,12 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos) if (mSubModeId == "move") { objectTag->mObject->setEdited (Object::Override_Position); - mDragStart.x() = objectTag->mObject->getPosition().pos[0]; - mDragStart.y() = objectTag->mObject->getPosition().pos[1]; - mDragStart.z() = objectTag->mObject->getPosition().pos[2]; + double x = objectTag->mObject->getPosition().pos[0]; + double y = objectTag->mObject->getPosition().pos[1]; + double z = objectTag->mObject->getPosition().pos[2]; + osg::Vec3d thisPoint(x, y, z); + mDragStart = getMousePlaneCoords(pos, getProjectionSpaceCoords(thisPoint)); + mObjectsAtDragStart.emplace_back(thisPoint); mDragMode = DragMode_Move; } else if (mSubModeId == "rotate") @@ -495,8 +500,10 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou return; } + int i = 0; + // Apply - for (std::vector >::iterator iter (selection.begin()); iter!=selection.end(); ++iter) + for (std::vector >::iterator iter (selection.begin()); iter!=selection.end(); ++iter, i++) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) { @@ -504,9 +511,12 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou { ESM::Position position = objectTag->mObject->getPosition(); osg::Vec3d mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart)); - position.pos[0] = mousePos.x(); - position.pos[1] = mousePos.y(); - position.pos[2] = mousePos.z(); + float addToX = mousePos.x() - mDragStart.x(); + float addToY = mousePos.y() - mDragStart.y(); + float addToZ = mousePos.z() - mDragStart.z(); + position.pos[0] = mObjectsAtDragStart[i].x() + addToX; + position.pos[1] = mObjectsAtDragStart[i].y() + addToY; + position.pos[2] = mObjectsAtDragStart[i].z() + addToZ; objectTag->mObject->setPosition(position.pos); } diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 3eb140a9af..5ddc5f7c27 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -46,6 +46,7 @@ namespace CSVRender float mUnitScaleDist; osg::ref_ptr mParentNode; osg::Vec3d mDragStart; + std::vector mObjectsAtDragStart; int getSubModeFromId (const std::string& id) const; From 23fe3d74ab9b66f060b684d0509895485c1c5787 Mon Sep 17 00:00:00 2001 From: unelsson Date: Wed, 1 Sep 2021 00:24:50 +0300 Subject: [PATCH 11/59] Use floats, not doubles --- apps/opencs/view/render/instancemode.cpp | 10 +++++----- apps/opencs/view/render/instancemode.hpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 5d07bf1422..535179b61f 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -307,10 +307,10 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos) if (mSubModeId == "move") { objectTag->mObject->setEdited (Object::Override_Position); - double x = objectTag->mObject->getPosition().pos[0]; - double y = objectTag->mObject->getPosition().pos[1]; - double z = objectTag->mObject->getPosition().pos[2]; - osg::Vec3d thisPoint(x, y, z); + float x = objectTag->mObject->getPosition().pos[0]; + float y = objectTag->mObject->getPosition().pos[1]; + float z = objectTag->mObject->getPosition().pos[2]; + osg::Vec3f thisPoint(x, y, z); mDragStart = getMousePlaneCoords(pos, getProjectionSpaceCoords(thisPoint)); mObjectsAtDragStart.emplace_back(thisPoint); mDragMode = DragMode_Move; @@ -510,7 +510,7 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou if (mDragMode == DragMode_Move) { ESM::Position position = objectTag->mObject->getPosition(); - osg::Vec3d mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart)); + osg::Vec3f mousePos = getMousePlaneCoords(pos, getProjectionSpaceCoords(mDragStart)); float addToX = mousePos.x() - mDragStart.x(); float addToY = mousePos.y() - mDragStart.y(); float addToZ = mousePos.z() - mDragStart.z(); diff --git a/apps/opencs/view/render/instancemode.hpp b/apps/opencs/view/render/instancemode.hpp index 5ddc5f7c27..4ece934e93 100644 --- a/apps/opencs/view/render/instancemode.hpp +++ b/apps/opencs/view/render/instancemode.hpp @@ -45,8 +45,8 @@ namespace CSVRender bool mLocked; float mUnitScaleDist; osg::ref_ptr mParentNode; - osg::Vec3d mDragStart; - std::vector mObjectsAtDragStart; + osg::Vec3f mDragStart; + std::vector mObjectsAtDragStart; int getSubModeFromId (const std::string& id) const; From 53d315c862f75121865fbfacb33a1bdee9ebf543 Mon Sep 17 00:00:00 2001 From: unelsson Date: Wed, 1 Sep 2021 01:37:17 +0300 Subject: [PATCH 12/59] XYZ-locking, mouse wheel move fix --- apps/opencs/view/render/instancemode.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index 535179b61f..ead1a8fdba 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -518,6 +518,16 @@ void CSVRender::InstanceMode::drag (const QPoint& pos, int diffX, int diffY, dou position.pos[1] = mObjectsAtDragStart[i].y() + addToY; position.pos[2] = mObjectsAtDragStart[i].z() + addToZ; + // XYZ-locking + if (mDragAxis != -1) + { + for (int j = 0; j < 3; ++j) + { + if (j != mDragAxis) + position.pos[j] = mObjectsAtDragStart[i][j]; + } + } + objectTag->mObject->setPosition(position.pos); } else if (mDragMode == DragMode_Rotate) @@ -625,8 +635,10 @@ void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor) std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); + int j = 0; + for (std::vector >::iterator iter (selection.begin()); - iter!=selection.end(); ++iter) + iter!=selection.end(); ++iter, j++) { if (CSVRender::ObjectTag *objectTag = dynamic_cast (iter->get())) { @@ -634,6 +646,9 @@ void CSVRender::InstanceMode::dragWheel (int diff, double speedFactor) for (int i=0; i<3; ++i) position.pos[i] += offset[i]; objectTag->mObject->setPosition (position.pos); + osg::Vec3f thisPoint(position.pos[0], position.pos[1], position.pos[2]); + mDragStart = getMousePlaneCoords(getWorldspaceWidget().mapFromGlobal(QCursor::pos()), getProjectionSpaceCoords(thisPoint)); + mObjectsAtDragStart[j] = thisPoint; } } } From f876ff2c14de2204e4dbda30c73d0cc898f5fd26 Mon Sep 17 00:00:00 2001 From: unelsson Date: Wed, 1 Sep 2021 01:56:11 +0300 Subject: [PATCH 13/59] Clear temporary movement data at the end of the drag --- apps/opencs/view/render/instancemode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index ead1a8fdba..ebb7f46fa5 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -609,6 +609,7 @@ void CSVRender::InstanceMode::dragCompleted(const QPoint& pos) } } + mObjectsAtDragStart.clear(); mDragMode = DragMode_None; } From 8edcaeb323fb4395537e1ca414a0aa262aea10a5 Mon Sep 17 00:00:00 2001 From: unelsson Date: Wed, 1 Sep 2021 02:03:03 +0300 Subject: [PATCH 14/59] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17337f7346..bc9c79411b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Feature #6032: Reverse-z depth buffer Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly Feature #6199: Support FBO Rendering + Feature #6251: OpenMW-CS: Set instance movement based on camera zoom 0.47.0 ------ From d4e3575f1d5b091ec47c55002c6ca0b947cb506f Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 20:13:32 +0200 Subject: [PATCH 15/59] Don't use `const` for objects returned by value. This prevents the usage of std::move semantics, and makes clang-tidy sad. --- apps/opencs/model/world/actoradapter.cpp | 4 ++-- apps/opencs/model/world/actoradapter.hpp | 2 +- apps/openmw/engine.cpp | 2 +- components/detournavigator/cachedrecastmeshmanager.cpp | 2 +- components/detournavigator/tilecachedrecastmeshmanager.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 8558aa9bc9..86a621970c 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -121,7 +121,7 @@ namespace CSMWorld return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf); } - const std::string ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const + const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { auto it = mParts.find(index); if (it == mParts.end()) @@ -131,7 +131,7 @@ namespace CSMWorld if (mFemale) { // Note: we should use male parts for females as fallback - const std::string femalePart = mRaceData->getFemalePart(index); + const std::string& femalePart = mRaceData->getFemalePart(index); if (!femalePart.empty()) return femalePart; } diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index 912a6bcb38..df3eeff64e 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -93,7 +93,7 @@ namespace CSMWorld /// Returns the skeleton the actor should use for attaching parts to std::string getSkeleton() const; /// Retrieves the associated actor part - const std::string getPart(ESM::PartReferenceType index) const; + const std::string& getPart(ESM::PartReferenceType index) const; /// Checks if the actor has a data dependency bool hasDependency(const std::string& id) const; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index f968bbfac7..772af3759e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -521,7 +521,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) throw std::runtime_error ("No default settings file found! Make sure the file \"defaults.bin\" was properly installed."); // load user settings if they exist - const std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); + std::string settingspath = (mCfgMgr.getUserConfigPath() / "settings.cfg").string(); if (boost::filesystem::exists(settingspath)) settings.loadUser(settingspath); diff --git a/components/detournavigator/cachedrecastmeshmanager.cpp b/components/detournavigator/cachedrecastmeshmanager.cpp index e7e5886589..19b87aa820 100644 --- a/components/detournavigator/cachedrecastmeshmanager.cpp +++ b/components/detournavigator/cachedrecastmeshmanager.cpp @@ -27,7 +27,7 @@ namespace DetourNavigator std::optional CachedRecastMeshManager::removeObject(const ObjectId id) { - const auto object = mImpl.removeObject(id); + auto object = mImpl.removeObject(id); if (object) mCached.lock()->reset(); return object; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 38314f08a5..63d7e13f6b 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -248,7 +248,7 @@ namespace DetourNavigator const auto tile = tiles.find(tilePosition); if (tile == tiles.end()) return std::optional(); - const auto tileResult = tile->second->removeObject(id); + auto tileResult = tile->second->removeObject(id); if (tile->second->isEmpty()) { tiles.erase(tile); From d20730458db884ef0f05c06ab8497772ca15312b Mon Sep 17 00:00:00 2001 From: fredzio Date: Thu, 12 Aug 2021 20:54:42 +0200 Subject: [PATCH 16/59] Replace std::map with std::unordered_map for mActors and mObjects. Use Ptr.mRef as a key instead of Ptr: it is constant for the lifetime of the object. --- apps/openmw/mwphysics/physicssystem.cpp | 109 +++++++++--------------- apps/openmw/mwphysics/physicssystem.hpp | 5 +- 2 files changed, 44 insertions(+), 70 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 5b50962be9..d248b599ee 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -181,7 +181,7 @@ namespace MWPhysics void PhysicsSystem::markAsNonSolid(const MWWorld::ConstPtr &ptr) { - ObjectMap::iterator found = mObjects.find(ptr); + ObjectMap::iterator found = mObjects.find(ptr.mRef); if (found == mObjects.end()) return; @@ -198,7 +198,7 @@ namespace MWPhysics if (obj.isEmpty()) return true; // assume standing on terrain (which is a non-object, so not collision tracked) - ObjectMap::const_iterator foundObj = mObjects.find(obj); + ObjectMap::const_iterator foundObj = mObjects.find(obj.mRef); if (foundObj == mObjects.end()) return false; @@ -374,8 +374,8 @@ namespace MWPhysics bool PhysicsSystem::getLineOfSight(const MWWorld::ConstPtr &actor1, const MWWorld::ConstPtr &actor2) const { - const auto it1 = mActors.find(actor1); - const auto it2 = mActors.find(actor2); + const auto it1 = mActors.find(actor1.mRef); + const auto it2 = mActors.find(actor2.mRef); if (it1 == mActors.end() || it2 == mActors.end()) return false; @@ -441,7 +441,7 @@ namespace MWPhysics { btCollisionObject* me = nullptr; - auto found = mObjects.find(ptr); + auto found = mObjects.find(ptr.mRef); if (found != mObjects.end()) me = found->second->getCollisionObject(); else @@ -464,7 +464,7 @@ namespace MWPhysics osg::Vec3f PhysicsSystem::traceDown(const MWWorld::Ptr &ptr, const osg::Vec3f& position, float maxHeight) { - ActorMap::iterator found = mActors.find(ptr); + ActorMap::iterator found = mActors.find(ptr.mRef); if (found == mActors.end()) return ptr.getRefData().getPosition().asVec3(); return MovementSolver::traceDown(ptr, position, found->second.get(), mCollisionWorld.get(), maxHeight); @@ -504,7 +504,7 @@ namespace MWPhysics assert(!getObject(ptr)); auto obj = std::make_shared(ptr, shapeInstance, rotation, collisionType, mTaskScheduler.get()); - mObjects.emplace(ptr, obj); + mObjects.emplace(ptr.mRef, obj); if (obj->isAnimated()) mAnimatedObjects.insert(obj.get()); @@ -512,8 +512,7 @@ namespace MWPhysics void PhysicsSystem::remove(const MWWorld::Ptr &ptr) { - ObjectMap::iterator found = mObjects.find(ptr); - if (found != mObjects.end()) + if (auto found = mObjects.find(ptr.mRef); found != mObjects.end()) { if (mUnrefQueue.get()) mUnrefQueue->push(found->second->getShapeInstance()); @@ -522,11 +521,9 @@ namespace MWPhysics mObjects.erase(found); } - - ActorMap::iterator foundActor = mActors.find(ptr); - if (foundActor != mActors.end()) + else if (auto found = mActors.find(ptr.mRef); found != mActors.end()) { - mActors.erase(foundActor); + mActors.erase(found); } } @@ -539,22 +536,10 @@ namespace MWPhysics void PhysicsSystem::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated) { - ObjectMap::iterator found = mObjects.find(old); - if (found != mObjects.end()) - { - auto obj = found->second; - obj->updatePtr(updated); - mObjects.erase(found); - mObjects.emplace(updated, std::move(obj)); - } - - auto actorNode = mActors.extract(old); - if (!actorNode.empty()) - { - actorNode.key() = updated; - actorNode.mapped()->updatePtr(updated); - mActors.insert(std::move(actorNode)); - } + if (auto found = mObjects.find(old.mRef); found != mObjects.end()) + found->second->updatePtr(updated); + else if (auto found = mActors.find(old.mRef); found != mActors.end()) + found->second->updatePtr(updated); for (auto& [_, actor] : mActors) { @@ -572,7 +557,7 @@ namespace MWPhysics Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) { - ActorMap::iterator found = mActors.find(ptr); + ActorMap::iterator found = mActors.find(ptr.mRef); if (found != mActors.end()) return found->second.get(); return nullptr; @@ -580,7 +565,7 @@ namespace MWPhysics const Actor *PhysicsSystem::getActor(const MWWorld::ConstPtr &ptr) const { - ActorMap::const_iterator found = mActors.find(ptr); + ActorMap::const_iterator found = mActors.find(ptr.mRef); if (found != mActors.end()) return found->second.get(); return nullptr; @@ -588,7 +573,7 @@ namespace MWPhysics const Object* PhysicsSystem::getObject(const MWWorld::ConstPtr &ptr) const { - ObjectMap::const_iterator found = mObjects.find(ptr); + ObjectMap::const_iterator found = mObjects.find(ptr.mRef); if (found != mObjects.end()) return found->second.get(); return nullptr; @@ -604,20 +589,16 @@ namespace MWPhysics void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { - ObjectMap::iterator found = mObjects.find(ptr); - if (found != mObjects.end()) + if (auto found = mObjects.find(ptr.mRef); found != mObjects.end()) { float scale = ptr.getCellRef().getScale(); found->second->setScale(scale); mTaskScheduler->updateSingleAabb(found->second); - return; } - ActorMap::iterator foundActor = mActors.find(ptr); - if (foundActor != mActors.end()) + else if (auto found = mActors.find(ptr.mRef); found != mActors.end()) { - foundActor->second->updateScale(); - mTaskScheduler->updateSingleAabb(foundActor->second); - return; + found->second->updateScale(); + mTaskScheduler->updateSingleAabb(found->second); } } @@ -650,40 +631,32 @@ namespace MWPhysics void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr, osg::Quat rotate) { - ObjectMap::iterator found = mObjects.find(ptr); - if (found != mObjects.end()) + if (auto found = mObjects.find(ptr.mRef); found != mObjects.end()) { found->second->setRotation(rotate); mTaskScheduler->updateSingleAabb(found->second); - return; } - ActorMap::iterator foundActor = mActors.find(ptr); - if (foundActor != mActors.end()) + else if (auto found = mActors.find(ptr.mRef); found != mActors.end()) { - if (!foundActor->second->isRotationallyInvariant()) + if (!found->second->isRotationallyInvariant()) { - foundActor->second->setRotation(rotate); - mTaskScheduler->updateSingleAabb(foundActor->second); + found->second->setRotation(rotate); + mTaskScheduler->updateSingleAabb(found->second); } - return; } } void PhysicsSystem::updatePosition(const MWWorld::Ptr &ptr) { - ObjectMap::iterator found = mObjects.find(ptr); - if (found != mObjects.end()) + if (auto found = mObjects.find(ptr.mRef); found != mObjects.end()) { found->second->updatePosition(); mTaskScheduler->updateSingleAabb(found->second); - return; } - ActorMap::iterator foundActor = mActors.find(ptr); - if (foundActor != mActors.end()) + else if (auto found = mActors.find(ptr.mRef); found != mActors.end()) { - foundActor->second->updatePosition(); - mTaskScheduler->updateSingleAabb(foundActor->second, true); - return; + found->second->updatePosition(); + mTaskScheduler->updateSingleAabb(found->second, true); } } @@ -710,7 +683,7 @@ namespace MWPhysics auto actor = std::make_shared(ptr, shape, mTaskScheduler.get(), canWaterWalk); - mActors.emplace(ptr, std::move(actor)); + mActors.emplace(ptr.mRef, std::move(actor)); } int PhysicsSystem::addProjectile (const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius, bool canTraverseWater) @@ -738,7 +711,7 @@ namespace MWPhysics bool PhysicsSystem::toggleCollisionMode() { - ActorMap::iterator found = mActors.find(MWMechanics::getPlayer()); + ActorMap::iterator found = mActors.find(MWMechanics::getPlayer().mRef); if (found != mActors.end()) { bool cmode = found->second->getCollisionMode(); @@ -753,7 +726,7 @@ namespace MWPhysics void PhysicsSystem::queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity) { - ActorMap::iterator found = mActors.find(ptr); + ActorMap::iterator found = mActors.find(ptr.mRef); if (found != mActors.end()) found->second->setVelocity(velocity); } @@ -770,13 +743,13 @@ namespace MWPhysics framedata.first.reserve(mActors.size()); framedata.second.reserve(mActors.size()); const MWBase::World *world = MWBase::Environment::get().getWorld(); - for (const auto& [actor, physicActor] : mActors) + for (const auto& [ref, physicActor] : mActors) { auto ptr = physicActor->getPtr(); - if (!actor.getClass().isMobile(ptr)) + if (!ptr.getClass().isMobile(ptr)) continue; float waterlevel = -std::numeric_limits::max(); - const MWWorld::CellStore *cell = actor.getCell(); + const MWWorld::CellStore *cell = ptr.getCell(); if(cell->getCell()->hasWater()) waterlevel = cell->getWaterLevel(); @@ -786,7 +759,7 @@ namespace MWPhysics bool waterCollision = false; if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()) { - if (physicActor->getCollisionMode() || !world->isUnderwater(actor.getCell(), actor.getRefData().getPosition().asVec3())) + if (physicActor->getCollisionMode() || !world->isUnderwater(ptr.getCell(), ptr.getRefData().getPosition().asVec3())) waterCollision = true; } @@ -813,7 +786,7 @@ namespace MWPhysics { if (animatedObject->animateCollisionShapes()) { - auto obj = mObjects.find(animatedObject->getPtr()); + auto obj = mObjects.find(animatedObject->getPtr().mRef); assert(obj != mObjects.end()); mTaskScheduler->updateSingleAabb(obj->second); } @@ -851,7 +824,7 @@ namespace MWPhysics void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object) { - ObjectMap::iterator found = mObjects.find(object); + ObjectMap::iterator found = mObjects.find(object.mRef); if (found != mObjects.end()) if (found->second->animateCollisionShapes()) mTaskScheduler->updateSingleAabb(found->second); @@ -865,7 +838,7 @@ namespace MWPhysics bool PhysicsSystem::isActorStandingOn(const MWWorld::Ptr &actor, const MWWorld::ConstPtr &object) const { - const auto physActor = mActors.find(actor); + const auto physActor = mActors.find(actor.mRef); if (physActor != mActors.end()) return physActor->second->getStandingOnPtr() == object; return false; @@ -943,7 +916,7 @@ namespace MWPhysics bool PhysicsSystem::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const { btCollisionObject* object = nullptr; - const auto it = mActors.find(ignore); + const auto it = mActors.find(ignore.mRef); if (it != mActors.end()) object = it->second->getCollisionObject(); const auto bulletPosition = Misc::Convert::toBullet(position); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index b20c8f88e1..78569bb0c3 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,7 @@ namespace MWPhysics class PhysicsTaskScheduler; class Projectile; - using ActorMap = std::map>; + using ActorMap = std::unordered_map>; struct ContactPoint { @@ -272,7 +273,7 @@ namespace MWPhysics std::unique_ptr mShapeManager; Resource::ResourceSystem* mResourceSystem; - using ObjectMap = std::map>; + using ObjectMap = std::unordered_map>; ObjectMap mObjects; std::set mAnimatedObjects; // stores pointers to elements in mObjects From a8c16071dc8977aabf258578bbfd912f91c51701 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 4 Sep 2021 18:04:43 +0200 Subject: [PATCH 17/59] Fix -Wreturn-local-addr warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /home/elsid/dev/openmw/apps/opencs/model/world/actoradapter.cpp: In member function ‘const string& CSMWorld::ActorAdapter::ActorData::getPart(ESM::PartReferenceType) const’: /home/elsid/dev/openmw/apps/opencs/model/world/actoradapter.cpp:142:20: error: returning reference to temporary [-Werror=return-local-addr] 142 | return ""; | ^~ --- apps/opencs/model/world/actoradapter.cpp | 7 +++++-- apps/opencs/model/world/actoradapter.hpp | 4 +++- apps/opencs/view/render/actor.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 86a621970c..7882dd4535 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -9,6 +9,9 @@ #include "data.hpp" +#include +#include + namespace CSMWorld { const std::string& ActorAdapter::RaceData::getId() const @@ -121,7 +124,7 @@ namespace CSMWorld return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf); } - const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const + std::string_view ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const { auto it = mParts.find(index); if (it == mParts.end()) @@ -139,7 +142,7 @@ namespace CSMWorld return mRaceData->getMalePart(index); } - return ""; + return {}; } const std::string& partName = it->second.first; diff --git a/apps/opencs/model/world/actoradapter.hpp b/apps/opencs/model/world/actoradapter.hpp index df3eeff64e..826e3b9179 100644 --- a/apps/opencs/model/world/actoradapter.hpp +++ b/apps/opencs/model/world/actoradapter.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -93,7 +95,7 @@ namespace CSMWorld /// Returns the skeleton the actor should use for attaching parts to std::string getSkeleton() const; /// Retrieves the associated actor part - const std::string& getPart(ESM::PartReferenceType index) const; + std::string_view getPart(ESM::PartReferenceType index) const; /// Checks if the actor has a data dependency bool hasDependency(const std::string& id) const; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index d6077a65a5..10f7330d1c 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -96,7 +96,7 @@ namespace CSVRender for (int i = 0; i < ESM::PRT_Count; ++i) { auto type = (ESM::PartReferenceType) i; - std::string partId = mActorData->getPart(type); + const std::string partId(mActorData->getPart(type)); attachBodyPart(type, getBodyPartMesh(partId)); } } From cb08f490d7efb9d4cede6edbfadec1f2af650aca Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 29 Aug 2021 15:15:45 +0200 Subject: [PATCH 18/59] Sprinkle some const-ref in loop This was done on the good advices of clang-tidy --- components/resource/keyframemanager.cpp | 2 +- components/shader/shadermanager.cpp | 17 ++++++++--------- components/terrain/buffercache.cpp | 8 ++++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 77c31d9ad7..444d2bd7aa 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -30,7 +30,7 @@ namespace Resource std::vector emulatedAnimations; - for (auto animation : mAnimationManager->getAnimationList()) + for (const auto& animation : mAnimationManager->getAnimationList()) { if (animation) { diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 9b057cdfc6..33f79415f1 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -371,11 +371,10 @@ namespace Shader void ShaderManager::setGlobalDefines(DefineMap & globalDefines) { mGlobalDefines = globalDefines; - for (auto shaderMapElement: mShaders) + for (const auto& [key, shader]: mShaders) { - std::string templateId = shaderMapElement.first.first; - ShaderManager::DefineMap defines = shaderMapElement.first.second; - osg::ref_ptr shader = shaderMapElement.second; + std::string templateId = key.first; + ShaderManager::DefineMap defines = key.second; if (shader == nullptr) // I'm not sure how to handle a shader that was already broken as there's no way to get a potential replacement to the nodes that need it. continue; @@ -391,13 +390,13 @@ namespace Shader void ShaderManager::releaseGLObjects(osg::State *state) { std::lock_guard lock(mMutex); - for (auto shader : mShaders) + for (const auto& [_, shader] : mShaders) { - if (shader.second != nullptr) - shader.second->releaseGLObjects(state); + if (shader != nullptr) + shader->releaseGLObjects(state); } - for (auto program : mPrograms) - program.second->releaseGLObjects(state); + for (const auto& [_, program] : mPrograms) + program->releaseGLObjects(state); } } diff --git a/components/terrain/buffercache.cpp b/components/terrain/buffercache.cpp index f9eb7ae635..399df16d34 100644 --- a/components/terrain/buffercache.cpp +++ b/components/terrain/buffercache.cpp @@ -245,13 +245,13 @@ namespace Terrain { { std::lock_guard lock(mIndexBufferMutex); - for (auto indexbuffer : mIndexBufferMap) - indexbuffer.second->releaseGLObjects(state); + for (const auto& [_, indexbuffer] : mIndexBufferMap) + indexbuffer->releaseGLObjects(state); } { std::lock_guard lock(mUvBufferMutex); - for (auto uvbuffer : mUvBufferMap) - uvbuffer.second->releaseGLObjects(state); + for (const auto& [_, uvbuffer] : mUvBufferMap) + uvbuffer->releaseGLObjects(state); } } From 1b1deeb59b56738c62dee2fe99aab51cadd8531c Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 4 Sep 2021 16:39:06 +0200 Subject: [PATCH 19/59] Fail CI build when not allowed warnings are present Put -Wno-error after -Wall to make it work properly for clang. --- CI/before_script.linux.sh | 8 ++++++++ CMakeLists.txt | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index 2687946f41..bc0eb0013d 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -14,6 +14,12 @@ if [[ "${BUILD_TESTS_ONLY}" ]]; then BUILD_BENCHMARKS=ON fi +CXX_FLAGS='-Werror -Wno-error=deprecated-declarations -Wno-error=nonnull -Wno-error=deprecated-copy' + +if [[ "${CXX}" == 'clang++' ]]; then + CXX_FLAGS="${CXX_FLAGS} -Wno-error=unused-lambda-capture -Wno-error=gnu-zero-variadic-macro-arguments" +fi + declare -a CMAKE_CONF_OPTS=( -DCMAKE_C_COMPILER="${CC:-/usr/bin/cc}" -DCMAKE_CXX_COMPILER="${CXX:-/usr/bin/c++}" @@ -24,6 +30,8 @@ declare -a CMAKE_CONF_OPTS=( -DBUILD_SHARED_LIBS=OFF -DUSE_SYSTEM_TINYXML=ON -DCMAKE_INSTALL_PREFIX=install + -DCMAKE_C_FLAGS='-Werror' + -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" ) if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then diff --git a/CMakeLists.txt b/CMakeLists.txt index c733c22ff5..52a824d4e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -512,7 +512,7 @@ endif() if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -pedantic -Wno-long-long") + set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wundef -Wno-unused-parameter -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") add_definitions( -DBOOST_NO_CXX11_SCOPED_ENUMS=ON ) if (APPLE) From 43538a5ca56955e7466237fa4d5610f5e41efad8 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 6 Sep 2021 00:00:56 +0200 Subject: [PATCH 20/59] Support commulative timeseries graph for osg stats --- scripts/osg_stats.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index 140a911fea..3397b58f26 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -13,11 +13,14 @@ import statistics import sys import termtables + @click.command() @click.option('--print_keys', is_flag=True, help='Print a list of all present keys in the input file.') @click.option('--timeseries', type=str, multiple=True, help='Show a graph for given metric over time.') +@click.option('--commulative_timeseries', type=str, multiple=True, + help='Show a graph for commulative sum of a given metric over time.') @click.option('--hist', type=str, multiple=True, help='Show a histogram for all values of given metric.') @click.option('--hist_ratio', nargs=2, type=str, multiple=True, @@ -34,6 +37,8 @@ import termtables help='Print table with stats for a given metric containing min, max, mean, median etc.') @click.option('--timeseries_sum', is_flag=True, help='Add a graph to timeseries for a sum per frame of all given timeseries metrics.') +@click.option('--commulative_timeseries_sum', is_flag=True, + help='Add a graph to timeseries for a sum per frame of all given commulative timeseries.') @click.option('--stats_sum', is_flag=True, help='Add a row to stats table for a sum per frame of all given stats metrics.') @click.option('--begin_frame', type=int, default=0, @@ -42,7 +47,8 @@ import termtables help='End processing at this frame.') @click.argument('path', default='', type=click.Path()) def main(print_keys, timeseries, hist, hist_ratio, stdev_hist, plot, stats, - timeseries_sum, stats_sum, begin_frame, end_frame, path): + timeseries_sum, stats_sum, begin_frame, end_frame, path, + commulative_timeseries, commulative_timeseries_sum): data = list(read_data(path)) keys = collect_unique_keys(data) frames = collect_per_frame(data=data, keys=keys, begin_frame=begin_frame, end_frame=end_frame) @@ -50,7 +56,9 @@ def main(print_keys, timeseries, hist, hist_ratio, stdev_hist, plot, stats, for v in keys: print(v) if timeseries: - draw_timeseries(frames=frames, keys=timeseries, timeseries_sum=timeseries_sum) + draw_timeseries(frames=frames, keys=timeseries, add_sum=timeseries_sum) + if commulative_timeseries: + draw_commulative_timeseries(frames=frames, keys=commulative_timeseries, add_sum=commulative_timeseries_sum) if hist: draw_hists(frames=frames, keys=hist) if hist_ratio: @@ -105,18 +113,30 @@ def collect_unique_keys(frames): return sorted(result) -def draw_timeseries(frames, keys, timeseries_sum): +def draw_timeseries(frames, keys, add_sum): fig, ax = matplotlib.pyplot.subplots() x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) for key in keys: ax.plot(x, frames[key], label=key) - if timeseries_sum: + if add_sum: ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label='sum') ax.grid(True) ax.legend() fig.canvas.set_window_title('timeseries') +def draw_commulative_timeseries(frames, keys, add_sum): + fig, ax = matplotlib.pyplot.subplots() + x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) + for key in keys: + ax.plot(x, numpy.cumsum(frames[key]), label=key) + if add_sum: + ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label='sum') + ax.grid(True) + ax.legend() + fig.canvas.set_window_title('commulative_timeseries') + + def draw_hists(frames, keys): fig, ax = matplotlib.pyplot.subplots() bins = numpy.linspace( From 7b26058fa51fc1db24d8583b094d20add4b1a0a1 Mon Sep 17 00:00:00 2001 From: Frederic Chardon Date: Mon, 6 Sep 2021 11:47:21 +0200 Subject: [PATCH 21/59] moveObject() has side effects that might invalidate iterators from mActors. Instead of iterating over mActors, make a copy of needed data and iterate over the copies. --- apps/openmw/mwphysics/physicssystem.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d248b599ee..b3c4ef6168 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -813,12 +813,20 @@ namespace MWPhysics { auto* player = getActor(MWMechanics::getPlayer()); auto* world = MWBase::Environment::get().getWorld(); - for (auto& [ptr, physicActor] : mActors) + + // copy new ptr position in temporary vector. player is handled separately as its movement might change active cell. + std::vector> newPositions; + newPositions.reserve(mActors.size() - 1); + for (const auto& [ptr, physicActor] : mActors) { if (physicActor.get() == player) continue; - world->moveObject(physicActor->getPtr(), physicActor->getSimulationPosition(), false, false); + newPositions.emplace_back(physicActor->getPtr(), physicActor->getSimulationPosition()); } + + for (auto& [ptr, pos] : newPositions) + world->moveObject(ptr, pos, false, false); + world->moveObject(player->getPtr(), player->getSimulationPosition(), false, false); } From b0f772af405c60f74fd98279ef509e4d32495e81 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 25 Aug 2021 20:49:22 +0200 Subject: [PATCH 22/59] Define dependency to OSG plugins in one place Each binary depending on components library requires OSG plugins to be linked. Duplicating dependecies for each binary does not give benefits and brings problems when new binary is added. --- apps/opencs/CMakeLists.txt | 25 ------------------------- apps/openmw/CMakeLists.txt | 25 ------------------------- components/CMakeLists.txt | 25 +++++++++++++++++++++++++ 3 files changed, 25 insertions(+), 50 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5435de07e2..4b3b8030e6 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -232,31 +232,6 @@ target_link_libraries(openmw-cs components_qt ) -if(OSG_STATIC) - unset(_osg_plugins_static_files) - add_library(openmw_cs_osg_plugins INTERFACE) - foreach(_plugin ${USED_OSG_PLUGINS}) - string(TOUPPER ${_plugin} _plugin_uc) - if(OPENMW_USE_SYSTEM_OSG) - list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) - else() - list(APPEND _osg_plugins_static_files $) - target_link_libraries(openmw_cs_osg_plugins INTERFACE $) - add_dependencies(openmw_cs_osg_plugins ${${_plugin_uc}_LIBRARY}) - endif() - endforeach() - # We use --whole-archive because OSG plugins use registration. - get_whole_archive_options(_opts ${_osg_plugins_static_files}) - target_link_options(openmw_cs_osg_plugins INTERFACE ${_opts}) - target_link_libraries(openmw-cs openmw_cs_osg_plugins) - - if(OPENMW_USE_SYSTEM_OSG) - # OSG plugin pkgconfig files are missing these dependencies. - # https://github.com/openscenegraph/OpenSceneGraph/issues/1052 - target_link_libraries(openmw freetype jpeg png) - endif() -endif(OSG_STATIC) - target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL) if (WIN32) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 53e35f3310..5605ff229e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -155,31 +155,6 @@ target_link_libraries(openmw ${LUA_LIBRARIES} ) -if(OSG_STATIC) - unset(_osg_plugins_static_files) - add_library(openmw_osg_plugins INTERFACE) - foreach(_plugin ${USED_OSG_PLUGINS}) - string(TOUPPER ${_plugin} _plugin_uc) - if(OPENMW_USE_SYSTEM_OSG) - list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) - else() - list(APPEND _osg_plugins_static_files $) - target_link_libraries(openmw_osg_plugins INTERFACE $) - add_dependencies(openmw_osg_plugins ${${_plugin_uc}_LIBRARY}) - endif() - endforeach() - # We use --whole-archive because OSG plugins use registration. - get_whole_archive_options(_opts ${_osg_plugins_static_files}) - target_link_options(openmw_osg_plugins INTERFACE ${_opts}) - target_link_libraries(openmw openmw_osg_plugins) - - if(OPENMW_USE_SYSTEM_OSG) - # OSG plugin pkgconfig files are missing these dependencies. - # https://github.com/openscenegraph/OpenSceneGraph/issues/1052 - target_link_libraries(openmw freetype jpeg png) - endif() -endif(OSG_STATIC) - if (ANDROID) target_link_libraries(openmw EGL android log z) endif (ANDROID) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 3de864ea52..6e7d6e379d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -304,3 +304,28 @@ endif() set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) target_compile_definitions(components PUBLIC BT_USE_DOUBLE_PRECISION) + +if(OSG_STATIC) + unset(_osg_plugins_static_files) + add_library(components_osg_plugins INTERFACE) + foreach(_plugin ${USED_OSG_PLUGINS}) + string(TOUPPER ${_plugin} _plugin_uc) + if(OPENMW_USE_SYSTEM_OSG) + list(APPEND _osg_plugins_static_files ${${_plugin_uc}_LIBRARY}) + else() + list(APPEND _osg_plugins_static_files $) + target_link_libraries(components_osg_plugins INTERFACE $) + add_dependencies(components_osg_plugins ${${_plugin_uc}_LIBRARY}) + endif() + endforeach() + # We use --whole-archive because OSG plugins use registration. + get_whole_archive_options(_opts ${_osg_plugins_static_files}) + target_link_options(components_osg_plugins INTERFACE ${_opts}) + target_link_libraries(components components_osg_plugins) + + if(OPENMW_USE_SYSTEM_OSG) + # OSG plugin pkgconfig files are missing these dependencies. + # https://github.com/openscenegraph/OpenSceneGraph/issues/1052 + target_link_libraries(components freetype jpeg png) + endif() +endif(OSG_STATIC) From e910dd7a25833e69098c08531efa5dcedcf61e01 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 20 Aug 2021 00:09:31 +0200 Subject: [PATCH 23/59] Rename CellRef::getRefIdPtr -> getRefIdRef and return reference Return value can't be nullptr. Pointer complicates the code because has to be dereferenced. Also move function definition to hpp to make it easier for compiler to optimize calls. --- apps/openmw/mwlua/actions.cpp | 2 +- apps/openmw/mwlua/luamanagerimp.cpp | 2 +- apps/openmw/mwlua/object.cpp | 6 +++--- apps/openmw/mwworld/cellref.cpp | 5 ----- apps/openmw/mwworld/cellref.hpp | 4 ++-- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.cpp | 4 ++-- 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwlua/actions.cpp b/apps/openmw/mwlua/actions.cpp index 500ad98490..1f75760f7c 100644 --- a/apps/openmw/mwlua/actions.cpp +++ b/apps/openmw/mwlua/actions.cpp @@ -71,7 +71,7 @@ namespace MWLua else { const std::string& recordId = std::get(item); - if (old_it != store.end() && *old_it->getCellRef().getRefIdPtr() == recordId) + if (old_it != store.end() && old_it->getCellRef().getRefIdRef() == recordId) return true; // already equipped itemPtr = store.search(recordId); if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0) diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index d358979aec..1e009081ff 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -284,7 +284,7 @@ namespace MWLua std::shared_ptr scripts; // When loading a game, it can be called before LuaManager::setPlayer, // so we can't just check ptr == mPlayer here. - if (*ptr.getCellRef().getRefIdPtr() == "player") + if (ptr.getCellRef().getRefIdRef() == "player") { scripts = std::make_shared(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry())); scripts->addPackage("openmw.ui", mUserInterfacePackage); diff --git a/apps/openmw/mwlua/object.cpp b/apps/openmw/mwlua/object.cpp index 696179d003..d94ce1f49d 100644 --- a/apps/openmw/mwlua/object.cpp +++ b/apps/openmw/mwlua/object.cpp @@ -51,13 +51,13 @@ namespace MWLua bool isMarker(const MWWorld::Ptr& ptr) { - std::string_view id = *ptr.getCellRef().getRefIdPtr(); + std::string_view id = ptr.getCellRef().getRefIdRef(); return id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker"; } std::string_view getMWClassName(const MWWorld::Ptr& ptr) { - if (*ptr.getCellRef().getRefIdPtr() == "player") + if (ptr.getCellRef().getRefIdRef() == "player") return "Player"; if (isMarker(ptr)) return "Marker"; @@ -71,7 +71,7 @@ namespace MWLua res.append(" ("); res.append(getMWClassName(ptr)); res.append(", "); - res.append(*ptr.getCellRef().getRefIdPtr()); + res.append(ptr.getCellRef().getRefIdRef()); res.append(")"); return res; } diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 5e91ddcc67..0b16964043 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -48,11 +48,6 @@ namespace MWWorld return mCellRef.mRefID; } - const std::string* CellRef::getRefIdPtr() const - { - return &mCellRef.mRefID; - } - bool CellRef::getTeleport() const { return mCellRef.mTeleport; diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 6a6ac69c57..78170a766f 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -38,8 +38,8 @@ namespace MWWorld // Id of object being referenced std::string getRefId() const; - // Pointer to ID of the object being referenced - const std::string* getRefIdPtr() const; + // Reference to ID of the object being referenced + const std::string& getRefIdRef() const { return mCellRef.mRefID; } // For doors - true if this door teleports to somewhere else, false // if it should open through animation. diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index ad4dfcfb90..d020eace45 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -36,7 +36,7 @@ namespace } bool cont = cell.second.forEach([&] (MWWorld::Ptr ptr) { - if(*ptr.getCellRef().getRefIdPtr() == id) + if (ptr.getCellRef().getRefIdRef() == id) { return visitor(ptr); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 37c4e178ad..3d82a30c29 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -181,7 +181,7 @@ namespace { for (typename MWWorld::CellRefList::List::iterator iter (collection.mList.begin()); iter!=collection.mList.end(); ++iter) - if (iter->mRef.getRefNum()==state.mRef.mRefNum && *iter->mRef.getRefIdPtr() == state.mRef.mRefID) + if (iter->mRef.getRefNum()==state.mRef.mRefNum && iter->mRef.getRefIdRef() == state.mRef.mRefID) { // overwrite existing reference float oldscale = iter->mRef.getScale(); @@ -417,7 +417,7 @@ namespace MWWorld const std::string *mIdToFind; bool operator()(const PtrType& ptr) { - if (*ptr.getCellRef().getRefIdPtr() == *mIdToFind) + if (ptr.getCellRef().getRefIdRef() == *mIdToFind) { mFound = ptr; return false; From 403f0a72f0b1ace7647f3b2421bc156604bbd16e Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 20 Aug 2021 00:13:39 +0200 Subject: [PATCH 24/59] Do not copy RefId when need to compare Makes ContainerStore::stacks ~4x times faster when adding 4k different items in a single frame. --- apps/openmw/mwworld/containerstore.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index cced17688d..b02c2bb407 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -184,7 +184,7 @@ int MWWorld::ContainerStore::count(const std::string &id) const { int total=0; for (const auto&& iter : *this) - if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefIdRef(), id)) total += iter.getRefData().getCount(); return total; } @@ -249,7 +249,7 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) const MWWorld::Class& cls1 = ptr1.getClass(); const MWWorld::Class& cls2 = ptr2.getClass(); - if (!Misc::StringUtils::ciEqual(ptr1.getCellRef().getRefId(), ptr2.getCellRef().getRefId())) + if (!Misc::StringUtils::ciEqual(ptr1.getCellRef().getRefIdRef(), ptr2.getCellRef().getRefIdRef())) return false; // If it has an enchantment, don't stack when some of the charge is already used @@ -364,7 +364,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr, for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (Misc::StringUtils::ciEqual((*iter).getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefIdRef(), MWWorld::ContainerStore::sGoldId)) { iter->getRefData().setCount(addItems(iter->getRefData().getCount(false), realCount)); flagAsModified(); @@ -465,7 +465,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const int toRemove = count; for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) - if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), itemId)) + if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefIdRef(), itemId)) toRemove -= remove(*iter, toRemove, actor, equipReplacement, resolveFirst); flagAsModified(); @@ -740,7 +740,7 @@ MWWorld::Ptr MWWorld::ContainerStore::findReplacement(const std::string& id) for (auto&& iter : *this) { int iterHealth = iter.getClass().hasItemHealth(iter) ? iter.getClass().getItemHealth(iter) : 1; - if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefId(), id)) + if (Misc::StringUtils::ciEqual(iter.getCellRef().getRefIdRef(), id)) { // Prefer the stack with the lowest remaining uses // Try to get item with zero durability only if there are no other items found From e30709170d10644a6d64e63f54972925ec6cfb33 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 7 Sep 2021 00:04:44 +0200 Subject: [PATCH 25/59] Add script to find missing merge requests --- scripts/find_missing_merge_requests.py | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 scripts/find_missing_merge_requests.py diff --git a/scripts/find_missing_merge_requests.py b/scripts/find_missing_merge_requests.py new file mode 100755 index 0000000000..09d3e9a581 --- /dev/null +++ b/scripts/find_missing_merge_requests.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 + +import click +import multiprocessing +import pathlib +import requests +import urllib.parse + + +@click.command() +@click.option('--token_path', type=str, default=pathlib.Path.home() / '.gitlab_token', + help='Path to text file with Gitlab token.') +@click.option('--project_id', type=int, default=7107382, + help='Gitlab project id.') +@click.option('--host', type=str, default='gitlab.com', + help='Gitlab host.') +@click.option('--workers', type=int, default=10, + help='Number of parallel workers.') +@click.option('--target_branch', type=str, default='master', + help='Merge request target branch.') +@click.option('--begin_page', type=int, default=1, + help='Begin with given /merge_requests page.') +@click.option('--end_page', type=int, default=4, + help='End before given /merge_requests page.') +@click.option('--per_page', type=int, default=100, + help='Number of merge requests per page.') +def main(token_path, project_id, host, workers, target_branch, begin_page, end_page, per_page): + token = read_token(token_path) + base_url = f'https://{host}/api/v4/projects/{project_id}/' + checked = 0 + filtered = 0 + missing = 0 + for page in range(begin_page, end_page): + merge_requests = requests.get( + url=urllib.parse.urljoin(base_url, 'merge_requests'), + headers={'PRIVATE-TOKEN': token}, + params=dict(state='merged', per_page=per_page, page=page), + ).json() + if not merge_requests: + break + checked += len(merge_requests) + merge_requests = [v for v in merge_requests if v['target_branch'] == target_branch] + if not merge_requests: + continue + filtered += len(merge_requests) + with multiprocessing.Pool(workers) as pool: + missing_merge_requests = pool.map(FilterMissingMergeRequest(token, base_url), merge_requests) + for mr in missing_merge_requests: + if mr is not None: + missing += 1 + print(f"MR {mr['reference']} ({mr['id']}) is missing from branch {mr['target_branch']}," + f" previously was merged as {mr['merge_commit_sha']}") + print(f'Checked {checked} MRs ({filtered} with {target_branch} target branch), {missing} are missing') + + +class FilterMissingMergeRequest: + def __init__(self, token, base_url): + self.token = token + self.base_url = base_url + + def __call__(self, merge_request): + commit_refs = requests.get( + url=urllib.parse.urljoin(self.base_url, f"repository/commits/{merge_request['merge_commit_sha']}/refs"), + headers={'PRIVATE-TOKEN': self.token}, + ).json() + if 'message' in commit_refs and commit_refs['message'] == '404 Commit Not Found': + return merge_request + if not present_in_branch(commit_refs, branch=merge_request['target_branch']): + return merge_request + + +def present_in_branch(commit_refs, branch): + return bool(next((v for v in commit_refs if v['type'] == 'branch' and v['name'] == branch), None)) + + +def read_token(path): + with open(path) as stream: + return stream.readline().strip() + + +if __name__ == '__main__': + main() From 605cb8db7c2f6fa8f9fea4e5ac5641867ba7a20e Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 5 Sep 2021 17:43:46 +0200 Subject: [PATCH 26/59] Make sync terrain preloading sleep free This reduces average time spent on in. 5 milliseconds as a base precision is quite a lot considering that for 60 FPS frame time is 1000/16 = ~16.67 ms when it's a cell loading frame and there is more important work to do rather than sleeping. --- apps/openmw/mwworld/cellpreloader.cpp | 22 ++++++------- apps/openmw/mwworld/cellpreloader.hpp | 7 ++++- apps/openmw/mwworld/scene.cpp | 21 +++---------- components/CMakeLists.txt | 4 +++ components/loadinglistener/reporter.cpp | 41 +++++++++++++++++++++++++ components/loadinglistener/reporter.hpp | 32 +++++++++++++++++++ components/terrain/quadtreeworld.cpp | 13 +++++--- components/terrain/quadtreeworld.hpp | 2 +- components/terrain/world.hpp | 7 ++++- 9 files changed, 113 insertions(+), 36 deletions(-) create mode 100644 components/loadinglistener/reporter.cpp create mode 100644 components/loadinglistener/reporter.hpp diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index a2167c562f..7b6f640373 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "../mwrender/landmanager.hpp" @@ -157,8 +158,6 @@ namespace MWWorld public: TerrainPreloadItem(const std::vector >& views, Terrain::World* world, const std::vector& preloadPositions) : mAbort(false) - , mProgress(views.size()) - , mProgressRange(0) , mTerrainViews(views) , mWorld(world) , mPreloadPositions(preloadPositions) @@ -178,8 +177,9 @@ namespace MWWorld for (unsigned int i=0; ireset(); - mWorld->preload(mTerrainViews[i], mPreloadPositions[i].first, mPreloadPositions[i].second, mAbort, mProgress[i], mProgressRange); + mWorld->preload(mTerrainViews[i], mPreloadPositions[i].first, mPreloadPositions[i].second, mAbort, mLoadingReporter); } + mLoadingReporter.complete(); } void abort() override @@ -187,16 +187,17 @@ namespace MWWorld mAbort = true; } - int getProgress() const { return !mProgress.empty() ? mProgress[0].load() : 0; } - int getProgressRange() const { return !mProgress.empty() && mProgress[0].load() ? mProgressRange : 0; } + void wait(Loading::Listener& listener) const + { + mLoadingReporter.wait(listener); + } private: std::atomic mAbort; - std::vector> mProgress; - int mProgressRange; std::vector > mTerrainViews; Terrain::World* mWorld; std::vector mPreloadPositions; + Loading::Reporter mLoadingReporter; }; /// Worker thread item: update the resource system's cache, effectively deleting unused entries. @@ -415,7 +416,7 @@ namespace MWWorld mUnrefQueue = unrefQueue; } - bool CellPreloader::syncTerrainLoad(const std::vector &positions, int& progress, int& progressRange, double timestamp) + bool CellPreloader::syncTerrainLoad(const std::vector &positions, double timestamp, Loading::Listener& listener) { if (!mTerrainPreloadItem) return true; @@ -435,9 +436,8 @@ namespace MWWorld } else { - progress = mTerrainPreloadItem->getProgress(); - progressRange = mTerrainPreloadItem->getProgressRange(); - return false; + mTerrainPreloadItem->wait(listener); + return true; } } diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index e719f2e606..e2eea33146 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -29,6 +29,11 @@ namespace MWRender class LandManager; } +namespace Loading +{ + class Listener; +} + namespace MWWorld { class CellStore; @@ -72,7 +77,7 @@ namespace MWWorld typedef std::pair PositionCellGrid; void setTerrainPreloadPositions(const std::vector& positions); - bool syncTerrainLoad(const std::vector &positions, int& progress, int& progressRange, double timestamp); + bool syncTerrainLoad(const std::vector &positions, double timestamp, Loading::Listener& listener); void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos); private: diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 90e5bc265e..399d0e6d7f 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1250,23 +1250,10 @@ namespace MWWorld Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); - int progress = 0, initialProgress = -1, progressRange = 0; - while (!mPreloader->syncTerrainLoad(vec, progress, progressRange, mRendering.getReferenceTime())) - { - if (initialProgress == -1) - { - loadingListener->setLabel("#{sLoadingMessage4}"); - initialProgress = progress; - } - if (progress) - { - loadingListener->setProgressRange(std::max(0, progressRange-initialProgress)); - loadingListener->setProgress(progress-initialProgress); - } - else - loadingListener->setProgress(0); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } + + loadingListener->setLabel("#{sLoadingMessage4}"); + + while (!mPreloader->syncTerrainLoad(vec, mRendering.getReferenceTime(), *loadingListener)) {} } void Scene::reloadTerrain() diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6e7d6e379d..7983de6190 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -197,6 +197,10 @@ add_component_dir(detournavigator navmeshcacheitem ) +add_component_dir(loadinglistener + reporter + ) + set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui ) diff --git a/components/loadinglistener/reporter.cpp b/components/loadinglistener/reporter.cpp new file mode 100644 index 0000000000..0ad04fded1 --- /dev/null +++ b/components/loadinglistener/reporter.cpp @@ -0,0 +1,41 @@ +#include "reporter.hpp" +#include "loadinglistener.hpp" + +#include +#include +#include + +namespace Loading +{ + void Reporter::addTotal(std::size_t value) + { + const std::lock_guard lock(mMutex); + mTotal += value; + mUpdated.notify_all(); + } + + void Reporter::addProgress(std::size_t value) + { + const std::lock_guard lock(mMutex); + mProgress += value; + mUpdated.notify_all(); + } + + void Reporter::complete() + { + const std::lock_guard lock(mMutex); + mDone = true; + mUpdated.notify_all(); + } + + void Reporter::wait(Listener& listener) const + { + std::unique_lock lock(mMutex); + while (!mDone) + { + listener.setProgressRange(mTotal); + listener.setProgress(mProgress); + mUpdated.wait(lock); + } + } +} diff --git a/components/loadinglistener/reporter.hpp b/components/loadinglistener/reporter.hpp new file mode 100644 index 0000000000..b59c519082 --- /dev/null +++ b/components/loadinglistener/reporter.hpp @@ -0,0 +1,32 @@ +#ifndef COMPONENTS_LOADINGLISTENER_REPORTER_H +#define COMPONENTS_LOADINGLISTENER_REPORTER_H + +#include +#include +#include + +namespace Loading +{ + class Listener; + + class Reporter + { + public: + void addTotal(std::size_t value); + + void addProgress(std::size_t value); + + void complete(); + + void wait(Listener& listener) const; + + private: + std::size_t mProgress = 0; + std::size_t mTotal = 0; + bool mDone = false; + mutable std::mutex mMutex; + mutable std::condition_variable mUpdated; + }; +} + +#endif diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index e26fc1b617..9ca504ebeb 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "quadtreenode.hpp" #include "storage.hpp" @@ -496,7 +497,7 @@ View* QuadTreeWorld::createView() return mViewDataMap->createIndependentView(); } -void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::Vec4i &grid, std::atomic &abort, std::atomic &progress, int& progressTotal) +void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg::Vec4i &grid, std::atomic &abort, Loading::Reporter& reporter) { ensureQuadTreeBuilt(); @@ -506,16 +507,18 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg:: DefaultLodCallback lodCallback(mLodFactor, mMinSize, mViewDistance, grid); mRootNode->traverseNodes(vd, viewPoint, &lodCallback); - if (!progressTotal) - for (unsigned int i=0; igetNumEntries(); ++i) - progressTotal += vd->getEntry(i).mNode->getSize(); + std::size_t progressTotal = 0; + for (unsigned int i = 0, n = vd->getNumEntries(); i < n; ++i) + progressTotal += vd->getEntry(i).mNode->getSize(); + + reporter.addTotal(progressTotal); const float cellWorldSize = mStorage->getCellWorldSize(); for (unsigned int i=0; igetNumEntries() && !abort; ++i) { ViewData::Entry& entry = vd->getEntry(i); loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true); - progress += entry.mNode->getSize(); + reporter.addProgress(entry.mNode->getSize()); } vd->markUnchanged(); } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 2ddea42049..3a2aa8349d 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -39,7 +39,7 @@ namespace Terrain void unloadCell(int x, int y) override; View* createView() override; - void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic& abort, std::atomic& progress, int& progressRange) override; + void preload(View* view, const osg::Vec3f& eyePoint, const osg::Vec4i &cellgrid, std::atomic& abort, Loading::Reporter& reporter) override; bool storeView(const View* view, double referenceTime) override; void rebuildViews() override; diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 5797d894ef..b62a1cb568 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -32,6 +32,11 @@ namespace SceneUtil class WorkQueue; } +namespace Loading +{ + class Reporter; +} + namespace Terrain { class Storage; @@ -148,7 +153,7 @@ namespace Terrain /// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads. - virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i &cellgrid, std::atomic& abort, std::atomic& progress, int& progressRange) {} + virtual void preload(View* view, const osg::Vec3f& viewPoint, const osg::Vec4i &cellgrid, std::atomic& abort, Loading::Reporter& reporter) {} /// Store a preloaded view into the cache with the intent that the next rendering traversal can use it. /// @note Not thread safe. From b19da7f6505a334d5ed33af20be9620de8947aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matja=C5=BE=20Lamut?= Date: Tue, 7 Sep 2021 18:57:03 +0000 Subject: [PATCH 27/59] Update an obsolete link pointing to teh old wiki. The information is moved to the new wiki at gitlab and the link now points there. --- docs/source/manuals/installation/install-openmw.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/manuals/installation/install-openmw.rst b/docs/source/manuals/installation/install-openmw.rst index fab00ab9b7..362637746d 100644 --- a/docs/source/manuals/installation/install-openmw.rst +++ b/docs/source/manuals/installation/install-openmw.rst @@ -18,7 +18,7 @@ and run the install package once downloaded. It's now installed! The (bleeding edge) Source Way ============================== -Visit the `Development Environment Setup `_ +Visit the `Development Environment Setup `_ section of the Wiki for detailed instructions on how to build the engine. The Ubuntu Way From bdbc6c0cbae128f0e65b0698ffc4fff0a18c7f99 Mon Sep 17 00:00:00 2001 From: JanuarySnow Date: Wed, 8 Sep 2021 10:07:54 +0000 Subject: [PATCH 28/59] Dead animation code removal --- AUTHORS.md | 1 + CHANGELOG.md | 1 + apps/openmw/mwrender/animation.cpp | 114 +---------------------------- 3 files changed, 4 insertions(+), 112 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index beb2b490f2..abc3f1a8d1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -99,6 +99,7 @@ Programmers James Stephens (james-h-stephens) Jan-Peter Nilsson (peppe) Jan Borsodi (am0s) + JanuarySnow Jason Hooks (jhooks) jeaye jefetienne diff --git a/CHANGELOG.md b/CHANGELOG.md index bc9c79411b..3ad818bd25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly Feature #6199: Support FBO Rendering Feature #6251: OpenMW-CS: Set instance movement based on camera zoom + Task #6264: Remove the old classes in animation.cpp 0.47.0 ------ diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 591e666d01..a04724c70a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -196,32 +196,6 @@ namespace return 0.0f; } - /// @brief Base class for visitors that remove nodes from a scene graph. - /// Subclasses need to fill the mToRemove vector. - /// To use, node->accept(removeVisitor); removeVisitor.remove(); - class RemoveVisitor : public osg::NodeVisitor - { - public: - RemoveVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - void remove() - { - for (RemoveVec::iterator it = mToRemove.begin(); it != mToRemove.end(); ++it) - { - if (!it->second->removeChild(it->first)) - Log(Debug::Error) << "Error removing " << it->first->getName(); - } - } - - protected: - // - typedef std::vector > RemoveVec; - std::vector > mToRemove; - }; - class GetExtendedBonesVisitor : public osg::NodeVisitor { public: @@ -244,7 +218,7 @@ namespace std::vector > mFoundBones; }; - class RemoveFinishedCallbackVisitor : public RemoveVisitor + class RemoveFinishedCallbackVisitor : public SceneUtil::RemoveVisitor { public: bool mHasMagicEffects; @@ -289,7 +263,7 @@ namespace } }; - class RemoveCallbackVisitor : public RemoveVisitor + class RemoveCallbackVisitor : public SceneUtil::RemoveVisitor { public: bool mHasMagicEffects; @@ -397,90 +371,6 @@ namespace private: int mEffectId; }; - - // Removes all drawables from a graph. - class CleanObjectRootVisitor : public RemoveVisitor - { - public: - void apply(osg::Drawable& drw) override - { - applyDrawable(drw); - } - - void apply(osg::Group& node) override - { - applyNode(node); - } - void apply(osg::MatrixTransform& node) override - { - applyNode(node); - } - void apply(osg::Node& node) override - { - applyNode(node); - } - - void applyNode(osg::Node& node) - { - if (node.getStateSet()) - node.setStateSet(nullptr); - - if (node.getNodeMask() == 0x1 && node.getNumParents() == 1) - mToRemove.emplace_back(&node, node.getParent(0)); - else - traverse(node); - } - void applyDrawable(osg::Node& node) - { - osg::NodePath::iterator parent = getNodePath().end()-2; - // We know that the parent is a Group because only Groups can have children. - osg::Group* parentGroup = static_cast(*parent); - - // Try to prune nodes that would be empty after the removal - if (parent != getNodePath().begin()) - { - // This could be extended to remove the parent's parent, and so on if they are empty as well. - // But for NIF files, there won't be a benefit since only TriShapes can be set to STATIC dataVariance. - osg::Group* parentParent = static_cast(*(parent - 1)); - if (parentGroup->getNumChildren() == 1 && parentGroup->getDataVariance() == osg::Object::STATIC) - { - mToRemove.emplace_back(parentGroup, parentParent); - return; - } - } - - mToRemove.emplace_back(&node, parentGroup); - } - }; - - class RemoveTriBipVisitor : public RemoveVisitor - { - public: - void apply(osg::Drawable& drw) override - { - applyImpl(drw); - } - - void apply(osg::Group& node) override - { - traverse(node); - } - void apply(osg::MatrixTransform& node) override - { - traverse(node); - } - - void applyImpl(osg::Node& node) - { - const std::string toFind = "tri bip"; - if (Misc::StringUtils::ciCompareLen(node.getName(), toFind, toFind.size()) == 0) - { - osg::Group* parent = static_cast(*(getNodePath().end()-2)); - // Not safe to remove in apply(), since the visitor is still iterating the child list - mToRemove.emplace_back(&node, parent); - } - } - }; } namespace MWRender From d36c373cc71b907cdeb598690718f682524d88db Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Wed, 8 Sep 2021 17:23:35 +0000 Subject: [PATCH 29/59] visitor.cpp early out --- components/sceneutil/visitor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index f1f15f786f..3fc1898959 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -32,13 +32,13 @@ namespace SceneUtil void FindByNameVisitor::apply(osg::Group &group) { - if (!checkGroup(group)) + if (!mFoundNode && !checkGroup(group)) traverse(group); } void FindByNameVisitor::apply(osg::MatrixTransform &node) { - if (!checkGroup(node)) + if (!mFoundNode && !checkGroup(node)) traverse(node); } From 5ab5419f7bc68653f7eb928c4831c19278d533bb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Wed, 8 Sep 2021 21:08:04 +0000 Subject: [PATCH 30/59] Remove unsafe characters from zip filenames on Windows --- .gitlab-ci.yml | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8d82d6ed79..c9b8cf9341 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -223,6 +223,18 @@ variables: &tests-targets - choco install ninja -y - choco install python -y - refreshenv + - | + function Make-SafeFileName { + param( + [Parameter(Mandatory=$true)] + [String] + $FileName + ) + [IO.Path]::GetInvalidFileNameChars() | ForEach-Object { + $FileName = $FileName.Replace($_, '_') + } + return $FileName + } stage: build script: - $time = (Get-Date -Format "HH:mm:ss") @@ -237,10 +249,10 @@ variables: &tests-targets - Get-ChildItem -Recurse *.ilk | Remove-Item - | if (Get-ChildItem -Recurse *.pdb) { - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt + 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*' + - 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*' - if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } } after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log @@ -326,6 +338,18 @@ Windows_Ninja_Tests_RelWithDebInfo: - choco install vswhere -y - choco install python -y - refreshenv + - | + function Make-SafeFileName { + param( + [Parameter(Mandatory=$true)] + [String] + $FileName + ) + [IO.Path]::GetInvalidFileNameChars() | ForEach-Object { + $FileName = $FileName.Replace($_, '_') + } + return $FileName + } stage: build script: - $time = (Get-Date -Format "HH:mm:ss") @@ -339,10 +363,10 @@ Windows_Ninja_Tests_RelWithDebInfo: - Get-ChildItem -Recurse *.ilk | Remove-Item - | if (Get-ChildItem -Recurse *.pdb) { - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt + 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt Get-ChildItem -Recurse *.pdb | Remove-Item } - - 7z a -tzip ..\..\OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip '*' + - 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${package}_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*' - if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } } after_script: - Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log From dc623597b4155459bfad0b32f8f3d805dcc13e92 Mon Sep 17 00:00:00 2001 From: "Hristos N. Triantafillou" Date: Wed, 8 Sep 2021 19:19:40 -0500 Subject: [PATCH 31/59] This is the right path for saves --- docs/source/reference/modding/paths.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/reference/modding/paths.rst b/docs/source/reference/modding/paths.rst index 97cfe37a5c..bc955b703d 100644 --- a/docs/source/reference/modding/paths.rst +++ b/docs/source/reference/modding/paths.rst @@ -29,7 +29,7 @@ Savegames +--------------+-----------------------------------------------------------------------------------------------------+ | OS | Location | +==============+=====================================================================================================+ -| Linux | ``$HOME/.config/openmw/saves`` | +| Linux | ``$HOME/.local/share/openmw/saves`` | +--------------+-----------------------------------------------------------------------------------------------------+ | Mac | ``$HOME/Library/Application\ Support/openmw/saves`` | +--------------+---------------+-------------------------------------------------------------------------------------+ From 6b7434ca696d59f5c0400b25a0efb7511aab6121 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 4 Sep 2021 18:07:23 +0200 Subject: [PATCH 32/59] Pass std::string_view instead of const std::string& * Starting with Actor::getBodyPartMesh and ending with Misc::StringUtils::ciEqual. * Add tests for Misc::StringUtils::ciEqual. --- apps/opencs/model/world/actoradapter.cpp | 3 +- apps/opencs/model/world/collection.hpp | 5 +- apps/opencs/model/world/collectionbase.hpp | 3 +- apps/opencs/model/world/columns.cpp | 2 +- apps/opencs/model/world/infocollection.cpp | 6 +- apps/opencs/model/world/infocollection.hpp | 5 +- apps/opencs/model/world/refcollection.cpp | 4 +- apps/opencs/model/world/refcollection.hpp | 3 +- apps/opencs/model/world/refidcollection.cpp | 3 +- apps/opencs/model/world/refidcollection.hpp | 3 +- apps/opencs/model/world/refiddata.cpp | 4 +- apps/opencs/model/world/refiddata.hpp | 3 +- apps/opencs/model/world/resources.cpp | 3 +- apps/opencs/model/world/resources.hpp | 3 +- apps/opencs/view/render/actor.cpp | 4 +- apps/opencs/view/render/actor.hpp | 3 +- apps/openmw/mwgui/messagebox.cpp | 4 +- .../openmw_test_suite/misc/test_stringops.cpp | 102 +++++++++++++++++- components/misc/stringops.hpp | 44 +++++--- components/sceneutil/visitor.cpp | 5 +- 20 files changed, 170 insertions(+), 42 deletions(-) diff --git a/apps/opencs/model/world/actoradapter.cpp b/apps/opencs/model/world/actoradapter.cpp index 7882dd4535..7e7f926384 100644 --- a/apps/opencs/model/world/actoradapter.cpp +++ b/apps/opencs/model/world/actoradapter.cpp @@ -145,8 +145,7 @@ namespace CSMWorld return {}; } - const std::string& partName = it->second.first; - return partName; + return it->second.first; } bool ActorAdapter::ActorData::hasDependency(const std::string& id) const diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp index 9d9c69a5da..6ab9d7ff9d 100644 --- a/apps/opencs/model/world/collection.hpp +++ b/apps/opencs/model/world/collection.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -153,7 +154,7 @@ namespace CSMWorld ///< Change the state of a record from base to modified, if it is not already. /// \return True if the record was changed. - int searchId (const std::string& id) const override; + int searchId(std::string_view id) const override; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) @@ -476,7 +477,7 @@ namespace CSMWorld } template - int Collection::searchId (const std::string& id) const + int Collection::searchId(std::string_view id) const { std::string id2 = Misc::StringUtils::lowerCase(id); diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 13471b9886..be6131ee52 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "universalid.hpp" #include "columns.hpp" @@ -61,7 +62,7 @@ namespace CSMWorld UniversalId::Type type = UniversalId::Type_None) = 0; ///< \param type Will be ignored, unless the collection supports multiple record types - virtual int searchId (const std::string& id) const = 0; + virtual int searchId(std::string_view id) const = 0; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index cf04d96753..d6066aa04d 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -391,7 +391,7 @@ int CSMWorld::Columns::getId (const std::string& name) std::string name2 = Misc::StringUtils::lowerCase (name); for (int i=0; sNames[i].mName; ++i) - if (Misc::StringUtils::ciEqual(sNames[i].mName, name2)) + if (Misc::StringUtils::ciEqual(std::string_view(sNames[i].mName), name2)) return sNames[i].mId; return -1; diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 978ce3595d..d58a8327f2 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -97,7 +97,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) } } -int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const +int CSMWorld::InfoCollection::getInfoIndex(std::string_view id, std::string_view topic) const { // find the topic first std::unordered_map > >::const_iterator iter @@ -345,12 +345,12 @@ void CSMWorld::InfoCollection::appendBlankRecord (const std::string& id, Univer insertRecord(std::move(record2), getInsertIndex(id, type, nullptr), type); // call InfoCollection::insertRecord() } -int CSMWorld::InfoCollection::searchId (const std::string& id) const +int CSMWorld::InfoCollection::searchId(std::string_view id) const { std::string::size_type separator = id.find_last_of('#'); if (separator == std::string::npos) - throw std::runtime_error("invalid info ID: " + id); + throw std::runtime_error("invalid info ID: " + std::string(id)); return getInfoIndex(id.substr(separator+1), id.substr(0, separator)); } diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index 3e8455c399..96061fb03c 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_INFOCOLLECTION_H #include +#include #include "collection.hpp" #include "info.hpp" @@ -43,7 +44,7 @@ namespace CSMWorld void load (const Info& record, bool base); - int getInfoIndex (const std::string& id, const std::string& topic) const; + int getInfoIndex(std::string_view id, std::string_view topic) const; ///< Return index for record \a id or -1 (if not present; deleted records are considered) /// /// \param id info ID without topic prefix @@ -79,7 +80,7 @@ namespace CSMWorld void appendBlankRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None) override; - int searchId (const std::string& id) const override; + int searchId(std::string_view id) const override; void appendRecord (std::unique_ptr record, UniversalId::Type type = UniversalId::Type_None) override; diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp index 4782bde6b9..4f56bbb463 100644 --- a/apps/opencs/model/world/refcollection.cpp +++ b/apps/opencs/model/world/refcollection.cpp @@ -7,6 +7,8 @@ #include "universalid.hpp" #include "record.hpp" +#include + namespace CSMWorld { template<> @@ -261,7 +263,7 @@ void CSMWorld::RefCollection::cloneRecord (const std::string& origin, insertRecord(std::move(copy), getAppendIndex(destination, type)); // call RefCollection::insertRecord() } -int CSMWorld::RefCollection::searchId (const std::string& id) const +int CSMWorld::RefCollection::searchId(std::string_view id) const { return searchId(extractIdNum(id)); } diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index e0e88d721f..34e258c11b 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -2,6 +2,7 @@ #define CSM_WOLRD_REFCOLLECTION_H #include +#include #include "../doc/stage.hpp" @@ -56,7 +57,7 @@ namespace CSMWorld const std::string& destination, const UniversalId::Type type); - virtual int searchId (const std::string& id) const; + virtual int searchId(std::string_view id) const; virtual void appendRecord (std::unique_ptr record, UniversalId::Type type = UniversalId::Type_None); diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 177844a31d..71629694c0 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -787,7 +788,7 @@ void CSMWorld::RefIdCollection::appendBlankRecord (const std::string& id, Univer mData.appendRecord (type, id, false); } -int CSMWorld::RefIdCollection::searchId (const std::string& id) const +int CSMWorld::RefIdCollection::searchId(std::string_view id) const { RefIdData::LocalIndex localIndex = mData.searchId (id); diff --git a/apps/opencs/model/world/refidcollection.hpp b/apps/opencs/model/world/refidcollection.hpp index dc722055ff..ee17bb3214 100644 --- a/apps/opencs/model/world/refidcollection.hpp +++ b/apps/opencs/model/world/refidcollection.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "columnbase.hpp" #include "collectionbase.hpp" @@ -85,7 +86,7 @@ namespace CSMWorld void appendBlankRecord (const std::string& id, UniversalId::Type type) override; ///< \param type Will be ignored, unless the collection supports multiple record types - int searchId (const std::string& id) const override; + int searchId(std::string_view id) const override; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) diff --git a/apps/opencs/model/world/refiddata.cpp b/apps/opencs/model/world/refiddata.cpp index df8e06c251..3bd8bfd5fc 100644 --- a/apps/opencs/model/world/refiddata.cpp +++ b/apps/opencs/model/world/refiddata.cpp @@ -2,6 +2,7 @@ #include #include +#include CSMWorld::RefIdDataContainerBase::~RefIdDataContainerBase() {} @@ -74,8 +75,7 @@ int CSMWorld::RefIdData::localToGlobalIndex (const LocalIndex& index) return globalIndex; } -CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId ( - const std::string& id) const +CSMWorld::RefIdData::LocalIndex CSMWorld::RefIdData::searchId(std::string_view id) const { std::string id2 = Misc::StringUtils::lowerCase (id); diff --git a/apps/opencs/model/world/refiddata.hpp b/apps/opencs/model/world/refiddata.hpp index 175aaef410..b9dee80638 100644 --- a/apps/opencs/model/world/refiddata.hpp +++ b/apps/opencs/model/world/refiddata.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -277,7 +278,7 @@ namespace CSMWorld int localToGlobalIndex (const LocalIndex& index) const; - LocalIndex searchId (const std::string& id) const; + LocalIndex searchId(std::string_view id) const; void erase (int index, int count); diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index c3eb9762e7..2544886f3e 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -83,7 +84,7 @@ int CSMWorld::Resources::getIndex (const std::string& id) const return index; } -int CSMWorld::Resources::searchId (const std::string& id) const +int CSMWorld::Resources::searchId(std::string_view id) const { std::string id2 = Misc::StringUtils::lowerCase (id); diff --git a/apps/opencs/model/world/resources.hpp b/apps/opencs/model/world/resources.hpp index c217b793d3..2de13a259e 100644 --- a/apps/opencs/model/world/resources.hpp +++ b/apps/opencs/model/world/resources.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "universalid.hpp" @@ -35,7 +36,7 @@ namespace CSMWorld int getIndex (const std::string& id) const; - int searchId (const std::string& id) const; + int searchId(std::string_view id) const; UniversalId::Type getType() const; }; diff --git a/apps/opencs/view/render/actor.cpp b/apps/opencs/view/render/actor.cpp index 10f7330d1c..271ca2365a 100644 --- a/apps/opencs/view/render/actor.cpp +++ b/apps/opencs/view/render/actor.cpp @@ -96,7 +96,7 @@ namespace CSVRender for (int i = 0; i < ESM::PRT_Count; ++i) { auto type = (ESM::PartReferenceType) i; - const std::string partId(mActorData->getPart(type)); + const std::string_view partId = mActorData->getPart(type); attachBodyPart(type, getBodyPartMesh(partId)); } } @@ -115,7 +115,7 @@ namespace CSVRender } } - std::string Actor::getBodyPartMesh(const std::string& bodyPartId) + std::string Actor::getBodyPartMesh(std::string_view bodyPartId) { const auto& bodyParts = mData.getBodyParts(); diff --git a/apps/opencs/view/render/actor.hpp b/apps/opencs/view/render/actor.hpp index 2f19454f78..8172e6fff7 100644 --- a/apps/opencs/view/render/actor.hpp +++ b/apps/opencs/view/render/actor.hpp @@ -2,6 +2,7 @@ #define OPENCS_VIEW_RENDER_ACTOR_H #include +#include #include @@ -54,7 +55,7 @@ namespace CSVRender void loadBodyParts(); void attachBodyPart(ESM::PartReferenceType, const std::string& mesh); - std::string getBodyPartMesh(const std::string& bodyPartId); + std::string getBodyPartMesh(std::string_view bodyPartId); static const std::string MeshPrefix; diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 4907a247ff..ed6633c983 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -376,7 +376,9 @@ namespace MWGui { for (const std::string& keyword : keywords) { - if(Misc::StringUtils::ciEqual(MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}"), button->getCaption())) + if (Misc::StringUtils::ciEqual( + MyGUI::LanguageManager::getInstance().replaceTags("#{" + keyword + "}").asUTF8(), + button->getCaption().asUTF8())) { return button; } diff --git a/apps/openmw_test_suite/misc/test_stringops.cpp b/apps/openmw_test_suite/misc/test_stringops.cpp index 086908692d..173cfa4447 100644 --- a/apps/openmw_test_suite/misc/test_stringops.cpp +++ b/apps/openmw_test_suite/misc/test_stringops.cpp @@ -1,6 +1,10 @@ #include #include "components/misc/stringops.hpp" +#include +#include +#include + struct PartialBinarySearchTest : public ::testing::Test { protected: @@ -12,10 +16,6 @@ struct PartialBinarySearchTest : public ::testing::Test std::sort(mDataVec.begin(), mDataVec.end(), Misc::StringUtils::ciLess); } - void TearDown() override - { - } - bool matches(const std::string& keyword) { return Misc::StringUtils::partialBinarySearch(mDataVec.begin(), mDataVec.end(), keyword) != mDataVec.end(); @@ -51,3 +51,97 @@ TEST_F (PartialBinarySearchTest, ci_test) std::string unicode1 = "\u04151 \u0418"; // CYRILLIC CAPITAL LETTER IE, CYRILLIC CAPITAL LETTER I EXPECT_TRUE( Misc::StringUtils::lowerCase(unicode1) == unicode1 ); } + +namespace +{ + using ::Misc::StringUtils; + using namespace ::testing; + + template + struct MiscStringUtilsCiEqualEmptyTest : Test {}; + + TYPED_TEST_SUITE_P(MiscStringUtilsCiEqualEmptyTest); + + TYPED_TEST_P(MiscStringUtilsCiEqualEmptyTest, empty_strings_should_be_equal) + { + EXPECT_TRUE(StringUtils::ciEqual(typename TypeParam::first_type {}, typename TypeParam::second_type {})); + } + + REGISTER_TYPED_TEST_SUITE_P(MiscStringUtilsCiEqualEmptyTest, + empty_strings_should_be_equal + ); + + using EmptyStringTypePairsTypes = Types< + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair + >; + + INSTANTIATE_TYPED_TEST_SUITE_P(EmptyStringTypePairs, MiscStringUtilsCiEqualEmptyTest, EmptyStringTypePairsTypes); + + template + struct MiscStringUtilsCiEqualNotEmptyTest : Test {}; + + TYPED_TEST_SUITE_P(MiscStringUtilsCiEqualNotEmptyTest); + + using RawValue = const char[4]; + + constexpr RawValue foo = "foo"; + constexpr RawValue fooUpper = "FOO"; + constexpr RawValue bar = "bar"; + + template + using Value = std::conditional_t, RawValue&, T>; + + TYPED_TEST_P(MiscStringUtilsCiEqualNotEmptyTest, same_strings_should_be_equal) + { + const Value a {foo}; + const Value b {foo}; + EXPECT_TRUE(StringUtils::ciEqual(a, b)) << a << "\n" << b; + } + + TYPED_TEST_P(MiscStringUtilsCiEqualNotEmptyTest, same_strings_with_different_case_sensetivity_should_be_equal) + { + const Value a {foo}; + const Value b {fooUpper}; + EXPECT_TRUE(StringUtils::ciEqual(a, b)) << a << "\n" << b; + } + + TYPED_TEST_P(MiscStringUtilsCiEqualNotEmptyTest, different_strings_content_should_not_be_equal) + { + const Value a {foo}; + const Value b {bar}; + EXPECT_FALSE(StringUtils::ciEqual(a, b)) << a << "\n" << b; + } + + REGISTER_TYPED_TEST_SUITE_P(MiscStringUtilsCiEqualNotEmptyTest, + same_strings_should_be_equal, + same_strings_with_different_case_sensetivity_should_be_equal, + different_strings_content_should_not_be_equal + ); + + using NotEmptyStringTypePairsTypes = Types< + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair, + std::pair + >; + + INSTANTIATE_TYPED_TEST_SUITE_P(NotEmptyStringTypePairs, MiscStringUtilsCiEqualNotEmptyTest, NotEmptyStringTypePairsTypes); + + TEST(MiscStringUtilsCiEqualTest, string_with_different_length_should_not_be_equal) + { + EXPECT_FALSE(StringUtils::ciEqual(std::string("a"), std::string("aa"))); + } +} diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 2a865606fd..0863522356 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "utf8stream.hpp" @@ -109,18 +111,34 @@ public: return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), ci()); } - static bool ciEqual(const std::string &x, const std::string &y) { - if (x.size() != y.size()) { + template + static bool ciEqual(const X& x, const Y& y) + { + if (std::size(x) != std::size(y)) return false; - } - std::string::const_iterator xit = x.begin(); - std::string::const_iterator yit = y.begin(); - for (; xit != x.end(); ++xit, ++yit) { - if (toLower(*xit) != toLower(*yit)) { - return false; - } - } - return true; + return std::equal(std::begin(x), std::end(x), std::begin(y), + [] (char l, char r) { return toLower(l) == toLower(r); }); + } + + template + static auto ciEqual(const char(& x)[n], const char(& y)[n]) + { + static_assert(n > 0); + return ciEqual(std::string_view(x, n - 1), std::string_view(y, n - 1)); + } + + template + static auto ciEqual(const char(& x)[n], const T& y) + { + static_assert(n > 0); + return ciEqual(std::string_view(x, n - 1), y); + } + + template + static auto ciEqual(const T& x, const char(& y)[n]) + { + static_assert(n > 0); + return ciEqual(x, std::string_view(y, n - 1)); } static int ciCompareLen(const std::string &x, const std::string &y, size_t len) @@ -157,9 +175,9 @@ public: } /// Returns lower case copy of input string - static std::string lowerCase(const std::string &in) + static std::string lowerCase(std::string_view in) { - std::string out = in; + std::string out(in); lowerCaseInPlace(out); return out; } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp index f1f15f786f..2d990c1b9e 100644 --- a/components/sceneutil/visitor.cpp +++ b/components/sceneutil/visitor.cpp @@ -9,6 +9,9 @@ #include +#include +#include + namespace SceneUtil { @@ -24,7 +27,7 @@ namespace SceneUtil void FindByClassVisitor::apply(osg::Node &node) { - if (Misc::StringUtils::ciEqual(node.className(), mNameToFind)) + if (Misc::StringUtils::ciEqual(std::string_view(node.className()), mNameToFind)) mFoundNodes.push_back(&node); traverse(node); From 6e6214bc43ec3dc3c98a7a1aa423d2d24e77fd1e Mon Sep 17 00:00:00 2001 From: Lamoot Date: Thu, 9 Sep 2021 20:46:27 +0200 Subject: [PATCH 33/59] In OpenMW-CS, when creating a new object, sort the entries in the drop-down menu alphabetically. Also have the menu be tall enough to show all of them at once (without scroll bars). --- apps/opencs/view/world/referenceablecreator.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index 1a2f2bbaa3..6bc0126b3e 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -22,7 +22,8 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd std::vector types = CSMWorld::UniversalId::listReferenceableTypes(); mType = new QComboBox (this); - + mType->setMaxVisibleItems(20); + for (std::vector::const_iterator iter (types.begin()); iter!=types.end(); ++iter) { @@ -31,7 +32,9 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd mType->addItem (QIcon (id2.getIcon().c_str()), id2.getTypeName().c_str(), static_cast (id2.getType())); } - + + mType->model()->sort(0); + insertBeforeButtons (mType, false); connect (mType, SIGNAL (currentIndexChanged (int)), this, SLOT (setType (int))); From 147ed39900645a8e9ac46aacce53ea79a8391712 Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Thu, 9 Sep 2021 20:56:57 +0000 Subject: [PATCH 34/59] This PR solves a crash with Robert's bodies logged on your bugtracker. (#3095) * attach.cpp [ci skip] * attach.cpp [ci skip] * attach.cpp [ci skip] * npcanimation.cpp [ci skip] * attach.hpp [ci skip] * attach.cpp [ci skip] * creatureanimation.cpp [ci skip] * creatureanimation.cpp [ci skip] * cellpreloader.cpp * npcanimation.cpp * attach.cpp * make android adk happy * make android adk happy * changelog.md [ci skip] * authors.md [ci skip] --- AUTHORS.md | 1 + CHANGELOG.md | 1 + apps/openmw/mwrender/creatureanimation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 4 +-- apps/openmw/mwworld/cellpreloader.cpp | 5 +-- components/sceneutil/attach.cpp | 38 ++++++++++------------ components/sceneutil/attach.hpp | 4 +-- 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index abc3f1a8d1..62121a797b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -44,6 +44,7 @@ Programmers Austin Salgat (Salgat) Ben Shealy (bentsherman) Berulacks + Bo Svensson Britt Mathis (galdor557) Capostrophic Carl Maxwell diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad818bd25..b1132a9e68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes Bug #3905: Great House Dagoth issues Bug #4203: Resurrecting an actor should close the loot GUI + Bug #4602: Robert's Bodies: crash inside createInstance() Bug #4700: Editor: Incorrect command implementation Bug #4744: Invisible particles must still be processed Bug #4752: UpdateCellCommand doesn't undo properly diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2987111621..f1d28b0634 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -158,7 +158,7 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) try { - osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(itemModel); + osg::ref_ptr node = mResourceSystem->getSceneManager()->getTemplate(itemModel); const NodeMap& nodeMap = getNodeMap(); NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d142996f40..7fc488020c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -714,14 +714,14 @@ void NpcAnimation::updateParts() PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const std::string& bonename, const std::string& bonefilter, bool enchantedGlow, osg::Vec4f* glowColor) { - osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model); + osg::ref_ptr templateNode = mResourceSystem->getSceneManager()->getTemplate(model); const NodeMap& nodeMap = getNodeMap(); NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) throw std::runtime_error("Can't find attachment node " + bonename); - osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, found->second); + osg::ref_ptr attached = SceneUtil::attach(templateNode, mObjectRoot, bonefilter, found->second); if (enchantedGlow) mGlowUpdater = SceneUtil::addEnchantedGlow(attached, mResourceSystem, *glowColor); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 7b6f640373..b2dba1d452 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -114,10 +114,7 @@ namespace MWWorld } } } - if (mPreloadInstances && animated) - mPreloadedObjects.insert(mSceneManager->cacheInstance(mesh)); - else - mPreloadedObjects.insert(mSceneManager->getTemplate(mesh)); + mPreloadedObjects.insert(mSceneManager->getTemplate(mesh)); if (mPreloadInstances) mPreloadedObjects.insert(mBulletShapeManager->cacheInstance(mesh)); else diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 597c7adf48..fe8aad0879 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -15,6 +15,7 @@ #include #include "visitor.hpp" +#include "clone.hpp" namespace SceneUtil { @@ -49,10 +50,10 @@ namespace SceneUtil return; osg::Node* node = &drawable; - while (node->getNumParents()) + for (auto it = getNodePath().rbegin()+1; it != getNodePath().rend(); ++it) { - osg::Group* parent = node->getParent(0); - if (!parent || !filterMatches(parent->getName())) + osg::Node* parent = *it; + if (!filterMatches(parent->getName())) break; node = parent; } @@ -63,12 +64,7 @@ namespace SceneUtil { for (const osg::ref_ptr& node : mToCopy) { - if (node->getNumParents() > 1) - Log(Debug::Error) << "Error CopyRigVisitor: node has " << node->getNumParents() << " parents"; - while (node->getNumParents()) - node->getParent(0)->removeChild(node); - - mParent->addChild(node); + mParent->addChild(static_cast(node->clone(SceneUtil::CopyOp()))); } mToCopy.clear(); } @@ -90,25 +86,25 @@ namespace SceneUtil std::string mFilter2; }; - void mergeUserData(osg::UserDataContainer* source, osg::Object* target) + void mergeUserData(const osg::UserDataContainer* source, osg::Object* target) { if (!target->getUserDataContainer()) - target->setUserDataContainer(source); + target->setUserDataContainer(osg::clone(source, osg::CopyOp::SHALLOW_COPY)); else { for (unsigned int i=0; igetNumUserObjects(); ++i) - target->getUserDataContainer()->addUserObject(source->getUserObject(i)); + target->getUserDataContainer()->addUserObject(osg::clone(source->getUserObject(i), osg::CopyOp::SHALLOW_COPY)); } } - osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, osg::Group* attachNode) + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node *master, const std::string &filter, osg::Group* attachNode) { - if (dynamic_cast(toAttach.get())) + if (dynamic_cast(toAttach.get())) { osg::ref_ptr handle = new osg::Group; CopyRigVisitor copyVisitor(handle, filter); - toAttach->accept(copyVisitor); + const_cast(toAttach.get())->accept(copyVisitor); copyVisitor.doCopy(); if (handle->getNumChildren() == 1) @@ -122,14 +118,16 @@ namespace SceneUtil else { master->asGroup()->addChild(handle); - handle->setUserDataContainer(toAttach->getUserDataContainer()); + mergeUserData(toAttach->getUserDataContainer(), handle); return handle; } } else { + osg::ref_ptr clonedToAttach = static_cast(toAttach->clone(SceneUtil::CopyOp())); + FindByNameVisitor findBoneOffset("BoneOffset"); - toAttach->accept(findBoneOffset); + clonedToAttach->accept(findBoneOffset); osg::ref_ptr trans; @@ -172,13 +170,13 @@ namespace SceneUtil if (trans) { attachNode->addChild(trans); - trans->addChild(toAttach); + trans->addChild(clonedToAttach); return trans; } else { - attachNode->addChild(toAttach); - return toAttach; + attachNode->addChild(clonedToAttach); + return clonedToAttach; } } } diff --git a/components/sceneutil/attach.hpp b/components/sceneutil/attach.hpp index a8a2239a84..806fc53488 100644 --- a/components/sceneutil/attach.hpp +++ b/components/sceneutil/attach.hpp @@ -14,12 +14,12 @@ namespace osg namespace SceneUtil { - /// Attach parts of the \a toAttach scenegraph to the \a master scenegraph, using the specified filter and attachment node. + /// Clone and attach parts of the \a toAttach scenegraph to the \a master scenegraph, using the specified filter and attachment node. /// If the \a toAttach scene graph contains skinned objects, we will attach only those (filtered by the \a filter). /// Otherwise, just attach all of the toAttach scenegraph to the attachment node on the master scenegraph, with no filtering. /// @note The master scene graph is expected to include a skeleton. /// @return A newly created node that is directly attached to the master scene graph - osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, osg::Group* attachNode); + osg::ref_ptr attach(osg::ref_ptr toAttach, osg::Node* master, const std::string& filter, osg::Group* attachNode); } From afba1884ab1977556e56055547e1c6c17704b0ac Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:04:11 +0000 Subject: [PATCH 35/59] clone.cpp remove dynamic_cast (#3097) --- components/sceneutil/clone.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/sceneutil/clone.cpp b/components/sceneutil/clone.cpp index 07a6e691ad..eaf5668c4a 100644 --- a/components/sceneutil/clone.cpp +++ b/components/sceneutil/clone.cpp @@ -2,8 +2,6 @@ #include -#include -#include #include #include @@ -35,11 +33,6 @@ namespace SceneUtil mUpdaterToOldPs[cloned] = updater->getParticleSystem(0); return cloned; } - - if (dynamic_cast(node) || dynamic_cast(node)) - { - return osg::clone(node, *this); - } return osg::CopyOp::operator()(node); } From c284d0cf5c6ca0a6a55e92f9de7351469946628d Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:04:38 +0000 Subject: [PATCH 36/59] actoranimation.cpp faster getbonebyname (#3099) --- apps/openmw/mwrender/actoranimation.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 4109d61e8c..8b0c09068a 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -67,17 +67,14 @@ ActorAnimation::~ActorAnimation() PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor) { - osg::Group* parent = getBoneByName(bonename); - if (!parent) - return nullptr; - - osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model, parent); - const NodeMap& nodeMap = getNodeMap(); NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) return PartHolderPtr(); + osg::Group* parent = found->second; + osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model, parent); + if (enchantedGlow) mGlowUpdater = SceneUtil::addEnchantedGlow(instance, mResourceSystem, *glowColor); @@ -136,9 +133,9 @@ bool ActorAnimation::updateCarriedLeftVisible(const int weaptype) const MWMechanics::CreatureStats &stats = cls.getCreatureStats(mPtr); if (cls.hasInventoryStore(mPtr) && weaptype != ESM::Weapon::Spell) { - SceneUtil::FindByNameVisitor findVisitor ("Bip01 AttachShield"); - mObjectRoot->accept(findVisitor); - if (findVisitor.mFoundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())) + osg::Group* foundNode = getBoneByName ("Bip01 AttachShield"); + + if (foundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())) { const MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr); const MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -276,10 +273,11 @@ osg::Group* ActorAnimation::getBoneByName(const std::string& boneName) if (!mObjectRoot) return nullptr; - SceneUtil::FindByNameVisitor findVisitor (boneName); - mObjectRoot->accept(findVisitor); - - return findVisitor.mFoundNode; + const NodeMap& nodeMap = getNodeMap(); + NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(boneName)); + if (found == nodeMap.end()) + return nullptr; + return found->second; } std::string ActorAnimation::getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon) From 9d661359a160c3fb265c71cbcacbd08945407e4c Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Thu, 9 Sep 2021 21:10:22 +0000 Subject: [PATCH 37/59] Groundcover consolidation (#3096) * chunkmanager.hpp viewdistance * chunkmanager.cpp viewdistance * chunkmanager.hpp viewdistance * quadtreeworld.cpp viewdistance * quadtreeworld.cpp consolidate * quadtreeworld.hpp consolidate * renderingmanager.cpp groundcover consolidate * renderingmanager.hpp groundcover consolidate * renderingmanager.cpp updater move * renderingmanager.hpp updater move * groundcover.hpp activegrid consolidation * groundcover.cpp activegrid consolidation * settings-default.cfg dead settings remove * viewdata.cpp revert * wrong file paste mistake * wrong file paste mistake * wrong file paste mistake * renderingmanager.cpp updatecallback fix * renderingmanager.cpp namespace fix * groundcover.hpp redefinition fix * groundcover.cpp redefinition fix * renderingmanager.cpp crash fix * renderingmanager.cpp euclidean groundcover distance * viewdata.hpp getreusedistance * quadtreeworld.cpp reusedistance * groundcover.rst [ci skip] --- apps/openmw/mwrender/groundcover.cpp | 4 +- apps/openmw/mwrender/groundcover.hpp | 4 +- apps/openmw/mwrender/renderingmanager.cpp | 52 +++++-------------- apps/openmw/mwrender/renderingmanager.hpp | 4 +- components/terrain/quadtreeworld.cpp | 26 +++++----- components/terrain/quadtreeworld.hpp | 7 ++- components/terrain/viewdata.cpp | 9 +--- components/terrain/viewdata.hpp | 2 + .../modding/settings/groundcover.rst | 14 ----- files/settings-default.cfg | 3 -- 10 files changed, 40 insertions(+), 85 deletions(-) diff --git a/apps/openmw/mwrender/groundcover.cpp b/apps/openmw/mwrender/groundcover.cpp index 947bdad202..a00d21bc97 100644 --- a/apps/openmw/mwrender/groundcover.cpp +++ b/apps/openmw/mwrender/groundcover.cpp @@ -180,7 +180,7 @@ namespace MWRender osg::ref_ptr Groundcover::getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) { - ChunkId id = std::make_tuple(center, size, activeGrid); + GroundcoverChunkId id = std::make_tuple(center, size); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) @@ -196,7 +196,7 @@ namespace MWRender } Groundcover::Groundcover(Resource::SceneManager* sceneManager, float density) - : GenericResourceManager(nullptr) + : GenericResourceManager(nullptr) , mSceneManager(sceneManager) , mDensity(density) { diff --git a/apps/openmw/mwrender/groundcover.hpp b/apps/openmw/mwrender/groundcover.hpp index b92ab97c95..10874b7e8b 100644 --- a/apps/openmw/mwrender/groundcover.hpp +++ b/apps/openmw/mwrender/groundcover.hpp @@ -29,8 +29,8 @@ namespace MWRender osg::Vec3f mPlayerPos; }; - typedef std::tuple ChunkId; // Center, Size, ActiveGrid - class Groundcover : public Resource::GenericResourceManager, public Terrain::QuadTreeWorld::ChunkManager + typedef std::tuple GroundcoverChunkId; // Center, Size + class Groundcover : public Resource::GenericResourceManager, public Terrain::QuadTreeWorld::ChunkManager { public: Groundcover(Resource::SceneManager* sceneManager, float density); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 381a2e5f62..56d3ba4a43 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -373,7 +373,9 @@ namespace MWRender mTerrainStorage.reset(new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps)); const float lodFactor = Settings::Manager::getFloat("lod factor", "Terrain"); - if (Settings::Manager::getBool("distant terrain", "Terrain")) + bool groundcover = Settings::Manager::getBool("enabled", "Groundcover"); + bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); + if (distantTerrain || groundcover) { const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain"); int compMapPower = Settings::Manager::getInt("composite map level", "Terrain"); @@ -398,41 +400,27 @@ namespace MWRender mTerrain->setTargetFrameRate(Settings::Manager::getFloat("target framerate", "Cells")); mTerrain->setWorkQueue(mWorkQueue.get()); - if (Settings::Manager::getBool("enabled", "Groundcover")) + osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; + + if (groundcover) { - osg::ref_ptr groundcoverRoot = new osg::Group; - groundcoverRoot->setNodeMask(Mask_Groundcover); - groundcoverRoot->setName("Groundcover Root"); - sceneRoot->addChild(groundcoverRoot); - - mGroundcoverUpdater = new GroundcoverUpdater; - groundcoverRoot->addUpdateCallback(mGroundcoverUpdater); - - float chunkSize = Settings::Manager::getFloat("min chunk size", "Groundcover"); - if (chunkSize >= 1.0f) - chunkSize = 1.0f; - else if (chunkSize >= 0.5f) - chunkSize = 0.5f; - else if (chunkSize >= 0.25f) - chunkSize = 0.25f; - else if (chunkSize != 0.125f) - chunkSize = 0.125f; - float density = Settings::Manager::getFloat("density", "Groundcover"); density = std::clamp(density, 0.f, 1.f); - mGroundcoverWorld.reset(new Terrain::QuadTreeWorld(groundcoverRoot, mTerrainStorage.get(), Mask_Groundcover, lodFactor, chunkSize)); + mGroundcoverUpdater = new GroundcoverUpdater; + composite->addController(mGroundcoverUpdater); + mGroundcover.reset(new Groundcover(mResourceSystem->getSceneManager(), density)); - static_cast(mGroundcoverWorld.get())->addChunkManager(mGroundcover.get()); + static_cast(mTerrain.get())->addChunkManager(mGroundcover.get()); mResourceSystem->addResourceManager(mGroundcover.get()); - // Groundcover it is handled in the same way indifferently from if it is from active grid or from distant cell. - // Use a stub grid to avoid splitting between chunks for active grid and chunks for distant cells. - mGroundcoverWorld->setActiveGrid(osg::Vec4i(0, 0, 0, 0)); + float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); + mGroundcover->setViewDistance(groundcoverDistance); } mStateUpdater = new StateUpdater; - sceneRoot->addUpdateCallback(mStateUpdater); + composite->addController(mStateUpdater); + sceneRoot->addUpdateCallback(composite); mSharedUniformStateUpdater = new SharedUniformStateUpdater; rootNode->addUpdateCallback(mSharedUniformStateUpdater); @@ -693,8 +681,6 @@ namespace MWRender if (store->getCell()->isExterior()) { mTerrain->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - if (mGroundcoverWorld) - mGroundcoverWorld->loadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } } void RenderingManager::removeCell(const MWWorld::CellStore *store) @@ -706,8 +692,6 @@ namespace MWRender if (store->getCell()->isExterior()) { mTerrain->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); - if (mGroundcoverWorld) - mGroundcoverWorld->unloadCell(store->getCell()->getGridX(), store->getCell()->getGridY()); } mWater->removeCell(store); @@ -718,8 +702,6 @@ namespace MWRender if (!enable) mWater->setCullCallback(nullptr); mTerrain->enable(enable); - if (mGroundcoverWorld) - mGroundcoverWorld->enable(enable); } void RenderingManager::setSkyEnabled(bool enabled) @@ -1179,12 +1161,6 @@ namespace MWRender fov = std::min(mFieldOfView, 140.f); float distanceMult = std::cos(osg::DegreesToRadians(fov)/2.f); mTerrain->setViewDistance(mViewDistance * (distanceMult ? 1.f/distanceMult : 1.f)); - - if (mGroundcoverWorld) - { - float groundcoverDistance = std::max(0.f, Settings::Manager::getFloat("rendering distance", "Groundcover")); - mGroundcoverWorld->setViewDistance(groundcoverDistance * (distanceMult ? 1.f/distanceMult : 1.f)); - } } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d6d7e74634..b991b08efa 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -262,8 +262,6 @@ namespace MWRender osg::ref_ptr mSceneRoot; Resource::ResourceSystem* mResourceSystem; - osg::ref_ptr mGroundcoverUpdater; - osg::ref_ptr mWorkQueue; osg::ref_ptr mUnrefQueue; @@ -278,10 +276,10 @@ namespace MWRender std::unique_ptr mObjects; std::unique_ptr mWater; std::unique_ptr mTerrain; - std::unique_ptr mGroundcoverWorld; std::unique_ptr mTerrainStorage; std::unique_ptr mObjectPaging; std::unique_ptr mGroundcover; + osg::ref_ptr mGroundcoverUpdater; std::unique_ptr mSky; std::unique_ptr mFog; std::unique_ptr mScreenshotManager; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 9ca504ebeb..6a228a75af 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -259,17 +259,6 @@ QuadTreeWorld::QuadTreeWorld(osg::Group *parent, osg::Group *compileRoot, Resour mChunkManagers.push_back(mChunkManager.get()); } -QuadTreeWorld::QuadTreeWorld(osg::Group *parent, Storage *storage, unsigned int nodeMask, float lodFactor, float chunkSize) - : TerrainGrid(parent, storage, nodeMask) - , mViewDataMap(new ViewDataMap) - , mQuadTreeBuilt(false) - , mLodFactor(lodFactor) - , mVertexLodMod(0) - , mViewDistance(std::numeric_limits::max()) - , mMinSize(chunkSize) -{ -} - QuadTreeWorld::~QuadTreeWorld() { } @@ -325,7 +314,7 @@ unsigned int getLodFlags(QuadTreeNode* node, int ourLod, int vertexLodMod, const return lodFlags; } -void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, float cellWorldSize, const osg::Vec4i &gridbounds, const std::vector& chunkManagers, bool compile) +void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, float cellWorldSize, const osg::Vec4i &gridbounds, const std::vector& chunkManagers, bool compile, float reuseDistance) { if (!vd->hasChanged() && entry.mRenderingNode) return; @@ -353,6 +342,8 @@ void loadRenderingNode(ViewData::Entry& entry, ViewData* vd, int vertexLodMod, f for (QuadTreeWorld::ChunkManager* m : chunkManagers) { + if (m->getViewDistance() && entry.mNode->distance(vd->getViewPoint()) > m->getViewDistance() + reuseDistance*10) + continue; osg::ref_ptr n = m->getChunk(entry.mNode->getSize(), entry.mNode->getCenter(), ourLod, entry.mLodFlags, activeGrid, vd->getViewPoint(), compile); if (n) pat->addChild(n); } @@ -447,7 +438,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv) for (unsigned int i=0; igetNumEntries(); ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, mActiveGrid, mChunkManagers, false); + loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, mActiveGrid, mChunkManagers, false, mViewDataMap->getReuseDistance()); entry.mRenderingNode->accept(nv); } @@ -517,8 +508,15 @@ void QuadTreeWorld::preload(View *view, const osg::Vec3f &viewPoint, const osg:: for (unsigned int i=0; igetNumEntries() && !abort; ++i) { ViewData::Entry& entry = vd->getEntry(i); - loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true); + + + + loadRenderingNode(entry, vd, mVertexLodMod, cellWorldSize, grid, mChunkManagers, true, mViewDataMap->getReuseDistance()); reporter.addProgress(entry.mNode->getSize()); + + + + } vd->markUnchanged(); } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 3a2aa8349d..3dd96a0b84 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -22,8 +22,6 @@ namespace Terrain public: QuadTreeWorld(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSystem* resourceSystem, Storage* storage, unsigned int nodeMask, unsigned int preCompileMask, unsigned int borderMask, int compMapResolution, float comMapLevel, float lodFactor, int vertexLodMod, float maxCompGeometrySize); - QuadTreeWorld(osg::Group *parent, Storage *storage, unsigned int nodeMask, float lodFactor, float chunkSize); - ~QuadTreeWorld(); void accept(osg::NodeVisitor& nv); @@ -51,6 +49,11 @@ namespace Terrain virtual ~ChunkManager(){} virtual osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile) = 0; virtual unsigned int getNodeMask() { return 0; } + + void setViewDistance(float viewDistance) { mViewDistance = viewDistance; } + float getViewDistance() const { return mViewDistance; } + private: + float mViewDistance = 0.f; }; void addChunkManager(ChunkManager*); diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index 996bf909c8..e4d043ffc4 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -141,9 +141,9 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo vd = found->second; needsUpdate = false; - if (!vd->suitableToUse(activeGrid) || (vd->getViewPoint()-viewPoint).length2() >= mReuseDistance*mReuseDistance || vd->getWorldUpdateRevision() < mWorldUpdateRevision) + if (!(vd->suitableToUse(activeGrid) && (vd->getViewPoint()-viewPoint).length2() < mReuseDistance*mReuseDistance && vd->getWorldUpdateRevision() >= mWorldUpdateRevision)) { - float shortestDist = viewer ? mReuseDistance*mReuseDistance : std::numeric_limits::max(); + float shortestDist = std::numeric_limits::max(); const ViewData* mostSuitableView = nullptr; for (const ViewData* other : mUsedViews) { @@ -162,11 +162,6 @@ ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPo vd->copyFrom(*mostSuitableView); return vd; } - else if (!mostSuitableView) - { - vd->setViewPoint(viewPoint); - needsUpdate = true; - } } if (!vd->suitableToUse(activeGrid)) { diff --git a/components/terrain/viewdata.hpp b/components/terrain/viewdata.hpp index 0289352585..378d07663c 100644 --- a/components/terrain/viewdata.hpp +++ b/components/terrain/viewdata.hpp @@ -95,6 +95,8 @@ namespace Terrain void rebuildViews(); bool storeView(const ViewData* view, double referenceTime); + float getReuseDistance() const { return mReuseDistance; } + private: std::list mViewVector; diff --git a/docs/source/reference/modding/settings/groundcover.rst b/docs/source/reference/modding/settings/groundcover.rst index 7c5a965e01..3e943e4284 100644 --- a/docs/source/reference/modding/settings/groundcover.rst +++ b/docs/source/reference/modding/settings/groundcover.rst @@ -40,20 +40,6 @@ May affect performance a lot. This setting can only be configured by editing the settings configuration file. -min chunk size --------------- - -:Type: floating point -:Range: 0.125, 0.25, 0.5, 1.0 -:Default: 0.5 - -Determines a minimum size of groundcover chunks in cells. For example, with 0.5 value -chunks near player will have size 4096x4096 game units. Larger chunks reduce CPU usage -(Draw and Cull bars), but can increase GPU usage (GPU bar) since culling becomes less efficient. -Smaller values do an opposite. - -This setting can only be configured by editing the settings configuration file. - stomp mode ---------- diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4737fcf5ee..7f57ba529d 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -1087,9 +1087,6 @@ density = 1.0 # A maximum distance in game units on which groundcover is rendered. rendering distance = 6144.0 -# A minimum size of groundcover chunk in cells (0.125, 0.25, 0.5, 1.0) -min chunk size = 0.5 - # Whether grass should respond to the player treading on it. # 0 - Grass cannot be trampled. # 1 - The player's XY position is taken into account. From 1edeffbafca621dce1888b75c0d6564f04d48390 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Thu, 9 Sep 2021 23:57:20 +0200 Subject: [PATCH 38/59] constify getBoneByName --- apps/openmw/mwrender/actoranimation.cpp | 2 +- apps/openmw/mwrender/actoranimation.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 8b0c09068a..cb46354590 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -268,7 +268,7 @@ bool ActorAnimation::useShieldAnimations() const return false; } -osg::Group* ActorAnimation::getBoneByName(const std::string& boneName) +osg::Group* ActorAnimation::getBoneByName(const std::string& boneName) const { if (!mObjectRoot) return nullptr; diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index e6bba48d56..61ad1ca235 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -41,7 +41,7 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener bool updateCarriedLeftVisible(const int weaptype) const override; protected: - osg::Group* getBoneByName(const std::string& boneName); + osg::Group* getBoneByName(const std::string& boneName) const; virtual void updateHolsteredWeapon(bool showHolsteredWeapons); virtual void updateHolsteredShield(bool showCarriedLeft); virtual void updateQuiver(); From 01a8998e3bca50cce6b749a510a4b3ee8cc3c9fb Mon Sep 17 00:00:00 2001 From: psi29a Date: Fri, 10 Sep 2021 14:04:11 +0000 Subject: [PATCH 39/59] return if source is null in mergeUserData --- components/sceneutil/attach.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index fe8aad0879..6690148c74 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -88,6 +88,9 @@ namespace SceneUtil void mergeUserData(const osg::UserDataContainer* source, osg::Object* target) { + if (!source) + return; + if (!target->getUserDataContainer()) target->setUserDataContainer(osg::clone(source, osg::CopyOp::SHALLOW_COPY)); else From ac72f3d636fedae5fbb5491bd785652fe8e33688 Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Fri, 10 Sep 2021 15:58:57 +0000 Subject: [PATCH 40/59] reduces virtual function calls in a hotspot of cache retrieval (#3100) * chunkmanager.cpp static_cast [ci skip] * groundcover.cpp static_cast [ci skip] * Update objectpaging.cpp objectpaging.cpp static_cast [ci skip] --- apps/openmw/mwrender/groundcover.cpp | 2 +- apps/openmw/mwrender/objectpaging.cpp | 2 +- components/terrain/chunkmanager.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/groundcover.cpp b/apps/openmw/mwrender/groundcover.cpp index a00d21bc97..39022709fb 100644 --- a/apps/openmw/mwrender/groundcover.cpp +++ b/apps/openmw/mwrender/groundcover.cpp @@ -184,7 +184,7 @@ namespace MWRender osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) - return obj->asNode(); + return static_cast(obj.get()); else { InstanceMap instances; diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index b23f079888..907631436f 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -77,7 +77,7 @@ namespace MWRender osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) - return obj->asNode(); + return static_cast(obj.get()); else { osg::ref_ptr node = createChunk(size, center, activeGrid, viewPoint, compile); diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index a744471de5..8809a75bb9 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -45,7 +45,7 @@ osg::ref_ptr ChunkManager::getChunk(float size, const osg::Vec2f& cen ChunkId id = std::make_tuple(center, lod, lodFlags); osg::ref_ptr obj = mCache->getRefFromObjectCache(id); if (obj) - return obj->asNode(); + return static_cast(obj.get()); else { osg::ref_ptr node = createChunk(size, center, lod, lodFlags, compile); From 36ba56a5137b598f824b867e4c93a9fa9772df6c Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 11 Sep 2021 13:49:00 +0200 Subject: [PATCH 41/59] Support multiple file sources for osg stats --- scripts/osg_stats.py | 167 +++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 76 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index 3397b58f26..f0e6ce4010 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -45,30 +45,30 @@ import termtables help='Start processing from this frame.') @click.option('--end_frame', type=int, default=sys.maxsize, help='End processing at this frame.') -@click.argument('path', default='', type=click.Path()) +@click.argument('path', type=click.Path(), nargs=-1) def main(print_keys, timeseries, hist, hist_ratio, stdev_hist, plot, stats, timeseries_sum, stats_sum, begin_frame, end_frame, path, commulative_timeseries, commulative_timeseries_sum): - data = list(read_data(path)) - keys = collect_unique_keys(data) - frames = collect_per_frame(data=data, keys=keys, begin_frame=begin_frame, end_frame=end_frame) + sources = {v: list(read_data(v)) for v in path} if path else {'stdin': list(read_data(None))} + keys = collect_unique_keys(sources) + frames = collect_per_frame(sources=sources, keys=keys, begin_frame=begin_frame, end_frame=end_frame) if print_keys: for v in keys: print(v) if timeseries: - draw_timeseries(frames=frames, keys=timeseries, add_sum=timeseries_sum) + draw_timeseries(sources=frames, keys=timeseries, add_sum=timeseries_sum) if commulative_timeseries: - draw_commulative_timeseries(frames=frames, keys=commulative_timeseries, add_sum=commulative_timeseries_sum) + draw_commulative_timeseries(sources=frames, keys=commulative_timeseries, add_sum=commulative_timeseries_sum) if hist: - draw_hists(frames=frames, keys=hist) + draw_hists(sources=frames, keys=hist) if hist_ratio: - draw_hist_ratio(frames=frames, pairs=hist_ratio) + draw_hist_ratio(sources=frames, pairs=hist_ratio) if stdev_hist: - draw_stdev_hists(frames=frames, stdev_hists=stdev_hist) + draw_stdev_hists(sources=frames, stdev_hists=stdev_hist) if plot: - draw_plots(frames=frames, plots=plot) + draw_plots(sources=frames, plots=plot) if stats: - print_stats(frames=frames, keys=stats, stats_sum=stats_sum) + print_stats(sources=frames, keys=stats, stats_sum=stats_sum) matplotlib.pyplot.show() @@ -92,126 +92,140 @@ def read_data(path): frame[key] = to_number(value) -def collect_per_frame(data, keys, begin_frame, end_frame): - result = collections.defaultdict(list) - for frame in data: - for key in keys: - if key in frame: - result[key].append(frame[key]) - else: - result[key].append(None) - for key, values in result.items(): - result[key] = numpy.array(values[begin_frame:end_frame]) +def collect_per_frame(sources, keys, begin_frame, end_frame): + result = collections.defaultdict(lambda: collections.defaultdict(list)) + for name, frames in sources.items(): + for frame in frames: + for key in keys: + if key in frame: + result[name][key].append(frame[key]) + else: + result[name][key].append(None) + for name, sources in result.items(): + for key, values in sources.items(): + result[name][key] = numpy.array(values[begin_frame:end_frame]) return result -def collect_unique_keys(frames): +def collect_unique_keys(sources): result = set() - for frame in frames: - for key in frame.keys(): - result.add(key) + for frames in sources.values(): + for frame in frames: + for key in frame.keys(): + result.add(key) return sorted(result) -def draw_timeseries(frames, keys, add_sum): +def draw_timeseries(sources, keys, add_sum): fig, ax = matplotlib.pyplot.subplots() - x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) - for key in keys: - ax.plot(x, frames[key], label=key) - if add_sum: - ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label='sum') + for name, frames in sources.items(): + x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) + for key in keys: + print(key, name) + ax.plot(x, frames[key], label=f'{key}:{name}') + if add_sum: + ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label=f'sum:{name}') ax.grid(True) ax.legend() fig.canvas.set_window_title('timeseries') -def draw_commulative_timeseries(frames, keys, add_sum): +def draw_commulative_timeseries(sources, keys, add_sum): fig, ax = matplotlib.pyplot.subplots() - x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) - for key in keys: - ax.plot(x, numpy.cumsum(frames[key]), label=key) - if add_sum: - ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label='sum') + for name, frames in sources.items(): + x = numpy.array(range(max(len(v) for k, v in frames.items() if k in keys))) + for key in keys: + ax.plot(x, numpy.cumsum(frames[key]), label=f'{key}:{name}') + if add_sum: + ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label=f'sum:{name}') ax.grid(True) ax.legend() fig.canvas.set_window_title('commulative_timeseries') -def draw_hists(frames, keys): +def draw_hists(sources, keys): fig, ax = matplotlib.pyplot.subplots() bins = numpy.linspace( - start=min(min(v) for k, v in frames.items() if k in keys), - stop=max(max(v) for k, v in frames.items() if k in keys), + start=min(min(min(v) for k, v in f.items() if k in keys) for f in sources.values()), + stop=max(max(max(v) for k, v in f.items() if k in keys) for f in sources.values()), num=20, ) - for key in keys: - ax.hist(frames[key], bins=bins, label=key, alpha=1 / len(keys)) + for name, frames in sources.items(): + for key in keys: + ax.hist(frames[key], bins=bins, label=f'{key}:{name}', alpha=1 / (len(keys) * len(sources))) ax.set_xticks(bins) ax.grid(True) ax.legend() fig.canvas.set_window_title('hists') -def draw_hist_ratio(frames, pairs): +def draw_hist_ratio(sources, pairs): fig, ax = matplotlib.pyplot.subplots() bins = numpy.linspace( - start=min(min(a / b for a, b in zip(frames[a], frames[b])) for a, b in pairs), - stop=max(max(a / b for a, b in zip(frames[a], frames[b])) for a, b in pairs), + start=min(min(min(a / b for a, b in zip(f[a], f[b])) for a, b in pairs) for f in sources.values()), + stop=max(max(max(a / b for a, b in zip(f[a], f[b])) for a, b in pairs) for f in sources.values()), num=20, ) - for a, b in pairs: - ax.hist(frames[a] / frames[b], bins=bins, label=f'{a} / {b}', alpha=1 / len(pairs)) + for name, frames in sources.items(): + for a, b in pairs: + ax.hist(frames[a] / frames[b], bins=bins, label=f'{a} / {b}:{name}', alpha=1 / (len(pairs) * len(sources))) ax.set_xticks(bins) ax.grid(True) ax.legend() - fig.canvas.set_window_title('hists') + fig.canvas.set_window_title('hists_ratio') -def draw_stdev_hists(frames, stdev_hists): +def draw_stdev_hists(sources, stdev_hists): for key, scale in stdev_hists: scale = float(scale) fig, ax = matplotlib.pyplot.subplots() - median = statistics.median(frames[key]) - stdev = statistics.stdev(frames[key]) + first_frames = next(v for v in sources.values()) + median = statistics.median(first_frames[key]) + stdev = statistics.stdev(first_frames[key]) start = median - stdev / 2 * scale stop = median + stdev / 2 * scale bins = numpy.linspace(start=start, stop=stop, num=9) - values = [v for v in frames[key] if start <= v <= stop] - ax.hist(values, bins=bins, label=key, alpha=1 / len(stdev_hists)) + for name, frames in sources.items(): + values = [v for v in frames[key] if start <= v <= stop] + ax.hist(values, bins=bins, label=f'{key}:{name}', alpha=1 / (len(stdev_hists) * len(sources))) ax.set_xticks(bins) ax.grid(True) ax.legend() fig.canvas.set_window_title('stdev_hists') -def draw_plots(frames, plots): +def draw_plots(sources, plots): fig, ax = matplotlib.pyplot.subplots() - for x_key, y_key, agg in plots: - if agg is None: - ax.plot(frames[x_key], frames[y_key], label=f'x={x_key}, y={y_key}') - elif agg: - agg_f = dict( - mean=statistics.mean, - median=statistics.median, - )[agg] - grouped = collections.defaultdict(list) - for x, y in zip(frames[x_key], frames[y_key]): - grouped[x].append(y) - aggregated = sorted((k, agg_f(v)) for k, v in grouped.items()) - ax.plot( - numpy.array([v[0] for v in aggregated]), - numpy.array([v[1] for v in aggregated]), - label=f'x={x_key}, y={y_key}, agg={agg}', - ) + for name, frames in sources.items(): + for x_key, y_key, agg in plots: + if agg is None: + ax.plot(frames[x_key], frames[y_key], label=f'x={x_key}, y={y_key}:{name}') + elif agg: + agg_f = dict( + mean=statistics.mean, + median=statistics.median, + )[agg] + grouped = collections.defaultdict(list) + for x, y in zip(frames[x_key], frames[y_key]): + grouped[x].append(y) + aggregated = sorted((k, agg_f(v)) for k, v in grouped.items()) + ax.plot( + numpy.array([v[0] for v in aggregated]), + numpy.array([v[1] for v in aggregated]), + label=f'x={x_key}, y={y_key}, agg={agg}:{name}', + ) ax.grid(True) ax.legend() fig.canvas.set_window_title('plots') -def print_stats(frames, keys, stats_sum): - stats = [make_stats(key=key, values=filter_not_none(frames[key])) for key in keys] - if stats_sum: - stats.append(make_stats(key='sum', values=sum_multiple(frames, keys))) +def print_stats(sources, keys, stats_sum): + stats = list() + for name, frames in sources.items(): + for key in keys: + stats.append(make_stats(source=name, key=key, values=filter_not_none(frames[key]))) + if stats_sum: + stats.append(make_stats(source=name, key='sum', values=sum_multiple(frames, keys))) metrics = list(stats[0].keys()) max_key_size = max(len(tuple(v.values())[0]) for v in stats) termtables.print( @@ -235,8 +249,9 @@ def sum_multiple(frames, keys): return numpy.array([result[k] for k in sorted(result.keys())]) -def make_stats(key, values): +def make_stats(source, key, values): return collections.OrderedDict( + source=source, key=key, number=len(values), min=min(values), From e2d0e860208b6f82f9b7e3d3529597a6e7520e7f Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Sat, 11 Sep 2021 18:58:42 +0000 Subject: [PATCH 42/59] cellpreloader.cpp unused variable (#3102) --- apps/openmw/mwworld/cellpreloader.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index b2dba1d452..c29d975c24 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -95,7 +95,6 @@ namespace MWWorld { mesh = Misc::ResourceHelpers::correctActorModelPath(mesh, mSceneManager->getVFS()); - bool animated = false; size_t slashpos = mesh.find_last_of("/\\"); if (slashpos != std::string::npos && slashpos != mesh.size()-1) { @@ -107,10 +106,7 @@ namespace MWWorld { kfname.replace(kfname.size()-4, 4, ".kf"); if (mSceneManager->getVFS()->exists(kfname)) - { mPreloadedObjects.insert(mKeyframeManager->get(kfname)); - animated = true; - } } } } From c40f921396927eacbadb24c198692fe4e416acb5 Mon Sep 17 00:00:00 2001 From: psi29a Date: Sun, 12 Sep 2021 07:56:20 +0000 Subject: [PATCH 43/59] Revert "actoranimation.cpp faster getbonebyname (#3099)" This reverts commit c284d0cf5c6ca0a6a55e92f9de7351469946628d --- apps/openmw/mwrender/actoranimation.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index cb46354590..f556e6891a 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -67,14 +67,17 @@ ActorAnimation::~ActorAnimation() PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor) { + osg::Group* parent = getBoneByName(bonename); + if (!parent) + return nullptr; + + osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model, parent); + const NodeMap& nodeMap = getNodeMap(); NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(bonename)); if (found == nodeMap.end()) return PartHolderPtr(); - osg::Group* parent = found->second; - osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model, parent); - if (enchantedGlow) mGlowUpdater = SceneUtil::addEnchantedGlow(instance, mResourceSystem, *glowColor); @@ -133,9 +136,9 @@ bool ActorAnimation::updateCarriedLeftVisible(const int weaptype) const MWMechanics::CreatureStats &stats = cls.getCreatureStats(mPtr); if (cls.hasInventoryStore(mPtr) && weaptype != ESM::Weapon::Spell) { - osg::Group* foundNode = getBoneByName ("Bip01 AttachShield"); - - if (foundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())) + SceneUtil::FindByNameVisitor findVisitor ("Bip01 AttachShield"); + mObjectRoot->accept(findVisitor); + if (findVisitor.mFoundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())) { const MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr); const MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -273,11 +276,10 @@ osg::Group* ActorAnimation::getBoneByName(const std::string& boneName) const if (!mObjectRoot) return nullptr; - const NodeMap& nodeMap = getNodeMap(); - NodeMap::const_iterator found = nodeMap.find(Misc::StringUtils::lowerCase(boneName)); - if (found == nodeMap.end()) - return nullptr; - return found->second; + SceneUtil::FindByNameVisitor findVisitor (boneName); + mObjectRoot->accept(findVisitor); + + return findVisitor.mFoundNode; } std::string ActorAnimation::getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon) From 52a9b4d989d3489e2238ce538516904574edb04d Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Sun, 12 Sep 2021 09:21:10 +0000 Subject: [PATCH 44/59] shadowsbin.cpp uniform --- components/sceneutil/shadowsbin.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/components/sceneutil/shadowsbin.cpp b/components/sceneutil/shadowsbin.cpp index 14dbc14178..af62b581c9 100644 --- a/components/sceneutil/shadowsbin.cpp +++ b/components/sceneutil/shadowsbin.cpp @@ -54,6 +54,7 @@ ShadowsBin::ShadowsBin() mShaderAlphaTestStateSet = new osg::StateSet; mShaderAlphaTestStateSet->addUniform(new osg::Uniform("alphaTestShadows", true)); + mShaderAlphaTestStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); mShaderAlphaTestStateSet->setMode(GL_BLEND, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED | osg::StateAttribute::OVERRIDE); for (size_t i = 0; i < sCastingPrograms.size(); ++i) From 6d12a240a39492f9ea7f3a94709cb641b9697ced Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Sun, 12 Sep 2021 09:23:36 +0000 Subject: [PATCH 45/59] shadervisitor.cpp uniform --- components/shader/shadervisitor.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 26511d4654..a72d772afe 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -340,15 +340,6 @@ namespace Shader mRequirements.back().mShaderRequired = true; } } - - if (diffuseMap) - { - if (!writableStateSet) - writableStateSet = getWritableStateSet(node); - // We probably shouldn't construct a new version of this each time as Uniforms use pointer comparison for early-out. - // Also it should probably belong to the shader manager or be applied by the shadows bin - writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); - } } const osg::StateSet::AttributeList& attributes = stateset->getAttributeList(); From b6f572578e04cf2e7a6fa2b9d09c2ea27e6e42e7 Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Mon, 13 Sep 2021 10:20:00 +0000 Subject: [PATCH 46/59] Groundcover optimisation (#3101) * groundcover.cpp share state * groundcover.hpp share state --- apps/openmw/mwrender/groundcover.cpp | 54 ++++++++-------------------- apps/openmw/mwrender/groundcover.hpp | 1 + 2 files changed, 16 insertions(+), 39 deletions(-) diff --git a/apps/openmw/mwrender/groundcover.cpp b/apps/openmw/mwrender/groundcover.cpp index 39022709fb..a199201d41 100644 --- a/apps/openmw/mwrender/groundcover.cpp +++ b/apps/openmw/mwrender/groundcover.cpp @@ -1,6 +1,7 @@ #include "groundcover.hpp" #include +#include #include #include @@ -66,18 +67,6 @@ namespace MWRender { } - void apply(osg::Node& node) override - { - osg::ref_ptr ss = node.getStateSet(); - if (ss != nullptr) - { - ss->removeAttribute(osg::StateAttribute::MATERIAL); - removeAlpha(ss); - } - - traverse(node); - } - void apply(osg::Geometry& geom) override { for (unsigned int i = 0; i < geom.getNumPrimitiveSets(); ++i) @@ -110,32 +99,14 @@ namespace MWRender // Display lists do not support instancing in OSG 3.4 geom.setUseDisplayList(false); + geom.setUseVertexBufferObjects(true); geom.setVertexAttribArray(6, transforms.get(), osg::Array::BIND_PER_VERTEX); geom.setVertexAttribArray(7, rotations.get(), osg::Array::BIND_PER_VERTEX); - - osg::ref_ptr ss = geom.getOrCreateStateSet(); - ss->setAttribute(new osg::VertexAttribDivisor(6, 1)); - ss->setAttribute(new osg::VertexAttribDivisor(7, 1)); - - ss->removeAttribute(osg::StateAttribute::MATERIAL); - removeAlpha(ss); - - traverse(geom); } private: std::vector mInstances; osg::Vec3f mChunkPosition; - - void removeAlpha(osg::StateSet* stateset) - { - // MGE uses default alpha settings for groundcover, so we can not rely on alpha properties - stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC); - stateset->removeMode(GL_ALPHA_TEST); - stateset->removeAttribute(osg::StateAttribute::BLENDFUNC); - stateset->removeMode(GL_BLEND); - stateset->setRenderBinToInherit(); - } }; class DensityCalculator @@ -199,7 +170,16 @@ namespace MWRender : GenericResourceManager(nullptr) , mSceneManager(sceneManager) , mDensity(density) + , mStateset(new osg::StateSet) { + // MGE uses default alpha settings for groundcover, so we can not rely on alpha properties + // Force a unified alpha handling instead of data from meshes + osg::ref_ptr alpha = new osg::AlphaFunc(osg::AlphaFunc::GEQUAL, 128.f / 255.f); + mStateset->setAttributeAndModes(alpha.get(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mStateset->setAttributeAndModes(new osg::BlendFunc, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); + mStateset->setRenderBinDetails(0, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS); + mStateset->setAttribute(new osg::VertexAttribDivisor(6, 1)); + mStateset->setAttribute(new osg::VertexAttribDivisor(7, 1)); } void Groundcover::collectInstances(InstanceMap& instances, float size, const osg::Vec2f& center) @@ -255,27 +235,23 @@ namespace MWRender for (auto& pair : instances) { const osg::Node* temp = mSceneManager->getTemplate(pair.first); - osg::ref_ptr node = static_cast(temp->clone(osg::CopyOp::DEEP_COPY_ALL&(~osg::CopyOp::DEEP_COPY_TEXTURES))); + osg::ref_ptr node = static_cast(temp->clone(osg::CopyOp::DEEP_COPY_NODES|osg::CopyOp::DEEP_COPY_DRAWABLES|osg::CopyOp::DEEP_COPY_USERDATA|osg::CopyOp::DEEP_COPY_ARRAYS|osg::CopyOp::DEEP_COPY_PRIMITIVES)); // Keep link to original mesh to keep it in cache group->getOrCreateUserDataContainer()->addUserObject(new Resource::TemplateRef(temp)); - mSceneManager->reinstateRemovedState(node); - InstancingVisitor visitor(pair.second, worldCenter); node->accept(visitor); group->addChild(node); } - // Force a unified alpha handling instead of data from meshes - osg::ref_ptr alpha = new osg::AlphaFunc(osg::AlphaFunc::GEQUAL, 128.f / 255.f); - group->getOrCreateStateSet()->setAttributeAndModes(alpha.get(), osg::StateAttribute::ON); - group->getBound(); + group->setStateSet(mStateset); group->setNodeMask(Mask_Groundcover); if (mSceneManager->getLightingMethod() != SceneUtil::LightingMethod::FFP) group->setCullCallback(new SceneUtil::LightListCallback); mSceneManager->recreateShaders(group, "groundcover", false, true); - + mSceneManager->shareState(group); + group->getBound(); return group; } diff --git a/apps/openmw/mwrender/groundcover.hpp b/apps/openmw/mwrender/groundcover.hpp index 10874b7e8b..4874bea899 100644 --- a/apps/openmw/mwrender/groundcover.hpp +++ b/apps/openmw/mwrender/groundcover.hpp @@ -56,6 +56,7 @@ namespace MWRender private: Resource::SceneManager* mSceneManager; float mDensity; + osg::ref_ptr mStateset; typedef std::map> InstanceMap; osg::ref_ptr createChunk(InstanceMap& instances, const osg::Vec2f& center); From e4eeb9cce9b29702bfde7dc9fdd3b983a8d69249 Mon Sep 17 00:00:00 2001 From: pi03k Date: Tue, 7 Sep 2021 23:10:18 +0200 Subject: [PATCH 47/59] Remove 'no relevant classes' moc warning --- CHANGELOG.md | 1 + CMakeLists.txt | 2 -- apps/launcher/CMakeLists.txt | 21 +++------------------ apps/opencs/CMakeLists.txt | 5 ++++- apps/opencs/view/tools/merge.hpp | 4 ++-- apps/wizard/CMakeLists.txt | 23 ++++------------------- cmake/OpenMWMacros.cmake | 6 ------ components/CMakeLists.txt | 7 +++++-- 8 files changed, 19 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1132a9e68..ffabc0b037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly Feature #6199: Support FBO Rendering Feature #6251: OpenMW-CS: Set instance movement based on camera zoom + Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings Task #6264: Remove the old classes in animation.cpp 0.47.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 52a824d4e9..d14762ef5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,8 +202,6 @@ if (USE_QT) find_package(Qt5Widgets REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5OpenGL REQUIRED) - # Instruct CMake to run moc automatically when needed. - #set(CMAKE_AUTOMOC ON) endif() set(USED_OSG_COMPONENTS diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index e9ec906e6a..7e8bd67e94 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -36,23 +36,6 @@ set(LAUNCHER_HEADER ) # Headers that must be pre-processed -set(LAUNCHER_HEADER_MOC - datafilespage.hpp - graphicspage.hpp - maindialog.hpp - playpage.hpp - textslotmsgbox.hpp - settingspage.hpp - advancedpage.hpp - - utils/cellnameloader.hpp - utils/textinputdialog.hpp - utils/profilescombobox.hpp - utils/lineedit.hpp - utils/openalutil.hpp - -) - set(LAUNCHER_UI ${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui ${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui @@ -74,7 +57,6 @@ if(WIN32) endif(WIN32) QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) -QT5_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) QT5_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -109,4 +91,7 @@ if (BUILD_WITH_CODE_COVERAGE) target_link_libraries(openmw-launcher gcov) endif() +if(USE_QT) + set_property(TARGET openmw-launcher PROPERTY AUTOMOC ON) +endif(USE_QT) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4b3b8030e6..60bd0f4ded 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -150,7 +150,6 @@ if(WIN32) endif(WIN32) qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) -qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) # for compiled .ui files @@ -259,3 +258,7 @@ endif (MSVC) if(APPLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT Bundle) endif() + +if(USE_QT) + set_property(TARGET openmw-cs PROPERTY AUTOMOC ON) +endif(USE_QT) diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index d394a431ed..c7c4585979 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -1,5 +1,5 @@ -#ifndef CSV_TOOLS_REPORTTABLE_H -#define CSV_TOOLS_REPORTTABLE_H +#ifndef CSV_TOOLS_MERGE_H +#define CSV_TOOLS_MERGE_H #include diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 2558ec81de..03cd63480a 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -1,4 +1,3 @@ - set(WIZARD componentselectionpage.cpp conclusionpage.cpp @@ -34,21 +33,6 @@ set(WIZARD_HEADER utils/componentlistwidget.hpp ) -# Headers that must be pre-processed -set(WIZARD_HEADER_MOC - componentselectionpage.hpp - conclusionpage.hpp - existinginstallationpage.hpp - importpage.hpp - installationtargetpage.hpp - intropage.hpp - languageselectionpage.hpp - mainwizard.hpp - methodselectionpage.hpp - - utils/componentlistwidget.hpp -) - set(WIZARD_UI ${CMAKE_SOURCE_DIR}/files/ui/wizard/componentselectionpage.ui ${CMAKE_SOURCE_DIR}/files/ui/wizard/conclusionpage.ui @@ -63,7 +47,6 @@ set(WIZARD_UI if (OPENMW_USE_UNSHIELD) set (WIZARD ${WIZARD} installationpage.cpp unshield/unshieldworker.cpp) set (WIZARD_HEADER ${WIZARD_HEADER} installationpage.hpp unshield/unshieldworker.hpp) - set (WIZARD_HEADER_MOC ${WIZARD_HEADER_MOC} installationpage.hpp unshield/unshieldworker.hpp) set (WIZARD_UI ${WIZARD_UI} ${CMAKE_SOURCE_DIR}/files/ui/wizard/installationpage.ui) add_definitions(-DOPENMW_USE_UNSHIELD) endif (OPENMW_USE_UNSHIELD) @@ -80,7 +63,6 @@ if(WIN32) endif(WIN32) QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/wizard/wizard.qrc) -QT5_WRAP_CPP(MOC_SRCS ${WIZARD_HEADER_MOC}) QT5_WRAP_UI(UI_HDRS ${WIZARD_UI}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) @@ -94,7 +76,6 @@ openmw_add_executable(openmw-wizard ${WIZARD} ${WIZARD_HEADER} ${RCC_SRCS} - ${MOC_SRCS} ${UI_HDRS} ) @@ -125,3 +106,7 @@ endif() if (WIN32) INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".") endif(WIN32) + +if(USE_QT) + set_property(TARGET openmw-wizard PROPERTY AUTOMOC ON) +endif(USE_QT) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 176a02d507..5bee345344 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -80,10 +80,6 @@ foreach (f ${ALL}) list (APPEND files "${f}") list (APPEND COMPONENT_QT_FILES "${f}") endforeach (f) -file (GLOB MOC_H "${dir}/${u}.hpp") -foreach (fi ${MOC_H}) -list (APPEND COMPONENT_MOC_FILES "${fi}") -endforeach (fi) endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_qt_dir) @@ -99,7 +95,6 @@ endmacro (add_unit) macro (add_qt_unit project dir unit) add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") -add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") endmacro (add_qt_unit) @@ -109,7 +104,6 @@ endmacro (add_hdr) macro (add_qt_hdr project dir unit) add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") -add_file (${project} _HDR_QT ${comp} "${dir}/${unit}.hpp") endmacro (add_qt_hdr) macro (opencs_units dir) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7983de6190..5b79a096cd 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -226,7 +226,6 @@ if (USE_QT) ) QT5_WRAP_UI(ESM_UI_HDR ${ESM_UI}) - QT5_WRAP_CPP(MOC_SRCS ${COMPONENT_MOC_FILES}) endif() if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -280,7 +279,7 @@ if (WIN32) endif() if (USE_QT) - add_library(components_qt STATIC ${COMPONENT_QT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) + add_library(components_qt STATIC ${COMPONENT_QT_FILES} ${ESM_UI_HDR}) target_link_libraries(components_qt components Qt5::Widgets Qt5::Core) target_compile_definitions(components_qt PRIVATE OPENMW_DOC_BASEURL="${OPENMW_DOC_BASEURL}") endif() @@ -333,3 +332,7 @@ if(OSG_STATIC) target_link_libraries(components freetype jpeg png) endif() endif(OSG_STATIC) + +if(USE_QT) + set_property(TARGET components_qt PROPERTY AUTOMOC ON) +endif(USE_QT) From 3415f12e128a2de023872d8cfb277de1fa2af275 Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Tue, 14 Sep 2021 11:30:07 +0000 Subject: [PATCH 48/59] shadervisitor.cpp --- components/shader/shadervisitor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index a72d772afe..cb0173c648 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -458,6 +458,9 @@ namespace Shader defineMap[texIt->second + std::string("UV")] = std::to_string(texIt->first); } + if (defineMap["diffuseMap"] == 0) + writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); + defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); From 2cebd194327b285b8a151b81b9f95dd8fbdd03ce Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Tue, 14 Sep 2021 11:37:23 +0000 Subject: [PATCH 49/59] shadervisitor.cpp --- components/shader/shadervisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index cb0173c648..cbd2863e46 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -458,7 +458,7 @@ namespace Shader defineMap[texIt->second + std::string("UV")] = std::to_string(texIt->first); } - if (defineMap["diffuseMap"] == 0) + if (defineMap["diffuseMap"] == "0") writableStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", false)); defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; From 60298cd66de1bc9a1fefd1cec23218a64c21678b Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 14 Sep 2021 16:53:57 +0200 Subject: [PATCH 50/59] Reset rotation when respawning actors --- CHANGELOG.md | 1 + apps/openmw/mwclass/creature.cpp | 1 + apps/openmw/mwclass/npc.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1132a9e68..91602e5408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Bug #6174: Spellmaking and Enchanting sliders differences from vanilla Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla Bug #6197: Infinite Casting Loop + Bug #6273: Respawning NPCs rotation is inconsistent Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record Feature #2780: A way to see current OpenMW version in the console Feature #3616: Allow Zoom levels on the World Map diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 50dafba39b..54623e6699 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -846,6 +846,7 @@ namespace MWClass // Reset to original position MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().asVec3()); + MWBase::Environment::get().getWorld()->rotateObject(ptr, ptr.getCellRef().getPosition().asRotationVec3(), MWBase::RotationFlag_none); } } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 41cf3beed5..718b4d972d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1397,6 +1397,7 @@ namespace MWClass // Reset to original position MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().asVec3()); + MWBase::Environment::get().getWorld()->rotateObject(ptr, ptr.getCellRef().getPosition().asRotationVec3(), MWBase::RotationFlag_none); } } } From d4e26746a32404d620c8e847335ba096668fee17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Mocquillon?= Date: Mon, 6 Sep 2021 21:56:32 +0200 Subject: [PATCH 51/59] Use recurse subdirectory iterator to iterate over the VFS without exposing internal details --- apps/niftest/niftest.cpp | 5 +-- apps/opencs/model/world/resources.cpp | 4 +- apps/openmw/mwgui/loadingscreen.cpp | 23 ++++------ apps/openmw/mwrender/animation.cpp | 36 ++++------------ apps/openmw/mwsound/soundmanagerimp.cpp | 18 ++------ components/fontloader/fontloader.cpp | 18 ++------ components/vfs/manager.cpp | 10 ++--- components/vfs/manager.hpp | 56 +++++++++++++++++++++++-- 8 files changed, 82 insertions(+), 88 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 2e81885c75..cb6205ef5c 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -52,11 +52,8 @@ void readVFS(VFS::Archive* anArchive,std::string archivePath = "") myManager.addArchive(anArchive); myManager.buildIndex(); - std::map files=myManager.getIndex(); - for(auto it=files.begin(); it!=files.end(); ++it) + for(const auto& name : myManager.getRecursiveDirectoryIterator("")) { - std::string name = it->first; - try{ if(isNIF(name)) { diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 2544886f3e..cd9f58e848 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -23,10 +23,8 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char * const * size_t baseSize = mBaseDirectory.size(); - const std::map& index = vfs->getIndex(); - for (std::map::const_iterator it = index.begin(); it != index.end(); ++it) + for (const auto& filepath : vfs->getRecursiveDirectoryIterator("")) { - std::string filepath = it->first; if (filepath.size()& index = mResourceSystem->getVFS()->getIndex(); std::string pattern = "Splash/"; mResourceSystem->getVFS()->normalizeFilename(pattern); /* priority given to the left */ const std::array supported_extensions {{".tga", ".dds", ".ktx", ".png", ".bmp", ".jpeg", ".jpg"}}; - auto found = index.lower_bound(pattern); - while (found != index.end()) + for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(pattern)) { - const std::string& name = found->first; - if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos) { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos) + for (auto const& extension : supported_extensions) { - for(auto const& extension: supported_extensions) + if (name.compare(pos, name.size() - pos, extension) == 0) { - if (name.compare(pos, name.size() - pos, extension) == 0) - { - mSplashScreens.push_back(found->first); - break; /* based on priority */ - } + mSplashScreens.push_back(name); + break; /* based on priority */ } } } - else - break; - ++found; } if (mSplashScreens.empty()) Log(Debug::Warning) << "Warning: no splash screens found!"; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a04724c70a..4eafd05f5f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -591,8 +591,6 @@ namespace MWRender void Animation::loadAllAnimationsInFolder(const std::string &model, const std::string &baseModel) { - const std::map& index = mResourceSystem->getVFS()->getIndex(); - std::string animationPath = model; if (animationPath.find("meshes") == 0) { @@ -602,19 +600,11 @@ namespace MWRender mResourceSystem->getVFS()->normalizeFilename(animationPath); - std::map::const_iterator found = index.lower_bound(animationPath); - while (found != index.end()) + for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { - const std::string& name = found->first; - if (name.size() >= animationPath.size() && name.substr(0, animationPath.size()) == animationPath) - { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".kf") == 0) - addSingleAnimSource(name, baseModel); - } - else - break; - ++found; + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".kf") == 0) + addSingleAnimSource(name, baseModel); } } @@ -1295,8 +1285,6 @@ namespace MWRender if (model.empty()) return; - const std::map& index = resourceSystem->getVFS()->getIndex(); - std::string animationPath = model; if (animationPath.find("meshes") == 0) { @@ -1306,19 +1294,11 @@ namespace MWRender resourceSystem->getVFS()->normalizeFilename(animationPath); - std::map::const_iterator found = index.lower_bound(animationPath); - while (found != index.end()) + for (const auto& name : resourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { - const std::string& name = found->first; - if (name.size() >= animationPath.size() && name.substr(0, animationPath.size()) == animationPath) - { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".nif") == 0) - loadBonesFromFile(node, name, resourceSystem); - } - else - break; - ++found; + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".nif") == 0) + loadBonesFromFile(node, name, resourceSystem); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index fc9735d576..f5c3231c99 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -294,20 +294,12 @@ namespace MWSound if (mMusicFiles.find(playlist) == mMusicFiles.end()) { std::vector filelist; - const std::map& index = mVFS->getIndex(); std::string pattern = "Music/" + playlist; mVFS->normalizeFilename(pattern); - std::map::const_iterator found = index.lower_bound(pattern); - while (found != index.end()) - { - if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) - filelist.push_back(found->first); - else - break; - ++found; - } + for (const auto& name : mVFS->getRecursiveDirectoryIterator(pattern)) + filelist.push_back(name); mMusicFiles[playlist] = filelist; } @@ -327,13 +319,11 @@ namespace MWSound if (mMusicFiles.find("Title") == mMusicFiles.end()) { std::vector filelist; - const std::map& index = mVFS->getIndex(); // Is there an ini setting for this filename or something? std::string filename = "music/special/morrowind title.mp3"; - auto found = index.find(filename); - if (found != index.end()) + if (mVFS->exists(filename)) { - filelist.emplace_back(found->first); + filelist.emplace_back(filename); mMusicFiles["Title"] = filelist; } else diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 487b7bd70b..998e9c0c64 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -191,24 +191,14 @@ namespace Gui void FontLoader::loadBitmapFonts(bool exportToFile) { - const std::map& index = mVFS->getIndex(); - std::string pattern = "Fonts/"; mVFS->normalizeFilename(pattern); - std::map::const_iterator found = index.lower_bound(pattern); - while (found != index.end()) + for (const auto& name : mVFS->getRecursiveDirectoryIterator(pattern)) { - const std::string& name = found->first; - if (name.size() >= pattern.size() && name.substr(0, pattern.size()) == pattern) - { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".fnt") == 0) - loadBitmapFont(name, exportToFile); - } - else - break; - ++found; + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".fnt") == 0) + loadBitmapFont(name, exportToFile); } } diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 045fe3cf5c..f799719e31 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -86,11 +86,6 @@ namespace VFS return mIndex.find(normalized) != mIndex.end(); } - const std::map& Manager::getIndex() const - { - return mIndex; - } - void Manager::normalizeFilename(std::string &name) const { normalize_path(name, mStrict); @@ -107,4 +102,9 @@ namespace VFS } return {}; } + + RecursiveDirectoryIterator Manager::getRecursiveDirectoryIterator(const std::string& path) const + { + return RecursiveDirectoryIterator(mIndex, path); + } } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 5a09a995eb..8656f3bf10 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -12,6 +12,51 @@ namespace VFS class Archive; class File; + class RecursiveDirectoryIterator; + RecursiveDirectoryIterator end(const RecursiveDirectoryIterator& iter); + + class RecursiveDirectoryIterator + { + public: + RecursiveDirectoryIterator(const std::map& index, const std::string& path) + : mPath(path) + , mIndex(&index) + , mIt(index.lower_bound(path)) + {} + + RecursiveDirectoryIterator(const RecursiveDirectoryIterator&) = default; + + const std::string& operator*() const { return mIt->first; } + const std::string* operator->() const { return &mIt->first; } + + bool operator!=(const RecursiveDirectoryIterator& other) { return mPath != other.mPath || mIt != other.mIt; } + + RecursiveDirectoryIterator& operator++() + { + if (++mIt == mIndex->end() || !starts_with(mIt->first, mPath)) + *this = end(*this); + return *this; + } + + friend RecursiveDirectoryIterator end(const RecursiveDirectoryIterator& iter); + + private: + static bool starts_with(const std::string& text, const std::string& start) { return text.rfind(start, 0) == 0; } + + std::string mPath; + const std::map* mIndex; + std::map::const_iterator mIt; + }; + + inline RecursiveDirectoryIterator begin(RecursiveDirectoryIterator iter) { return iter; } + + inline RecursiveDirectoryIterator end(const RecursiveDirectoryIterator& iter) + { + RecursiveDirectoryIterator result(iter); + result.mIt = result.mIndex->end(); + return result; + } + /// @brief The main class responsible for loading files from a virtual file system. /// @par Various archive types (e.g. directories on the filesystem, or compressed archives) /// can be registered, and will be merged into a single file tree. If the same filename is @@ -40,10 +85,6 @@ namespace VFS /// @note May be called from any thread once the index has been built. bool exists(const std::string& name) const; - /// Get a complete list of files from all archives - /// @note May be called from any thread once the index has been built. - const std::map& getIndex() const; - /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. /// @note May be called from any thread once the index has been built. void normalizeFilename(std::string& name) const; @@ -59,6 +100,13 @@ namespace VFS Files::IStreamPtr getNormalized(const std::string& normalizedName) const; std::string getArchive(const std::string& name) const; + + /// Recursivly iterate over the elements of the given path + /// In practice it return all files of the VFS starting with the given path + /// @note the path is normalized + /// @note May be called from any thread once the index has been built. + RecursiveDirectoryIterator getRecursiveDirectoryIterator(const std::string& path) const; + private: bool mStrict; From c2df0949e2d739830bf3c3838f644cfdd9bb3371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Mocquillon?= Date: Mon, 6 Sep 2021 22:01:41 +0200 Subject: [PATCH 52/59] Change normalizeFilename signature --- apps/openmw/mwgui/loadingscreen.cpp | 5 +---- apps/openmw/mwrender/animation.cpp | 4 ---- apps/openmw/mwsound/sound_buffer.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 15 +++------------ components/fontloader/fontloader.cpp | 5 +---- components/resource/bulletshapemanager.cpp | 9 +++------ components/resource/imagemanager.cpp | 3 +-- components/resource/keyframemanager.cpp | 3 +-- components/resource/scenemanager.cpp | 14 ++++---------- components/vfs/manager.cpp | 8 +++++--- components/vfs/manager.hpp | 2 +- 11 files changed, 21 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 2d65e4e508..7f454925fd 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -66,13 +66,10 @@ namespace MWGui void LoadingScreen::findSplashScreens() { - std::string pattern = "Splash/"; - mResourceSystem->getVFS()->normalizeFilename(pattern); - /* priority given to the left */ const std::array supported_extensions {{".tga", ".dds", ".ktx", ".png", ".bmp", ".jpeg", ".jpg"}}; - for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(pattern)) + for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator("Splash/")) { size_t pos = name.find_last_of('.'); if (pos != std::string::npos) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4eafd05f5f..3df902e469 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -598,8 +598,6 @@ namespace MWRender } animationPath.replace(animationPath.size()-3, 3, "/"); - mResourceSystem->getVFS()->normalizeFilename(animationPath); - for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { size_t pos = name.find_last_of('.'); @@ -1292,8 +1290,6 @@ namespace MWRender } animationPath.replace(animationPath.size()-4, 4, "/"); - resourceSystem->getVFS()->normalizeFilename(animationPath); - for (const auto& name : resourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { size_t pos = name.find_last_of('.'); diff --git a/apps/openmw/mwsound/sound_buffer.cpp b/apps/openmw/mwsound/sound_buffer.cpp index cb71cb56d2..e64e89d775 100644 --- a/apps/openmw/mwsound/sound_buffer.cpp +++ b/apps/openmw/mwsound/sound_buffer.cpp @@ -131,7 +131,7 @@ namespace MWSound max = std::max(min, max); Sound_Buffer& sfx = mSoundBuffers.emplace_back("Sound/" + sound.mSound, volume, min, max); - mVfs->normalizeFilename(sfx.mResourceName); + sfx.mResourceName = mVfs->normalizeFilename(sfx.mResourceName); mBufferNameMap.emplace(soundId, &sfx); return &sfx; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f5c3231c99..d2422870d7 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -295,10 +295,7 @@ namespace MWSound { std::vector filelist; - std::string pattern = "Music/" + playlist; - mVFS->normalizeFilename(pattern); - - for (const auto& name : mVFS->getRecursiveDirectoryIterator(pattern)) + for (const auto& name : mVFS->getRecursiveDirectoryIterator("Music/" + playlist)) filelist.push_back(name); mMusicFiles[playlist] = filelist; @@ -345,10 +342,7 @@ namespace MWSound if(!mOutput->isInitialized()) return; - std::string voicefile = "Sound/"+filename; - - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); if (!decoder) return; @@ -379,10 +373,7 @@ namespace MWSound if(!mOutput->isInitialized()) return; - std::string voicefile = "Sound/"+filename; - - mVFS->normalizeFilename(voicefile); - DecoderPtr decoder = loadVoice(voicefile); + DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); if (!decoder) return; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 998e9c0c64..9ba62f7694 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -191,10 +191,7 @@ namespace Gui void FontLoader::loadBitmapFonts(bool exportToFile) { - std::string pattern = "Fonts/"; - mVFS->normalizeFilename(pattern); - - for (const auto& name : mVFS->getRecursiveDirectoryIterator(pattern)) + for (const auto& name : mVFS->getRecursiveDirectoryIterator("Fonts/")) { size_t pos = name.find_last_of('.'); if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".fnt") == 0) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index b1b0f74176..98878df152 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -121,8 +121,7 @@ BulletShapeManager::~BulletShapeManager() osg::ref_ptr BulletShapeManager::getShape(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr shape; osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); @@ -180,8 +179,7 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & osg::ref_ptr BulletShapeManager::cacheInstance(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr instance = createInstance(normalized); if (instance) @@ -191,8 +189,7 @@ osg::ref_ptr BulletShapeManager::cacheInstance(const std::s osg::ref_ptr BulletShapeManager::getInstance(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr obj = mInstanceCache->takeFromObjectCache(normalized); if (obj.get()) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 37e76359ff..ba46b5cce9 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -83,8 +83,7 @@ namespace Resource osg::ref_ptr ImageManager::getImage(const std::string &filename) { - std::string normalized = filename; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(filename); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 444d2bd7aa..6d431fb3a5 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -133,8 +133,7 @@ namespace Resource osg::ref_ptr KeyframeManager::get(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 33a9ab99a1..ec6bea02d7 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -358,10 +358,7 @@ namespace Resource bool SceneManager::checkLoaded(const std::string &name, double timeStamp) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); - - return mCache->checkInObjectCache(normalized, timeStamp); + return mCache->checkInObjectCache(mVFS->normalizeFilename(name), timeStamp); } /// @brief Callback to read image files from the VFS. @@ -533,8 +530,7 @@ namespace Resource osg::ref_ptr SceneManager::getTemplate(const std::string &name, bool compile) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) @@ -603,8 +599,7 @@ namespace Resource osg::ref_ptr SceneManager::cacheInstance(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr node = createInstance(normalized); @@ -642,8 +637,7 @@ namespace Resource osg::ref_ptr SceneManager::getInstance(const std::string &name) { - std::string normalized = name; - mVFS->normalizeFilename(normalized); + const std::string normalized = mVFS->normalizeFilename(name); osg::ref_ptr obj = mInstanceCache->takeFromObjectCache(normalized); if (obj.get()) diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index f799719e31..1cb8745497 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -86,9 +86,11 @@ namespace VFS return mIndex.find(normalized) != mIndex.end(); } - void Manager::normalizeFilename(std::string &name) const + std::string Manager::normalizeFilename(const std::string& name) const { - normalize_path(name, mStrict); + std::string result = name; + normalize_path(result, mStrict); + return result; } std::string Manager::getArchive(const std::string& name) const @@ -105,6 +107,6 @@ namespace VFS RecursiveDirectoryIterator Manager::getRecursiveDirectoryIterator(const std::string& path) const { - return RecursiveDirectoryIterator(mIndex, path); + return RecursiveDirectoryIterator(mIndex, normalizeFilename(path)); } } diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 8656f3bf10..b98d8021d4 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -87,7 +87,7 @@ namespace VFS /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. /// @note May be called from any thread once the index has been built. - void normalizeFilename(std::string& name) const; + [[nodiscard]] std::string normalizeFilename(const std::string& name) const; /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. From 681728209735520de5daf3657cc5c754783c5028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Mocquillon?= Date: Sat, 11 Sep 2021 15:49:47 +0200 Subject: [PATCH 53/59] Move getFileExtension to common header and use instead of repeating same code --- apps/openmw/mwgui/loadingscreen.cpp | 21 +++++++-------------- apps/openmw/mwrender/animation.cpp | 7 +++---- components/fontloader/fontloader.cpp | 4 ++-- components/misc/pathhelpers.hpp | 19 +++++++++++++++++++ components/resource/bulletshapemanager.cpp | 8 ++------ components/resource/imagemanager.cpp | 6 ++---- components/resource/keyframemanager.cpp | 4 ++-- components/resource/scenemanager.cpp | 13 +++---------- 8 files changed, 40 insertions(+), 42 deletions(-) create mode 100644 components/misc/pathhelpers.hpp diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7f454925fd..ef8eea0104 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -66,23 +67,15 @@ namespace MWGui void LoadingScreen::findSplashScreens() { - /* priority given to the left */ - const std::array supported_extensions {{".tga", ".dds", ".ktx", ".png", ".bmp", ".jpeg", ".jpg"}}; + auto isSupportedExtension = [](const std::string_view& ext) { + static const std::array supported_extensions{ {"tga", "dds", "ktx", "png", "bmp", "jpeg", "jpg"} }; + return !ext.empty() && std::find(supported_extensions.begin(), supported_extensions.end(), ext) != supported_extensions.end(); + }; for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator("Splash/")) { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos) - { - for (auto const& extension : supported_extensions) - { - if (name.compare(pos, name.size() - pos, extension) == 0) - { - mSplashScreens.push_back(name); - break; /* based on priority */ - } - } - } + if (isSupportedExtension(Misc::getFileExtension(name))) + mSplashScreens.push_back(name); } if (mSplashScreens.empty()) Log(Debug::Warning) << "Warning: no splash screens found!"; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3df902e469..1dc42db47c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -600,8 +601,7 @@ namespace MWRender for (const auto& name : mResourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".kf") == 0) + if (Misc::getFileExtension(name) == "kf") addSingleAnimSource(name, baseModel); } } @@ -1292,8 +1292,7 @@ namespace MWRender for (const auto& name : resourceSystem->getVFS()->getRecursiveDirectoryIterator(animationPath)) { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".nif") == 0) + if (Misc::getFileExtension(name) == "nif") loadBonesFromFile(node, name, resourceSystem); } } diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 9ba62f7694..da43cc38ec 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -17,6 +17,7 @@ #include +#include #include #include @@ -193,8 +194,7 @@ namespace Gui { for (const auto& name : mVFS->getRecursiveDirectoryIterator("Fonts/")) { - size_t pos = name.find_last_of('.'); - if (pos != std::string::npos && name.compare(pos, name.size() - pos, ".fnt") == 0) + if (Misc::getFileExtension(name) == "fnt") loadBitmapFont(name, exportToFile); } } diff --git a/components/misc/pathhelpers.hpp b/components/misc/pathhelpers.hpp new file mode 100644 index 0000000000..88913a1f7b --- /dev/null +++ b/components/misc/pathhelpers.hpp @@ -0,0 +1,19 @@ +#ifndef OPENMW_COMPONENTS_MISC_PATHHELPERS_H +#define OPENMW_COMPONENTS_MISC_PATHHELPERS_H + +#include + +namespace Misc +{ + inline std::string_view getFileExtension(std::string_view file) + { + if (auto extPos = file.find_last_of('.'); extPos != std::string::npos) + { + file.remove_prefix(extPos + 1); + return file; + } + return {}; + } +} + +#endif diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index 98878df152..0d0f81962b 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -129,12 +130,7 @@ osg::ref_ptr BulletShapeManager::getShape(const std::string & shape = osg::ref_ptr(static_cast(obj.get())); else { - size_t extPos = normalized.find_last_of('.'); - std::string ext; - if (extPos != std::string::npos && extPos+1 < normalized.size()) - ext = normalized.substr(extPos+1); - - if (ext == "nif") + if (Misc::getFileExtension(normalized) == "nif") { NifBullet::BulletNifLoader loader; shape = loader.load(*mNifFileManager->get(normalized)); diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index ba46b5cce9..a544b7b621 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "objectcache.hpp" @@ -102,10 +103,7 @@ namespace Resource return mWarningImage; } - size_t extPos = normalized.find_last_of('.'); - std::string ext; - if (extPos != std::string::npos && extPos+1 < normalized.size()) - ext = normalized.substr(extPos+1); + const std::string ext(Misc::getFileExtension(normalized)); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); if (!reader) { diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 6d431fb3a5..01a8639aa2 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "animation.hpp" @@ -141,8 +142,7 @@ namespace Resource else { osg::ref_ptr loaded (new SceneUtil::KeyframeHolder); - std::string ext = Resource::getFileExtension(normalized); - if (ext == "kf") + if (Misc::getFileExtension(normalized) == "kf") { NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index ec6bea02d7..76e73da384 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -388,12 +389,12 @@ namespace Resource osg::ref_ptr load (const std::string& normalizedFilename, const VFS::Manager* vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) { - std::string ext = Resource::getFileExtension(normalizedFilename); + auto ext = Misc::getFileExtension(normalizedFilename); if (ext == "nif") return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), imageManager); else { - osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(ext); + osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension(std::string(ext)); if (!reader) { std::stringstream errormsg; @@ -816,12 +817,4 @@ namespace Resource shaderVisitor->setTranslucentFramebuffer(translucentFramebuffer); return shaderVisitor; } - - std::string getFileExtension(const std::string& file) - { - size_t extPos = file.find_last_of('.'); - if (extPos != std::string::npos && extPos+1 < file.size()) - return file.substr(extPos+1); - return std::string(); - } } From dd6649d519939b157d2f9b2089aa0c1defc2f356 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Tue, 14 Sep 2021 22:59:04 +0200 Subject: [PATCH 54/59] Create cmake.yml (#3107) * Create cmake.yml * Update cmake.yml * Update cmake.yml * Update cmake.yml * Update cmake.yml --- .github/workflows/cmake.yml | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/cmake.yml diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000000..18221b3cb6 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,53 @@ +name: CMake + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + BUILD_TYPE: RelWithDebInfo + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Add OpenMW PPA Dependancies + run: sudo add-apt-repository ppa:openmw/openmw; sudo apt-get update + + - name: Install Building Dependancies + run: sudo CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic + + - name: Configure CMake + run: | + mkdir build + mkdir instdir + cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX:PATH=instdir + + - name: Build + run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3 + + - name: Test + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} + + - name: Install OpenMW + shell: bash + run: cmake --install . + + - name: Upload OpenMW Artifact + shell: bash + working-directory: instdir + run: | + ls -laR + 7z a ../build_artifact.7z . + + - name: Upload + uses: actions/upload-artifact@v1 + with: + path: ./build_artifact.7z + name: build_artifact.7z From c658acc2b311bb6676597845fe4464d2409314c4 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 15 Sep 2021 16:50:19 +0200 Subject: [PATCH 55/59] pipeline only on pull_requests (#3109) * Create debs * Update cmake.yml * give ccache a try * ccache round 2 * Update cmake.yml --- .github/workflows/cmake.yml | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 18221b3cb6..c220030050 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -1,8 +1,6 @@ name: CMake on: - push: - branches: [ master ] pull_request: branches: [ master ] @@ -22,31 +20,30 @@ jobs: - name: Install Building Dependancies run: sudo CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic - - name: Configure CMake - run: | - mkdir build - mkdir instdir - cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX:PATH=instdir + - name: Prime ccache + uses: hendrikmuhs/ccache-action@v1 + with: + key: ${{ matrix.os }}-${{ env.BUILD_TYPE }} + max-size: 1000M - - name: Build + - name: Configure + run: cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + - name: Buil run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3 - - - name: Test - working-directory: ${{github.workspace}}/build - run: ctest -C ${{env.BUILD_TYPE}} - - name: Install OpenMW + - name: Install shell: bash run: cmake --install . - - name: Upload OpenMW Artifact + - name: Create Artifact shell: bash - working-directory: instdir + working-directory: install run: | ls -laR 7z a ../build_artifact.7z . - - name: Upload + - name: Upload Artifact uses: actions/upload-artifact@v1 with: path: ./build_artifact.7z From f62adab43a821a75beb9eed0f68ae7af82af81ce Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Thu, 16 Sep 2021 20:11:19 +0000 Subject: [PATCH 56/59] Avoid the terrain sync completely in most cases (#3103) We can take elsid's commit 605cb8d further by avoiding the terrain sync completely in most cases. Currently in changeCellGrid we wait for a new preloading task to ensure the getPagedRefnums for the new active cells have been filled in by object paging. This is usually not necessary because we have already completed a preload in the past containing these active cells. With this PR we remember what we preloaded and skip the terrain sync if it is not needed. --- apps/openmw/mwworld/cellpreloader.cpp | 60 ++++++++++++++++--------- apps/openmw/mwworld/cellpreloader.hpp | 4 ++ apps/openmw/mwworld/scene.cpp | 10 ++--- components/resource/resourcemanager.hpp | 1 + 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index c29d975c24..f2f2ebc5a6 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -21,6 +21,29 @@ #include "cellstore.hpp" #include "class.hpp" +namespace +{ + template + bool contains(const std::vector& container, + const Contained& contained, float tolerance=1.f) + { + for (const auto& pos : contained) + { + bool found = false; + for (const auto& pos2 : container) + { + if ((pos.first-pos2.first).length2() < tolerance*tolerance && pos.second == pos2.second) + { + found = true; + break; + } + } + if (!found) return false; + } + return true; + } +} + namespace MWWorld { @@ -224,6 +247,7 @@ namespace MWWorld , mPreloadInstances(true) , mLastResourceCacheUpdate(0.0) , mStoreViewsFailCount(0) + , mLoadedTerrainTimestamp(0.0) { } @@ -369,7 +393,11 @@ namespace MWWorld setTerrainPreloadPositions(std::vector()); } else + { mStoreViewsFailCount = 0; + mLoadedTerrainPositions = mTerrainPreloadPositions; + mLoadedTerrainTimestamp = timestamp; + } mTerrainPreloadItem = nullptr; } } @@ -436,10 +464,8 @@ namespace MWWorld void CellPreloader::abortTerrainPreloadExcept(const CellPreloader::PositionCellGrid *exceptPos) { - const float resetThreshold = ESM::Land::REAL_SIZE; - for (const auto& pos : mTerrainPreloadPositions) - if (exceptPos && (pos.first-exceptPos->first).length2() < resetThreshold*resetThreshold && pos.second == exceptPos->second) - return; + if (exceptPos && contains(mTerrainPreloadPositions, std::array {*exceptPos}, ESM::Land::REAL_SIZE)) + return; if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone()) { mTerrainPreloadItem->abort(); @@ -448,28 +474,13 @@ namespace MWWorld setTerrainPreloadPositions(std::vector()); } - bool contains(const std::vector& container, const std::vector& contained) - { - for (const auto& pos : contained) - { - bool found = false; - for (const auto& pos2 : container) - { - if ((pos.first-pos2.first).length2() < 1 && pos.second == pos2.second) - { - found = true; - break; - } - } - if (!found) return false; - } - return true; - } - void CellPreloader::setTerrainPreloadPositions(const std::vector &positions) { if (positions.empty()) + { mTerrainPreloadPositions.clear(); + mLoadedTerrainPositions.clear(); + } else if (contains(mTerrainPreloadPositions, positions)) return; if (mTerrainPreloadItem && !mTerrainPreloadItem->isDone()) @@ -496,5 +507,10 @@ namespace MWWorld } } } + + bool CellPreloader::isTerrainLoaded(const CellPreloader::PositionCellGrid &position, double referenceTime) const + { + return mLoadedTerrainTimestamp + mResourceSystem->getSceneManager()->getExpiryDelay() > referenceTime && contains(mLoadedTerrainPositions, std::array {position}, ESM::Land::REAL_SIZE); + } } diff --git a/apps/openmw/mwworld/cellpreloader.hpp b/apps/openmw/mwworld/cellpreloader.hpp index e2eea33146..39436dc5ad 100644 --- a/apps/openmw/mwworld/cellpreloader.hpp +++ b/apps/openmw/mwworld/cellpreloader.hpp @@ -79,6 +79,7 @@ namespace MWWorld bool syncTerrainLoad(const std::vector &positions, double timestamp, Loading::Listener& listener); void abortTerrainPreloadExcept(const PositionCellGrid *exceptPos); + bool isTerrainLoaded(const CellPreloader::PositionCellGrid &position, double referenceTime) const; private: Resource::ResourceSystem* mResourceSystem; @@ -119,6 +120,9 @@ namespace MWWorld std::vector mTerrainPreloadPositions; osg::ref_ptr mTerrainPreloadItem; osg::ref_ptr mUpdateCacheItem; + + std::vector mLoadedTerrainPositions; + double mLoadedTerrainTimestamp; }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 399d0e6d7f..89349d329a 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -628,7 +628,10 @@ namespace MWWorld osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter); mRendering.setActiveGrid(newGrid); - preloadTerrain(pos, true); + if (mRendering.pagingUnlockCache()) + mPreloader->abortTerrainPreloadExcept(nullptr); + if (!mPreloader->isTerrainLoaded(std::make_pair(pos, newGrid), mRendering.getReferenceTime())) + preloadTerrain(pos, true); mPagedRefs.clear(); mRendering.getPagedRefnums(newGrid, mPagedRefs); @@ -1241,10 +1244,7 @@ namespace MWWorld { std::vector vec; vec.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos))); - if (sync && mRendering.pagingUnlockCache()) - mPreloader->abortTerrainPreloadExcept(nullptr); - else - mPreloader->abortTerrainPreloadExcept(&vec[0]); + mPreloader->abortTerrainPreloadExcept(&vec[0]); mPreloader->setTerrainPreloadPositions(vec); if (!sync) return; diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index ccb065e3bf..b2b71f4635 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -59,6 +59,7 @@ namespace Resource /// How long to keep objects in cache after no longer being referenced. void setExpiryDelay (double expiryDelay) override { mExpiryDelay = expiryDelay; } + float getExpiryDelay() const { return mExpiryDelay; } const VFS::Manager* getVFS() const { return mVFS; } From 4ff5a04e9b3470847dd77efe3261e43c047c2b4f Mon Sep 17 00:00:00 2001 From: Pi03k Date: Thu, 16 Sep 2021 20:45:23 +0200 Subject: [PATCH 57/59] Remove redundant qt-related cmake macros --- apps/opencs/CMakeLists.txt | 28 ++++++++++++++-------------- cmake/OpenMWMacros.cmake | 25 ++----------------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 60bd0f4ded..0ffa3da559 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -8,11 +8,11 @@ opencs_units (model/doc document operation saving documentmanager loader runner operationholder ) -opencs_units_noqt (model/doc +opencs_units (model/doc stage savingstate savingstages blacklist messages ) -opencs_hdrs_noqt (model/doc +opencs_hdrs (model/doc state ) @@ -23,14 +23,14 @@ opencs_units (model/world ) -opencs_units_noqt (model/world +opencs_units (model/world universalid record commands columnbase columnimp scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro ) -opencs_hdrs_noqt (model/world +opencs_hdrs (model/world columnimp idcollection collection info subcellcollection ) @@ -39,14 +39,14 @@ opencs_units (model/tools tools reportmodel mergeoperation ) -opencs_units_noqt (model/tools +opencs_units (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck mergestages gmstcheck topicinfocheck journalcheck enchantmentcheck ) -opencs_hdrs_noqt (model/tools +opencs_hdrs (model/tools mergestate ) @@ -57,11 +57,11 @@ opencs_units (view/doc ) -opencs_units_noqt (view/doc +opencs_units (view/doc subviewfactory ) -opencs_hdrs_noqt (view/doc +opencs_hdrs (view/doc subviewfactoryimp ) @@ -74,7 +74,7 @@ opencs_units (view/world bodypartcreator landtexturecreator landcreator ) -opencs_units_noqt (view/world +opencs_units (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate scripthighlighter idvalidator dialoguecreator idcompletiondelegate colordelegate dragdroputils @@ -92,12 +92,12 @@ opencs_units (view/render cellwater terraintexturemode actor terrainselection terrainshapemode brushdraw commands ) -opencs_units_noqt (view/render +opencs_units (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase cellarrow cellmarker cellborder pathgrid ) -opencs_hdrs_noqt (view/render +opencs_hdrs (view/render mask ) @@ -106,7 +106,7 @@ opencs_units (view/tools reportsubview reporttable searchsubview searchbox merge ) -opencs_units_noqt (view/tools +opencs_units (view/tools subviews ) @@ -119,11 +119,11 @@ opencs_units (model/prefs shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting ) -opencs_units_noqt (model/prefs +opencs_units (model/prefs category ) -opencs_units_noqt (model/filter +opencs_units (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 5bee345344..0adc185b38 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -93,42 +93,21 @@ add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") endmacro (add_unit) -macro (add_qt_unit project dir unit) -add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") -add_file (${project} _SRC ${comp} "${dir}/${unit}.cpp") -endmacro (add_qt_unit) - macro (add_hdr project dir unit) add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") endmacro (add_hdr) -macro (add_qt_hdr project dir unit) -add_file (${project} _HDR ${comp} "${dir}/${unit}.hpp") -endmacro (add_qt_hdr) - macro (opencs_units dir) foreach (u ${ARGN}) -add_qt_unit (OPENCS ${dir} ${u}) -endforeach (u) -endmacro (opencs_units) - -macro (opencs_units_noqt dir) -foreach (u ${ARGN}) add_unit (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_units_noqt) +endmacro (opencs_units) macro (opencs_hdrs dir) foreach (u ${ARGN}) -add_qt_hdr (OPENCS ${dir} ${u}) -endforeach (u) -endmacro (opencs_hdrs) - -macro (opencs_hdrs_noqt dir) -foreach (u ${ARGN}) add_hdr (OPENCS ${dir} ${u}) endforeach (u) -endmacro (opencs_hdrs_noqt) +endmacro (opencs_hdrs) include(CMakeParseArguments) From e4648cec48ba9b28e8907b23ffa68d63c9f1e6e8 Mon Sep 17 00:00:00 2001 From: Bo Svensson <90132211+bosvensson1@users.noreply.github.com> Date: Fri, 17 Sep 2021 17:24:11 +0000 Subject: [PATCH 58/59] kill buil (#3118) He was a great fellow. We will forever be in debt for his services. Time to say good-bye. --- .github/workflows/cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index c220030050..f9375a3ba5 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -29,7 +29,7 @@ jobs: - name: Configure run: cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache - - name: Buil + - name: Build run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3 - name: Install From b9825afb8a8c97085560f58febd2a9175a14971b Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 2 Sep 2021 01:06:27 +0200 Subject: [PATCH 59/59] Fix build with system static OpenSceneGraph * Add dependency to libraries required by OSG but missing when linking with OSG system library. * Use find_package for already defined dependencies. --- CMakeLists.txt | 5 +++++ components/CMakeLists.txt | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d14762ef5f..1b8350a04b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,11 @@ if(POLICY CMP0083) cmake_policy(SET CMP0083 NEW) endif() +# to link with freetype library +if(POLICY CMP0079) + cmake_policy(SET CMP0079 NEW) +endif() + option(OPENMW_GL4ES_MANUAL_INIT "Manually initialize gl4es. This is more reliable on platforms without a windowing system. Requires gl4es to be configured with -DNOEGL=ON -DNO_LOADER=ON -DNO_INIT_CONSTRUCTOR=ON." OFF) if(OPENMW_GL4ES_MANUAL_INIT) add_definitions(-DOPENMW_GL4ES_MANUAL_INIT) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5b79a096cd..7ee3d184d8 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -288,6 +288,15 @@ if (GIT_CHECKOUT) add_dependencies (components git-version) endif (GIT_CHECKOUT) +if (OSG_STATIC AND CMAKE_SYSTEM_NAME MATCHES "Linux") + find_package(X11 REQUIRED COMPONENTS Xinerama Xrandr) + target_link_libraries(components ${CMAKE_DL_LIBS} X11::X11 X11::Xinerama X11::Xrandr) + find_package(Fontconfig MODULE) + if(Fontconfig_FOUND) + target_link_libraries(components Fontconfig::Fontconfig) + endif() +endif() + if (WIN32) target_link_libraries(components shlwapi) endif() @@ -329,7 +338,10 @@ if(OSG_STATIC) if(OPENMW_USE_SYSTEM_OSG) # OSG plugin pkgconfig files are missing these dependencies. # https://github.com/openscenegraph/OpenSceneGraph/issues/1052 - target_link_libraries(components freetype jpeg png) + find_package(Freetype REQUIRED) + find_package(JPEG REQUIRED) + find_package(PNG REQUIRED) + target_link_libraries(components Freetype::Freetype JPEG::JPEG PNG::PNG) endif() endif(OSG_STATIC)