mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 03:35:27 +00:00
Some actors are supposed to spawn on a static object that belong to an adjacent cell.
Since actors can be active in 3x3 grid around the player, we need to first load all statics in a 5x5 grid around the player. Split load and unloading in 2 phases. Add an mInactiveCells set into the scene, which contains all cells inside the aforementioned 5x5 grid. These cells contains only heightfields and physics objects of static class.
This commit is contained in:
parent
165c731492
commit
f031a191b8
@ -63,4 +63,9 @@ namespace MWClass
|
|||||||
|
|
||||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Static::isStatic() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ namespace MWClass
|
|||||||
static void registerSelf();
|
static void registerSelf();
|
||||||
|
|
||||||
std::string getModel(const MWWorld::ConstPtr &ptr) const override;
|
std::string getModel(const MWWorld::ConstPtr &ptr) const override;
|
||||||
|
|
||||||
|
bool isStatic() const override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ namespace MWPhysics
|
|||||||
mAnimatedObjects.insert(obj.get());
|
mAnimatedObjects.insert(obj.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::remove(const MWWorld::Ptr &ptr)
|
void PhysicsSystem::remove(const MWWorld::Ptr &ptr, bool keepObject)
|
||||||
{
|
{
|
||||||
ObjectMap::iterator found = mObjects.find(ptr);
|
ObjectMap::iterator found = mObjects.find(ptr);
|
||||||
if (found != mObjects.end())
|
if (found != mObjects.end())
|
||||||
@ -479,6 +479,7 @@ namespace MWPhysics
|
|||||||
|
|
||||||
mAnimatedObjects.erase(found->second.get());
|
mAnimatedObjects.erase(found->second.get());
|
||||||
|
|
||||||
|
if (!keepObject)
|
||||||
mObjects.erase(found);
|
mObjects.erase(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ namespace MWPhysics
|
|||||||
Projectile* getProjectile(int projectileId) const;
|
Projectile* getProjectile(int projectileId) const;
|
||||||
|
|
||||||
// Object or Actor
|
// Object or Actor
|
||||||
void remove (const MWWorld::Ptr& ptr);
|
void remove (const MWWorld::Ptr& ptr, bool keepObject = false);
|
||||||
|
|
||||||
void updateScale (const MWWorld::Ptr& ptr);
|
void updateScale (const MWWorld::Ptr& ptr);
|
||||||
void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);
|
void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);
|
||||||
|
@ -18,12 +18,23 @@ namespace MWWorld
|
|||||||
if (ptr.getRefData().getBaseNode())
|
if (ptr.getRefData().getBaseNode())
|
||||||
{
|
{
|
||||||
ptr.getRefData().setBaseNode(nullptr);
|
ptr.getRefData().setBaseNode(nullptr);
|
||||||
mObjects.push_back (ptr);
|
|
||||||
}
|
}
|
||||||
|
mObjects.push_back (ptr);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ListObjectsVisitor
|
||||||
|
{
|
||||||
|
std::vector<MWWorld::Ptr> mObjects;
|
||||||
|
|
||||||
|
bool operator() (MWWorld::Ptr ptr)
|
||||||
|
{
|
||||||
|
mObjects.push_back (ptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -318,6 +318,10 @@ namespace MWWorld
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool isStatic() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
|
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
|
||||||
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
|
||||||
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
|
||||||
|
@ -105,7 +105,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
||||||
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs)
|
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs, bool onlyPhysics)
|
||||||
{
|
{
|
||||||
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
|
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
|
||||||
{
|
{
|
||||||
@ -113,16 +113,17 @@ namespace
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useAnim = ptr.getClass().useAnim();
|
|
||||||
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
||||||
|
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
||||||
|
if (!onlyPhysics)
|
||||||
|
{
|
||||||
|
bool useAnim = ptr.getClass().useAnim();
|
||||||
|
|
||||||
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
||||||
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
||||||
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
||||||
|
|
||||||
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
|
||||||
setNodeRotation(ptr, rendering, rotation);
|
setNodeRotation(ptr, rendering, rotation);
|
||||||
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
|
||||||
|
|
||||||
if (useAnim)
|
if (useAnim)
|
||||||
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
MWBase::Environment::get().getMechanicsManager()->add(ptr);
|
||||||
@ -133,6 +134,9 @@ namespace
|
|||||||
// Restore effect particles
|
// Restore effect particles
|
||||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||||
}
|
}
|
||||||
|
if (!physics.getObject(ptr))
|
||||||
|
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
||||||
|
}
|
||||||
|
|
||||||
void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
|
void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
|
||||||
{
|
{
|
||||||
@ -202,11 +206,12 @@ namespace
|
|||||||
{
|
{
|
||||||
MWWorld::CellStore& mCell;
|
MWWorld::CellStore& mCell;
|
||||||
Loading::Listener& mLoadingListener;
|
Loading::Listener& mLoadingListener;
|
||||||
|
bool mOnlyStatics;
|
||||||
bool mTest;
|
bool mTest;
|
||||||
|
|
||||||
std::vector<MWWorld::Ptr> mToInsert;
|
std::vector<MWWorld::Ptr> mToInsert;
|
||||||
|
|
||||||
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test);
|
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test);
|
||||||
|
|
||||||
bool operator() (const MWWorld::Ptr& ptr);
|
bool operator() (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
@ -214,8 +219,8 @@ namespace
|
|||||||
void insert(AddObject&& addObject);
|
void insert(AddObject&& addObject);
|
||||||
};
|
};
|
||||||
|
|
||||||
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test)
|
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test)
|
||||||
: mCell (cell), mLoadingListener (loadingListener), mTest(test)
|
: mCell (cell), mLoadingListener (loadingListener), mOnlyStatics(onlyStatics), mTest(test)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
||||||
@ -231,7 +236,7 @@ namespace
|
|||||||
{
|
{
|
||||||
for (MWWorld::Ptr& ptr : mToInsert)
|
for (MWWorld::Ptr& ptr : mToInsert)
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
|
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled() && ((mOnlyStatics && ptr.getClass().isStatic()) || !mOnlyStatics))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -264,6 +269,16 @@ namespace
|
|||||||
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection)
|
||||||
|
{
|
||||||
|
for (auto *cell : collection)
|
||||||
|
{
|
||||||
|
assert(cell->getCell()->isExterior());
|
||||||
|
if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -315,15 +330,41 @@ namespace MWWorld
|
|||||||
mRendering.update (duration, paused);
|
mRendering.update (duration, paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::unloadCell (CellStoreCollection::iterator iter, bool test)
|
void Scene::unloadInactiveCell (CellStore* cell, bool test)
|
||||||
{
|
{
|
||||||
|
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||||
|
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||||
if (!test)
|
if (!test)
|
||||||
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription();
|
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
|
||||||
|
|
||||||
|
ListObjectsVisitor visitor;
|
||||||
|
|
||||||
|
cell->forEach(visitor);
|
||||||
|
for (const auto& ptr : visitor.mObjects)
|
||||||
|
mPhysics->remove(ptr);
|
||||||
|
|
||||||
|
if (cell->getCell()->isExterior())
|
||||||
|
{
|
||||||
|
const auto cellX = cell->getCell()->getGridX();
|
||||||
|
const auto cellY = cell->getCell()->getGridY();
|
||||||
|
mPhysics->removeHeightField(cellX, cellY);
|
||||||
|
}
|
||||||
|
|
||||||
|
mInactiveCells.erase(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::deactivateCell(CellStore* cell, bool test)
|
||||||
|
{
|
||||||
|
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||||
|
if (mActiveCells.find(cell) == mActiveCells.end())
|
||||||
|
return;
|
||||||
|
if (!test)
|
||||||
|
Log(Debug::Info) << "Deactivate cell " << cell->getCell()->getDescription();
|
||||||
|
|
||||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||||
ListAndResetObjectsVisitor visitor;
|
ListAndResetObjectsVisitor visitor;
|
||||||
|
|
||||||
(*iter)->forEach(visitor);
|
cell->forEach(visitor);
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
for (const auto& ptr : visitor.mObjects)
|
for (const auto& ptr : visitor.mObjects)
|
||||||
{
|
{
|
||||||
@ -334,75 +375,57 @@ namespace MWWorld
|
|||||||
navigator->removeAgent(world->getPathfindingHalfExtents(ptr));
|
navigator->removeAgent(world->getPathfindingHalfExtents(ptr));
|
||||||
mRendering.removeActorPath(ptr);
|
mRendering.removeActorPath(ptr);
|
||||||
}
|
}
|
||||||
mPhysics->remove(ptr);
|
mPhysics->remove(ptr, ptr.getClass().isStatic());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto cellX = (*iter)->getCell()->getGridX();
|
const auto cellX = cell->getCell()->getGridX();
|
||||||
const auto cellY = (*iter)->getCell()->getGridY();
|
const auto cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
if ((*iter)->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
navigator->removeObject(DetourNavigator::ObjectId(heightField));
|
navigator->removeObject(DetourNavigator::ObjectId(heightField));
|
||||||
mPhysics->removeHeightField(cellX, cellY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*iter)->getCell()->hasWater())
|
if (cell->getCell()->hasWater())
|
||||||
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
||||||
|
|
||||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell()))
|
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||||
navigator->removePathgrid(*pathgrid);
|
navigator->removePathgrid(*pathgrid);
|
||||||
|
|
||||||
const auto player = world->getPlayerPtr();
|
const auto player = world->getPlayerPtr();
|
||||||
navigator->update(player.getRefData().getPosition().asVec3());
|
navigator->update(player.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
MWBase::Environment::get().getMechanicsManager()->drop (cell);
|
||||||
|
|
||||||
mRendering.removeCell(*iter);
|
mRendering.removeCell(cell);
|
||||||
MWBase::Environment::get().getWindowManager()->removeCell(*iter);
|
MWBase::Environment::get().getWindowManager()->removeCell(cell);
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
|
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (cell);
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound (*iter);
|
MWBase::Environment::get().getSoundManager()->stopSound (cell);
|
||||||
mActiveCells.erase(*iter);
|
mActiveCells.erase(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
|
void Scene::activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
|
||||||
{
|
{
|
||||||
std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell);
|
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||||
|
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
||||||
|
mActiveCells.insert(cell);
|
||||||
|
|
||||||
if(result.second)
|
|
||||||
{
|
|
||||||
if (test)
|
if (test)
|
||||||
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
|
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
|
||||||
else
|
else
|
||||||
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
||||||
|
|
||||||
float verts = ESM::Land::LAND_SIZE;
|
|
||||||
float worldsize = ESM::Land::REAL_SIZE;
|
|
||||||
|
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
const auto navigator = world->getNavigator();
|
const auto navigator = world->getNavigator();
|
||||||
|
|
||||||
const int cellX = cell->getCell()->getGridX();
|
const int cellX = cell->getCell()->getGridX();
|
||||||
const int cellY = cell->getCell()->getGridY();
|
const int cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
// Load terrain physics first...
|
|
||||||
if (!test && cell->getCell()->isExterior())
|
if (!test && cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
|
||||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static std::vector<float> defaultHeight;
|
|
||||||
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
|
||||||
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), 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))
|
||||||
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
|
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
|
||||||
heightField->getCollisionObject()->getWorldTransform());
|
heightField->getCollisionObject()->getWorldTransform());
|
||||||
@ -418,8 +441,7 @@ namespace MWWorld
|
|||||||
if (respawn)
|
if (respawn)
|
||||||
cell->respawn();
|
cell->respawn();
|
||||||
|
|
||||||
// ... then references. This is important for adjustPosition to work correctly.
|
insertCell (*cell, loadingListener, false, test);
|
||||||
insertCell (*cell, loadingListener, test);
|
|
||||||
|
|
||||||
mRendering.addCell(cell);
|
mRendering.addCell(cell);
|
||||||
if (!test)
|
if (!test)
|
||||||
@ -452,22 +474,58 @@ namespace MWWorld
|
|||||||
navigator->update(player.getRefData().getPosition().asVec3());
|
navigator->update(player.getRefData().getPosition().asVec3());
|
||||||
|
|
||||||
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
{
|
|
||||||
|
|
||||||
mRendering.configureAmbient(cell->getCell());
|
mRendering.configureAmbient(cell->getCell());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreloader->notifyLoaded(cell);
|
mPreloader->notifyLoaded(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene::loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test)
|
||||||
|
{
|
||||||
|
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||||
|
assert(mInactiveCells.find(cell) == mInactiveCells.end());
|
||||||
|
mInactiveCells.insert(cell);
|
||||||
|
|
||||||
|
if (test)
|
||||||
|
Log(Debug::Info) << "Testing inactive cell " << cell->getCell()->getDescription();
|
||||||
|
else
|
||||||
|
Log(Debug::Info) << "Loading inactive cell " << cell->getCell()->getDescription();
|
||||||
|
|
||||||
|
if (!test && cell->getCell()->isExterior())
|
||||||
|
{
|
||||||
|
float verts = ESM::Land::LAND_SIZE;
|
||||||
|
float worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
|
||||||
|
const int cellX = cell->getCell()->getGridX();
|
||||||
|
const int cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
|
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||||
|
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static std::vector<float> defaultHeight;
|
||||||
|
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
||||||
|
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insertCell (*cell, loadingListener, true, test);
|
||||||
|
}
|
||||||
|
|
||||||
void Scene::clear()
|
void Scene::clear()
|
||||||
{
|
{
|
||||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
||||||
while (active!=mActiveCells.end())
|
{
|
||||||
unloadCell (active++);
|
auto* cell = *iter++;
|
||||||
|
deactivateCell(cell);
|
||||||
|
unloadInactiveCell (cell);
|
||||||
|
}
|
||||||
assert(mActiveCells.empty());
|
assert(mActiveCells.empty());
|
||||||
|
assert(mInactiveCells.empty());
|
||||||
mCurrentCell = nullptr;
|
mCurrentCell = nullptr;
|
||||||
|
|
||||||
mPreloader->clear();
|
mPreloader->clear();
|
||||||
@ -510,20 +568,24 @@ namespace MWWorld
|
|||||||
|
|
||||||
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
|
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
|
||||||
{
|
{
|
||||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
for (auto iter = mInactiveCells.begin(); iter != mInactiveCells.end(); )
|
||||||
while (active!=mActiveCells.end())
|
|
||||||
{
|
{
|
||||||
if ((*active)->getCell()->isExterior())
|
auto* cell = *iter++;
|
||||||
|
if (cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
if (std::abs (playerCellX-(*active)->getCell()->getGridX())<=mHalfGridSize &&
|
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
|
||||||
std::abs (playerCellY-(*active)->getCell()->getGridY())<=mHalfGridSize)
|
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
|
||||||
{
|
if (dx > mHalfGridSize || dy > mHalfGridSize)
|
||||||
// keep cells within the new grid
|
deactivateCell(cell);
|
||||||
++active;
|
|
||||||
continue;
|
if (dx > mHalfGridSize+1 || dy > mHalfGridSize+1)
|
||||||
|
unloadInactiveCell(cell);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deactivateCell(cell);
|
||||||
|
unloadInactiveCell(cell);
|
||||||
}
|
}
|
||||||
unloadCell (active++);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
||||||
@ -535,32 +597,24 @@ namespace MWWorld
|
|||||||
mRendering.getPagedRefnums(newGrid, mPagedRefs);
|
mRendering.getPagedRefnums(newGrid, mPagedRefs);
|
||||||
|
|
||||||
std::size_t refsToLoad = 0;
|
std::size_t refsToLoad = 0;
|
||||||
|
const auto cellsToLoad = [&playerCellX,&playerCellY,&refsToLoad](CellStoreCollection& collection, int range) -> std::vector<std::pair<int,int>>
|
||||||
|
{
|
||||||
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
std::vector<std::pair<int, int>> cellsPositionsToLoad;
|
||||||
// get the number of refs to load
|
for (int x = playerCellX - range; x <= playerCellX + range; ++x)
|
||||||
for (int x = playerCellX - mHalfGridSize; x <= playerCellX + mHalfGridSize; ++x)
|
|
||||||
{
|
{
|
||||||
for (int y = playerCellY - mHalfGridSize; y <= playerCellY + mHalfGridSize; ++y)
|
for (int y = playerCellY - range; y <= playerCellY + range; ++y)
|
||||||
{
|
{
|
||||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
if (!isCellInCollection(x, y, collection))
|
||||||
|
|
||||||
while (iter!=mActiveCells.end())
|
|
||||||
{
|
|
||||||
assert ((*iter)->getCell()->isExterior());
|
|
||||||
|
|
||||||
if (x==(*iter)->getCell()->getGridX() &&
|
|
||||||
y==(*iter)->getCell()->getGridY())
|
|
||||||
break;
|
|
||||||
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter==mActiveCells.end())
|
|
||||||
{
|
{
|
||||||
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
|
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
|
||||||
cellsPositionsToLoad.emplace_back(x, y);
|
cellsPositionsToLoad.emplace_back(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return cellsPositionsToLoad;
|
||||||
|
};
|
||||||
|
auto cellsPositionsToLoad = cellsToLoad(mActiveCells,mHalfGridSize);
|
||||||
|
auto cellsPositionsToLoadInactive = cellsToLoad(mInactiveCells,mHalfGridSize+1);
|
||||||
|
|
||||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
Loading::ScopedLoad load(loadingListener);
|
Loading::ScopedLoad load(loadingListener);
|
||||||
@ -584,30 +638,26 @@ namespace MWWorld
|
|||||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
std::sort(cellsPositionsToLoadInactive.begin(), cellsPositionsToLoadInactive.end(),
|
||||||
|
[&] (const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
|
||||||
|
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||||
|
});
|
||||||
|
|
||||||
// Load cells
|
// Load cells
|
||||||
for (const auto& cellPosition : cellsPositionsToLoad)
|
for (const auto& [x,y] : cellsPositionsToLoadInactive)
|
||||||
{
|
{
|
||||||
const auto x = cellPosition.first;
|
if (!isCellInCollection(x, y, mInactiveCells))
|
||||||
const auto y = cellPosition.second;
|
|
||||||
|
|
||||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
|
||||||
|
|
||||||
while (iter != mActiveCells.end())
|
|
||||||
{
|
|
||||||
assert ((*iter)->getCell()->isExterior());
|
|
||||||
|
|
||||||
if (x == (*iter)->getCell()->getGridX() &&
|
|
||||||
y == (*iter)->getCell()->getGridY())
|
|
||||||
break;
|
|
||||||
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter == mActiveCells.end())
|
|
||||||
{
|
{
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
||||||
|
loadInactiveCell (cell, loadingListener);
|
||||||
loadCell (cell, loadingListener, changeEvent);
|
}
|
||||||
|
}
|
||||||
|
for (const auto& [x,y] : cellsPositionsToLoad)
|
||||||
|
{
|
||||||
|
if (!isCellInCollection(x, y, mActiveCells))
|
||||||
|
{
|
||||||
|
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
||||||
|
activateCell (cell, loadingListener, changeEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,7 +690,8 @@ namespace MWWorld
|
|||||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||||
|
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
|
||||||
loadCell (cell, loadingListener, false, true);
|
loadInactiveCell (cell, loadingListener, true);
|
||||||
|
activateCell (cell, loadingListener, false, true);
|
||||||
|
|
||||||
iter = mActiveCells.begin();
|
iter = mActiveCells.begin();
|
||||||
while (iter != mActiveCells.end())
|
while (iter != mActiveCells.end())
|
||||||
@ -648,7 +699,8 @@ namespace MWWorld
|
|||||||
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
|
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
|
||||||
it->mData.mY == (*iter)->getCell()->getGridY())
|
it->mData.mY == (*iter)->getCell()->getGridY())
|
||||||
{
|
{
|
||||||
unloadCell(iter, true);
|
deactivateCell(*iter, true);
|
||||||
|
unloadInactiveCell (*iter, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,7 +738,8 @@ namespace MWWorld
|
|||||||
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
|
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
|
||||||
|
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
|
||||||
loadCell (cell, loadingListener, false, true);
|
loadInactiveCell (cell, loadingListener, true);
|
||||||
|
activateCell (cell, loadingListener, false, true);
|
||||||
|
|
||||||
CellStoreCollection::iterator iter = mActiveCells.begin();
|
CellStoreCollection::iterator iter = mActiveCells.begin();
|
||||||
while (iter != mActiveCells.end())
|
while (iter != mActiveCells.end())
|
||||||
@ -695,7 +748,8 @@ namespace MWWorld
|
|||||||
|
|
||||||
if (it->mName == (*iter)->getCell()->mName)
|
if (it->mName == (*iter)->getCell()->mName)
|
||||||
{
|
{
|
||||||
unloadCell(iter, true);
|
deactivateCell(*iter, true);
|
||||||
|
unloadInactiveCell (*iter, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,15 +872,21 @@ namespace MWWorld
|
|||||||
Log(Debug::Info) << "Changing to interior";
|
Log(Debug::Info) << "Changing to interior";
|
||||||
|
|
||||||
// unload
|
// unload
|
||||||
CellStoreCollection::iterator active = mActiveCells.begin();
|
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
||||||
while (active!=mActiveCells.end())
|
{
|
||||||
unloadCell (active++);
|
auto* cell = *iter++;
|
||||||
|
deactivateCell(cell);
|
||||||
|
unloadInactiveCell(cell);
|
||||||
|
}
|
||||||
|
assert(mActiveCells.empty());
|
||||||
|
assert(mInactiveCells.empty());
|
||||||
|
|
||||||
loadingListener->setProgressRange(cell->count());
|
loadingListener->setProgressRange(cell->count());
|
||||||
|
|
||||||
// Load cell.
|
// Load cell.
|
||||||
mPagedRefs.clear();
|
mPagedRefs.clear();
|
||||||
loadCell (cell, loadingListener, changeEvent);
|
loadInactiveCell (cell, loadingListener);
|
||||||
|
activateCell (cell, loadingListener, changeEvent);
|
||||||
|
|
||||||
changePlayerCell(cell, position, adjustPlayerPos);
|
changePlayerCell(cell, position, adjustPlayerPos);
|
||||||
|
|
||||||
@ -874,23 +934,26 @@ namespace MWWorld
|
|||||||
mCellChanged = false;
|
mCellChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test)
|
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test)
|
||||||
{
|
{
|
||||||
InsertVisitor insertVisitor (cell, *loadingListener, test);
|
InsertVisitor insertVisitor (cell, *loadingListener, onlyStatics, test);
|
||||||
cell.forEach (insertVisitor);
|
cell.forEach (insertVisitor);
|
||||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); });
|
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs, onlyStatics); });
|
||||||
|
if (!onlyStatics)
|
||||||
|
{
|
||||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
||||||
|
|
||||||
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
|
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
|
||||||
PositionVisitor posVisitor;
|
PositionVisitor posVisitor;
|
||||||
cell.forEach (posVisitor);
|
cell.forEach (posVisitor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Scene::addObjectToScene (const Ptr& ptr)
|
void Scene::addObjectToScene (const Ptr& ptr)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
addObject(ptr, *mPhysics, mRendering, mPagedRefs);
|
addObject(ptr, *mPhysics, mRendering, mPagedRefs, false);
|
||||||
addObject(ptr, *mPhysics, mNavigator);
|
addObject(ptr, *mPhysics, mNavigator);
|
||||||
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
||||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||||
|
@ -65,13 +65,13 @@ namespace MWWorld
|
|||||||
class Scene
|
class Scene
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using CellStoreCollection = std::set<CellStore *>;
|
||||||
typedef std::set<CellStore *> CellStoreCollection;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CellStore* mCurrentCell; // the cell the player is in
|
CellStore* mCurrentCell; // the cell the player is in
|
||||||
CellStoreCollection mActiveCells;
|
CellStoreCollection mActiveCells;
|
||||||
|
CellStoreCollection mInactiveCells;
|
||||||
bool mCellChanged;
|
bool mCellChanged;
|
||||||
MWPhysics::PhysicsSystem *mPhysics;
|
MWPhysics::PhysicsSystem *mPhysics;
|
||||||
MWRender::RenderingManager& mRendering;
|
MWRender::RenderingManager& mRendering;
|
||||||
@ -92,7 +92,7 @@ namespace MWWorld
|
|||||||
|
|
||||||
std::set<ESM::RefNum> mPagedRefs;
|
std::set<ESM::RefNum> mPagedRefs;
|
||||||
|
|
||||||
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false);
|
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test = false);
|
||||||
osg::Vec2i mCurrentGridCenter;
|
osg::Vec2i mCurrentGridCenter;
|
||||||
|
|
||||||
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
|
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
|
||||||
@ -108,6 +108,11 @@ namespace MWWorld
|
|||||||
osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const;
|
osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const;
|
||||||
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
|
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
|
||||||
|
|
||||||
|
void unloadInactiveCell (CellStore* cell, bool test = false);
|
||||||
|
void deactivateCell (CellStore* cell, bool test = false);
|
||||||
|
void activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
|
||||||
|
void loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
|
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
|
||||||
@ -119,10 +124,6 @@ namespace MWWorld
|
|||||||
void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
|
void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
|
||||||
void reloadTerrain();
|
void reloadTerrain();
|
||||||
|
|
||||||
void unloadCell (CellStoreCollection::iterator iter, bool test = false);
|
|
||||||
|
|
||||||
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
|
|
||||||
|
|
||||||
void playerMoved (const osg::Vec3f& pos);
|
void playerMoved (const osg::Vec3f& pos);
|
||||||
|
|
||||||
void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos);
|
void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user