1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-01 06:39:43 +00:00

can actually load and teleport to esm4 exterior spaces

This commit is contained in:
florent.teppe 2023-04-24 21:20:07 +02:00
parent eb48f8724f
commit d8a782425b
12 changed files with 40 additions and 25 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -18,8 +18,11 @@ namespace MWRender
mCache = new CacheType;
}
osg::ref_ptr<ESMTerrain::LandObject> LandManager::getLand(int x, int y)
osg::ref_ptr<ESMTerrain::LandObject> LandManager::getLand(int x, int y, ESM::RefId worldspace)
{
if (worldspace != ESM::Cell::sDefaultWorldspaceId)
return osg::ref_ptr<ESMTerrain::LandObject>(nullptr);
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(std::make_pair(x, y));
if (obj)
return static_cast<ESMTerrain::LandObject*>(obj.get());

View file

@ -20,7 +20,7 @@ namespace MWRender
LandManager(int loadFlags);
/// @note Will return nullptr if not found.
osg::ref_ptr<ESMTerrain::LandObject> getLand(int x, int y);
osg::ref_ptr<ESMTerrain::LandObject> getLand(int x, int y, ESM::RefId worldspace);
void reportStats(unsigned int frameNumber, osg::Stats* stats) const override;

View file

@ -68,7 +68,7 @@ namespace MWRender
osg::ref_ptr<const ESMTerrain::LandObject> 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)

View file

@ -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&)
{

View file

@ -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<int>(std::floor(x / Constants::CellSizeInUnits)),
static_cast<int>(std::floor(y / Constants::CellSizeInUnits)) };
const float cellSize = esm4Ext ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits;
return { static_cast<int>(std::floor(x / cellSize)), static_cast<int>(std::floor(y / cellSize)) };
}
}

View file

@ -13,6 +13,7 @@
#include <components/detournavigator/navigator.hpp>
#include <components/detournavigator/updateguard.hpp>
#include <components/esm/records.hpp>
#include <components/esm3/loadcell.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/convert.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -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<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
osg::ref_ptr<const ESMTerrain::LandObject> 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());

View file

@ -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<float>(cellSize * cellX);
y = static_cast<float>(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;

View file

@ -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;

View file

@ -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;