mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-08 03:41:11 -04:00
Merge branch 'esm4paging' into 'master'
Object paging in ESM4 worldspaces See merge request OpenMW/openmw!4770
This commit is contained in:
commit
152d87a6b3
@ -55,6 +55,16 @@ namespace MWClass
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Figure out a better way to find markers and LOD meshes
|
||||||
|
inline bool isMarkerModel(std::string_view model)
|
||||||
|
{
|
||||||
|
return Misc::StringUtils::ciStartsWith(model, "marker");
|
||||||
|
}
|
||||||
|
inline bool isLodModel(std::string_view model)
|
||||||
|
{
|
||||||
|
return Misc::StringUtils::ciEndsWith(model, "lod.nif");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base for many ESM4 Classes
|
// Base for many ESM4 Classes
|
||||||
@ -100,11 +110,8 @@ namespace MWClass
|
|||||||
{
|
{
|
||||||
std::string_view model = getClassModel<Record>(ptr);
|
std::string_view model = getClassModel<Record>(ptr);
|
||||||
|
|
||||||
// Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack.
|
// TODO: There should be a better way to hide markers
|
||||||
// Needed because otherwise LOD meshes are rendered on top of normal meshes.
|
if (ESM4Impl::isMarkerModel(model) || ESM4Impl::isLodModel(model))
|
||||||
// TODO: Figure out a better way find markers and LOD meshes; show LOD only outside of active grid.
|
|
||||||
if (model.empty() || Misc::StringUtils::ciStartsWith(model, "marker")
|
|
||||||
|| Misc::StringUtils::ciEndsWith(model, "lod.nif"))
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
@ -20,6 +20,12 @@
|
|||||||
#include <components/esm3/loaddoor.hpp>
|
#include <components/esm3/loaddoor.hpp>
|
||||||
#include <components/esm3/loadstat.hpp>
|
#include <components/esm3/loadstat.hpp>
|
||||||
#include <components/esm3/readerscache.hpp>
|
#include <components/esm3/readerscache.hpp>
|
||||||
|
#include <components/esm4/loadacti.hpp>
|
||||||
|
#include <components/esm4/loadcont.hpp>
|
||||||
|
#include <components/esm4/loaddoor.hpp>
|
||||||
|
#include <components/esm4/loadfurn.hpp>
|
||||||
|
#include <components/esm4/loadstat.hpp>
|
||||||
|
#include <components/esm4/loadtree.hpp>
|
||||||
#include <components/misc/pathhelpers.hpp>
|
#include <components/misc/pathhelpers.hpp>
|
||||||
#include <components/misc/resourcehelpers.hpp>
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
@ -36,12 +42,14 @@
|
|||||||
|
|
||||||
#include "apps/openmw/mwbase/environment.hpp"
|
#include "apps/openmw/mwbase/environment.hpp"
|
||||||
#include "apps/openmw/mwbase/world.hpp"
|
#include "apps/openmw/mwbase/world.hpp"
|
||||||
|
#include "apps/openmw/mwclass/esm4base.hpp"
|
||||||
#include "apps/openmw/mwworld/esmstore.hpp"
|
#include "apps/openmw/mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "vismask.hpp"
|
#include "vismask.hpp"
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool typeFilter(int type, bool far)
|
bool typeFilter(int type, bool far)
|
||||||
@ -51,8 +59,14 @@ namespace MWRender
|
|||||||
case ESM::REC_STAT:
|
case ESM::REC_STAT:
|
||||||
case ESM::REC_ACTI:
|
case ESM::REC_ACTI:
|
||||||
case ESM::REC_DOOR:
|
case ESM::REC_DOOR:
|
||||||
|
case ESM::REC_STAT4:
|
||||||
|
case ESM::REC_DOOR4:
|
||||||
|
case ESM::REC_TREE4:
|
||||||
return true;
|
return true;
|
||||||
case ESM::REC_CONT:
|
case ESM::REC_CONT:
|
||||||
|
case ESM::REC_ACTI4:
|
||||||
|
case ESM::REC_CONT4:
|
||||||
|
case ESM::REC_FURN4:
|
||||||
return !far;
|
return !far;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -60,7 +74,16 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getModel(int type, ESM::RefId id, const MWWorld::ESMStore& store)
|
template <typename Record>
|
||||||
|
std::string_view getEsm4Model(const Record& record)
|
||||||
|
{
|
||||||
|
if (MWClass::ESM4Impl::isMarkerModel(record->mModel))
|
||||||
|
return {};
|
||||||
|
else
|
||||||
|
return record->mModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view getModel(int type, ESM::RefId id, const MWWorld::ESMStore& store)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -72,6 +95,18 @@ namespace MWRender
|
|||||||
return store.get<ESM::Door>().searchStatic(id)->mModel;
|
return store.get<ESM::Door>().searchStatic(id)->mModel;
|
||||||
case ESM::REC_CONT:
|
case ESM::REC_CONT:
|
||||||
return store.get<ESM::Container>().searchStatic(id)->mModel;
|
return store.get<ESM::Container>().searchStatic(id)->mModel;
|
||||||
|
case ESM::REC_STAT4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Static>().searchStatic(id));
|
||||||
|
case ESM::REC_DOOR4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Door>().searchStatic(id));
|
||||||
|
case ESM::REC_TREE4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Tree>().searchStatic(id));
|
||||||
|
case ESM::REC_ACTI4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Activator>().searchStatic(id));
|
||||||
|
case ESM::REC_CONT4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Container>().searchStatic(id));
|
||||||
|
case ESM::REC_FURN4:
|
||||||
|
return getEsm4Model(store.get<ESM4::Furniture>().searchStatic(id));
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -494,6 +529,17 @@ namespace MWRender
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PagedCellRef makePagedCellRef(const ESM4::Reference& value)
|
||||||
|
{
|
||||||
|
return PagedCellRef{
|
||||||
|
.mRefId = value.mBaseObj,
|
||||||
|
.mRefNum = value.mId,
|
||||||
|
.mPosition = value.mPos.asVec3(),
|
||||||
|
.mRotation = value.mPos.asRotationVec3(),
|
||||||
|
.mScale = value.mScale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
std::map<ESM::RefNum, PagedCellRef> collectESM3References(
|
std::map<ESM::RefNum, PagedCellRef> collectESM3References(
|
||||||
float size, const osg::Vec2i& startCell, const MWWorld::ESMStore& store)
|
float size, const osg::Vec2i& startCell, const MWWorld::ESMStore& store)
|
||||||
{
|
{
|
||||||
@ -561,6 +607,45 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
return refs;
|
return refs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<ESM::RefNum, PagedCellRef> collectESM4References(
|
||||||
|
float size, const osg::Vec2i& startCell, ESM::RefId worldspace)
|
||||||
|
{
|
||||||
|
std::map<ESM::RefNum, PagedCellRef> refs;
|
||||||
|
const auto& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
for (int cellX = startCell.x(); cellX < startCell.x() + size; ++cellX)
|
||||||
|
{
|
||||||
|
for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY)
|
||||||
|
{
|
||||||
|
const ESM4::Cell* cell
|
||||||
|
= store.get<ESM4::Cell>().searchExterior(ESM::ExteriorCellLocation(cellX, cellY, worldspace));
|
||||||
|
if (!cell)
|
||||||
|
continue;
|
||||||
|
for (const ESM4::Reference* ref4 : store.get<ESM4::Reference>().getByCell(cell->mId))
|
||||||
|
{
|
||||||
|
if (ref4->mFlags & ESM4::Rec_Disabled)
|
||||||
|
continue;
|
||||||
|
int type = store.findStatic(ref4->mBaseObj);
|
||||||
|
if (!typeFilter(type, size >= 2))
|
||||||
|
continue;
|
||||||
|
if (!ref4->mEsp.parent.isZeroOrUnset())
|
||||||
|
{
|
||||||
|
const ESM4::Reference* parentRef
|
||||||
|
= store.get<ESM4::Reference>().searchStatic(ref4->mEsp.parent);
|
||||||
|
if (parentRef)
|
||||||
|
{
|
||||||
|
bool parentDisabled = parentRef->mFlags & ESM4::Rec_Disabled;
|
||||||
|
bool inversed = ref4->mEsp.flags & ESM4::EnableParent::Flag_Inversed;
|
||||||
|
if (parentDisabled != inversed)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refs.insert_or_assign(ref4->mId, makePagedCellRef(*ref4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid,
|
osg::ref_ptr<osg::Node> ObjectPaging::createChunk(float size, const osg::Vec2f& center, bool activeGrid,
|
||||||
@ -578,7 +663,7 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO
|
refs = collectESM4References(size, startCell, mWorldspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeGrid && !refs.empty())
|
if (activeGrid && !refs.empty())
|
||||||
@ -648,12 +733,12 @@ namespace MWRender
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const int type = store.findStatic(ref.mRefId);
|
const int type = store.findStatic(ref.mRefId);
|
||||||
VFS::Path::Normalized model = getModel(type, ref.mRefId, store);
|
VFS::Path::Normalized model(getModel(type, ref.mRefId, store));
|
||||||
if (model.empty())
|
if (model.empty())
|
||||||
continue;
|
continue;
|
||||||
model = Misc::ResourceHelpers::correctMeshPath(model);
|
model = Misc::ResourceHelpers::correctMeshPath(model);
|
||||||
|
|
||||||
if (activeGrid && type != ESM::REC_STAT)
|
if (activeGrid && type != ESM::REC_STAT && type != ESM::REC_STAT4)
|
||||||
{
|
{
|
||||||
model = Misc::ResourceHelpers::correctActorModelPath(model, mSceneManager->getVFS());
|
model = Misc::ResourceHelpers::correctActorModelPath(model, mSceneManager->getVFS());
|
||||||
if (Misc::getFileExtension(model) == "nif")
|
if (Misc::getFileExtension(model) == "nif")
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
#include <components/settings/values.hpp>
|
#include <components/settings/values.hpp>
|
||||||
|
#include <components/terrain/terraingrid.hpp>
|
||||||
#include <components/vfs/pathutil.hpp>
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
@ -511,7 +512,7 @@ namespace MWWorld
|
|||||||
|
|
||||||
if (cellVariant.isExterior())
|
if (cellVariant.isExterior())
|
||||||
{
|
{
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (mPhysics->getHeightField(cellX, cellY) != nullptr)
|
||||||
mNavigator.addWater(
|
mNavigator.addWater(
|
||||||
osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard);
|
osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, waterLevel, navigatorUpdateGuard);
|
||||||
}
|
}
|
||||||
@ -645,8 +646,11 @@ namespace MWWorld
|
|||||||
mHalfGridSize = halfGridSize;
|
mHalfGridSize = halfGridSize;
|
||||||
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
||||||
osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter);
|
osg::Vec4i newGrid = gridCenterToBounds(mCurrentGridCenter);
|
||||||
mRendering.setActiveGrid(newGrid);
|
|
||||||
|
// NOTE: setActiveGrid must be after enableTerrain, otherwise we set the grid in the old exterior worldspace
|
||||||
mRendering.enableTerrain(true, playerCellIndex.mWorldspace);
|
mRendering.enableTerrain(true, playerCellIndex.mWorldspace);
|
||||||
|
mRendering.setActiveGrid(newGrid);
|
||||||
|
|
||||||
mPreloader->setTerrain(mRendering.getTerrain());
|
mPreloader->setTerrain(mRendering.getTerrain());
|
||||||
if (mRendering.pagingUnlockCache())
|
if (mRendering.pagingUnlockCache())
|
||||||
mPreloader->abortTerrainPreloadExcept(nullptr);
|
mPreloader->abortTerrainPreloadExcept(nullptr);
|
||||||
@ -1292,6 +1296,9 @@ namespace MWWorld
|
|||||||
|
|
||||||
void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync)
|
void Scene::preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync)
|
||||||
{
|
{
|
||||||
|
if (mRendering.getTerrain()->getWorldspace() != worldspace)
|
||||||
|
throw std::runtime_error("preloadTerrain can only work with the current exterior worldspace");
|
||||||
|
|
||||||
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace);
|
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace);
|
||||||
const PositionCellGrid position{ pos, gridCenterToBounds({ cellPos.mX, cellPos.mY }) };
|
const PositionCellGrid position{ pos, gridCenterToBounds({ cellPos.mX, cellPos.mY }) };
|
||||||
mPreloader->abortTerrainPreloadExcept(&position);
|
mPreloader->abortTerrainPreloadExcept(&position);
|
||||||
|
@ -129,6 +129,9 @@ namespace MWWorld
|
|||||||
void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
|
void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
|
||||||
void preloadFastTravelDestinations(
|
void preloadFastTravelDestinations(
|
||||||
const osg::Vec3f& playerPos, std::vector<PositionCellGrid>& exteriorPositions);
|
const osg::Vec3f& playerPos, std::vector<PositionCellGrid>& exteriorPositions);
|
||||||
|
void preloadCellWithSurroundings(MWWorld::CellStore& cell);
|
||||||
|
void preloadCell(MWWorld::CellStore& cell);
|
||||||
|
void preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync = false);
|
||||||
|
|
||||||
osg::Vec4i gridCenterToBounds(const osg::Vec2i& centerCell) const;
|
osg::Vec4i gridCenterToBounds(const osg::Vec2i& centerCell) 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;
|
||||||
@ -143,9 +146,6 @@ namespace MWWorld
|
|||||||
|
|
||||||
~Scene();
|
~Scene();
|
||||||
|
|
||||||
void preloadCellWithSurroundings(MWWorld::CellStore& cell);
|
|
||||||
void preloadCell(MWWorld::CellStore& cell);
|
|
||||||
void preloadTerrain(const osg::Vec3f& pos, ESM::RefId worldspace, bool sync = false);
|
|
||||||
void reloadTerrain();
|
void reloadTerrain();
|
||||||
|
|
||||||
void playerMoved(const osg::Vec3f& pos);
|
void playerMoved(const osg::Vec3f& pos);
|
||||||
|
@ -517,13 +517,6 @@ namespace MWWorld
|
|||||||
|
|
||||||
mStore.checkPlayer();
|
mStore.checkPlayer();
|
||||||
mPlayer->readRecord(reader, type);
|
mPlayer->readRecord(reader, type);
|
||||||
if (getPlayerPtr().isInCell())
|
|
||||||
{
|
|
||||||
if (getPlayerPtr().getCell()->isExterior())
|
|
||||||
mWorldScene->preloadTerrain(getPlayerPtr().getRefData().getPosition().asVec3(),
|
|
||||||
getPlayerPtr().getCell()->getCell()->getWorldSpace());
|
|
||||||
mWorldScene->preloadCellWithSurroundings(*getPlayerPtr().getCell());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ESM::REC_CSTA:
|
case ESM::REC_CSTA:
|
||||||
// We need to rebuild the ESMStore index in order to be able to lookup dynamic records while loading the
|
// We need to rebuild the ESMStore index in order to be able to lookup dynamic records while loading the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user