diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 71bb85c798..e0d64fba9f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -316,7 +316,8 @@ namespace MWBase /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is /// obstructed). - virtual void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const = 0; + virtual void indexToPosition( + int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const = 0; ///< Convert cell numbers to position. virtual void queueMovement(const MWWorld::Ptr& ptr, const osg::Vec3f& velocity) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d2076a6280..5f4c09842a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -483,8 +483,10 @@ namespace MWPhysics mHeightFields.erase(heightfield); } - const HeightField* PhysicsSystem::getHeightField(int x, int y) const + const HeightField* PhysicsSystem::getHeightField(int x, int y, ESM::RefId worldspace) const { + if (worldspace != ESM::Cell::sDefaultWorldspaceId) + return nullptr; const auto heightField = mHeightFields.find(std::make_pair(x, y)); if (heightField == mHeightFields.end()) return nullptr; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 923ace45bb..d61b0f38d9 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -189,7 +189,7 @@ namespace MWPhysics void removeHeightField(int x, int y); - const HeightField* getHeightField(int x, int y) const; + const HeightField* getHeightField(int x, int y, ESM::RefId worldspace) const; bool toggleCollisionMode(); diff --git a/apps/openmw/mwrender/landmanager.cpp b/apps/openmw/mwrender/landmanager.cpp index 59b9fdbde4..74811677a0 100644 --- a/apps/openmw/mwrender/landmanager.cpp +++ b/apps/openmw/mwrender/landmanager.cpp @@ -18,8 +18,11 @@ namespace MWRender mCache = new CacheType; } - osg::ref_ptr LandManager::getLand(int x, int y) + osg::ref_ptr LandManager::getLand(int x, int y, ESM::RefId worldspace) { + if (worldspace != ESM::Cell::sDefaultWorldspaceId) + return osg::ref_ptr(nullptr); + osg::ref_ptr obj = mCache->getRefFromObjectCache(std::make_pair(x, y)); if (obj) return static_cast(obj.get()); diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 4c00cefe9b..959647fadc 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -20,7 +20,7 @@ namespace MWRender LandManager(int loadFlags); /// @note Will return nullptr if not found. - osg::ref_ptr getLand(int x, int y); + osg::ref_ptr getLand(int x, int y, ESM::RefId worldspace); void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index c85ee62f88..e23efbd2a3 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -68,7 +68,7 @@ namespace MWRender osg::ref_ptr TerrainStorage::getLand(int cellX, int cellY) { - return mLandManager->getLand(cellX, cellY); + return mLandManager->getLand(cellX, cellY, ESM::Cell::sDefaultWorldspaceId); } const ESM::LandTexture* TerrainStorage::getLandTexture(int index, short plugin) diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index 3ba20d635e..0e2e773b74 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -102,7 +102,7 @@ namespace MWWorld try { mTerrain->cacheCell(mTerrainView.get(), mX, mY); - mPreloadedObjects.insert(mLandManager->getLand(mX, mY)); + mPreloadedObjects.insert(mLandManager->getLand(mX, mY, ESM::Cell::sDefaultWorldspaceId)); } catch (std::exception&) { diff --git a/apps/openmw/mwworld/cellutils.hpp b/apps/openmw/mwworld/cellutils.hpp index a7e8e88c78..978e358c8b 100644 --- a/apps/openmw/mwworld/cellutils.hpp +++ b/apps/openmw/mwworld/cellutils.hpp @@ -9,10 +9,10 @@ namespace MWWorld { - inline osg::Vec2i positionToCellIndex(float x, float y) + inline osg::Vec2i positionToCellIndex(float x, float y, bool esm4Ext = false) { - return { static_cast(std::floor(x / Constants::CellSizeInUnits)), - static_cast(std::floor(y / Constants::CellSizeInUnits)) }; + const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; + return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)) }; } } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d0f755fece..ec63e6429b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -247,12 +248,13 @@ namespace return std::abs(cellPosition.first) + std::abs(cellPosition.second); } - bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection) + bool isCellInCollection(int x, int y, ESM::RefId worldspace, MWWorld::Scene::CellStoreCollection& collection) { for (auto* cell : collection) { assert(cell->getCell()->isExterior()); - if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY()) + if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY() + && cell->getCell()->getWorldSpace() == worldspace) return true; } return false; @@ -346,7 +348,7 @@ namespace MWWorld if (cell->getCell()->isExterior()) { - if (mPhysics->getHeightField(cellX, cellY) != nullptr) + if (mPhysics->getHeightField(cellX, cellY, cell->getCell()->getWorldSpace()) != nullptr) mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); mPhysics->removeHeightField(cellX, cellY); @@ -391,10 +393,12 @@ namespace MWWorld const int cellX = cell.getCell()->getGridX(); const int cellY = cell.getCell()->getGridY(); const MWWorld::Cell& cellVariant = *cell.getCell(); + ESM::RefId worldspace = cellVariant.getWorldSpace(); if (cellVariant.isExterior()) { - osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); + osg::ref_ptr land + = mRendering.getLandManager()->getLand(cellX, cellY, worldspace); const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; const int verts = ESM::Land::LAND_SIZE; const int worldsize = ESM::Land::REAL_SIZE; @@ -410,7 +414,7 @@ namespace MWWorld mPhysics->addHeightField(defaultHeight.data(), cellX, cellY, worldsize, verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get()); } - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) { const osg::Vec2i cellPosition(cellX, cellY); const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin(); @@ -465,7 +469,7 @@ namespace MWWorld if (cellVariant.isExterior()) { - if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) + if (const auto heightField = mPhysics->getHeightField(cellX, cellY, worldspace)) mNavigator.addWater( osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard); } @@ -507,17 +511,18 @@ namespace MWWorld osg::Vec2i Scene::getNewGridCenter(const osg::Vec3f& pos, const osg::Vec2i* currentGridCenter) const { + bool isEsm4Ext = mCurrentCell && mCurrentCell->getCell()->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; if (currentGridCenter) { float centerX, centerY; - mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true); + mWorld.indexToPosition(currentGridCenter->x(), currentGridCenter->y(), centerX, centerY, true, isEsm4Ext); float distance = std::max(std::abs(centerX - pos.x()), std::abs(centerY - pos.y())); const float maxDistance = Constants::CellSizeInUnits / 2 + mCellLoadingThreshold; // 1/2 cell size + threshold if (distance <= maxDistance) return *currentGridCenter; } - return positionToCellIndex(pos.x(), pos.y()); + return positionToCellIndex(pos.x(), pos.y(), isEsm4Ext); } void Scene::playerMoved(const osg::Vec3f& pos) @@ -532,7 +537,8 @@ namespace MWWorld void Scene::requestChangeCellGrid(const osg::Vec3f& position, const osg::Vec2i& cell, bool changeEvent) { - mChangeCellGridRequest = ChangeCellGridRequest{ position, cell, ESM::Cell::sDefaultWorldspaceId, changeEvent }; + mChangeCellGridRequest + = ChangeCellGridRequest{ position, cell, mCurrentCell->getCell()->getWorldSpace(), changeEvent }; } void Scene::changeCellGrid( @@ -580,7 +586,7 @@ namespace MWWorld { for (int y = playerCellY - range; y <= playerCellY + range; ++y) { - if (!isCellInCollection(x, y, collection)) + if (!isCellInCollection(x, y, exteriorWorldspace, collection)) { refsToLoad += mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace).count(); cellsPositionsToLoad.emplace_back(x, y); @@ -614,7 +620,7 @@ namespace MWWorld for (const auto& [x, y] : cellsPositionsToLoad) { - if (!isCellInCollection(x, y, mActiveCells)) + if (!isCellInCollection(x, y, exteriorWorldspace, mActiveCells)) { CellStore& cell = mWorld.getWorldModel().getExterior(x, y, exteriorWorldspace); loadCell(cell, loadingListener, changeEvent, pos, navigatorUpdateGuard.get()); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8f38a9e081..ff1b7842f7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1512,9 +1512,9 @@ namespace MWWorld return placed; } - void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre) const + void World::indexToPosition(int cellX, int cellY, float& x, float& y, bool centre, bool esm4Ext) const { - const int cellSize = Constants::CellSizeInUnits; + const int cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; x = static_cast(cellSize * cellX); y = static_cast(cellSize * cellY); @@ -2766,7 +2766,8 @@ namespace MWWorld { int x = ext->getGridX(); int y = ext->getGridY(); - indexToPosition(x, y, pos.pos[0], pos.pos[1], true); + bool esm4Ext = ext->getWorldSpace() != ESM::Cell::sDefaultWorldspaceId; + indexToPosition(x, y, pos.pos[0], pos.pos[1], true, esm4Ext); // Note: Z pos will be adjusted by adjustPosition later pos.pos[2] = 0; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8e9ba5bd8..b181e6d49d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -403,7 +403,8 @@ namespace MWWorld float getMaxActivationDistance() const override; - void indexToPosition(int cellX, int cellY, float& x, float& y, bool centre = false) const override; + void indexToPosition( + int cellX, int cellY, float& x, float& y, bool centre = false, bool esm4Exterior = false) const override; ///< Convert cell numbers to position. void queueMovement(const Ptr& ptr, const osg::Vec3f& velocity) override; diff --git a/components/misc/constants.hpp b/components/misc/constants.hpp index deb47a7667..545db87094 100644 --- a/components/misc/constants.hpp +++ b/components/misc/constants.hpp @@ -23,6 +23,7 @@ namespace Constants // Size of one exterior cell in game units constexpr int CellSizeInUnits = 8192; + constexpr int ESM4CellSizeInUnits = 4096; // Size of active cell grid in cells (it is a square with the (2 * CellGridRadius + 1) cells side) constexpr int CellGridRadius = 1;