mirror of
https://github.com/OpenMW/openmw.git
synced 2025-12-15 18:43:05 +00:00
Merge branch 'cleanup_object_paging' into 'master'
Cleanup object paging See merge request OpenMW/openmw!4149
This commit is contained in:
commit
8f3625b6a8
4 changed files with 509 additions and 503 deletions
|
|
@ -148,7 +148,7 @@ namespace MWBase
|
||||||
virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0;
|
virtual MWWorld::ConstPtr getPlayerConstPtr() const = 0;
|
||||||
|
|
||||||
virtual MWWorld::ESMStore& getStore() = 0;
|
virtual MWWorld::ESMStore& getStore() = 0;
|
||||||
const MWWorld::ESMStore& getStore() const { return const_cast<MWBase::World*>(this)->getStore(); }
|
virtual const MWWorld::ESMStore& getStore() const = 0;
|
||||||
|
|
||||||
virtual const std::vector<int>& getESMVersions() const = 0;
|
virtual const std::vector<int>& getESMVersions() const = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <components/esm3/esmreader.hpp>
|
#include <components/esm3/esmreader.hpp>
|
||||||
#include <components/esm3/loadacti.hpp>
|
#include <components/esm3/loadacti.hpp>
|
||||||
|
#include <components/esm3/loadcell.hpp>
|
||||||
#include <components/esm3/loadcont.hpp>
|
#include <components/esm3/loadcont.hpp>
|
||||||
#include <components/esm3/loaddoor.hpp>
|
#include <components/esm3/loaddoor.hpp>
|
||||||
#include <components/esm3/loadstat.hpp>
|
#include <components/esm3/loadstat.hpp>
|
||||||
|
|
@ -40,7 +41,8 @@
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
bool typeFilter(int type, bool far)
|
bool typeFilter(int type, bool far)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|
@ -57,7 +59,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getModel(int type, const ESM::RefId& id, const MWWorld::ESMStore& store)
|
std::string getModel(int type, ESM::RefId id, const MWWorld::ESMStore& store)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
@ -73,27 +75,27 @@ namespace MWRender
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
osg::ref_ptr<osg::Node> ObjectPaging::getChunk(float size, const osg::Vec2f& center, unsigned char lod,
|
osg::ref_ptr<osg::Node> ObjectPaging::getChunk(float size, const osg::Vec2f& center, unsigned char /*lod*/,
|
||||||
unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
|
unsigned int lodFlags, bool activeGrid, const osg::Vec3f& viewPoint, bool compile)
|
||||||
{
|
{
|
||||||
lod = static_cast<unsigned char>(lodFlags >> (4 * 4));
|
|
||||||
if (activeGrid && !mActiveGrid)
|
if (activeGrid && !mActiveGrid)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
ChunkId id = std::make_tuple(center, size, activeGrid);
|
const ChunkId id = std::make_tuple(center, size, activeGrid);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(id);
|
if (const osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(id))
|
||||||
if (obj)
|
|
||||||
return static_cast<osg::Node*>(obj.get());
|
return static_cast<osg::Node*>(obj.get());
|
||||||
else
|
|
||||||
{
|
const unsigned char lod = static_cast<unsigned char>(lodFlags >> (4 * 4));
|
||||||
osg::ref_ptr<osg::Node> node = createChunk(size, center, activeGrid, viewPoint, compile, lod);
|
osg::ref_ptr<osg::Node> node = createChunk(size, center, activeGrid, viewPoint, compile, lod);
|
||||||
mCache->addEntryToObjectCache(id, node.get());
|
mCache->addEntryToObjectCache(id, node.get());
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
class CanOptimizeCallback : public SceneUtil::Optimizer::IsOperationPermissibleForObjectCallback
|
class CanOptimizeCallback : public SceneUtil::Optimizer::IsOperationPermissibleForObjectCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -109,8 +111,6 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
using LODRange = osg::LOD::MinMaxPair;
|
using LODRange = osg::LOD::MinMaxPair;
|
||||||
|
|
||||||
LODRange intersection(const LODRange& left, const LODRange& right)
|
LODRange intersection(const LODRange& left, const LODRange& right)
|
||||||
|
|
@ -127,7 +127,6 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
return { r.first / div, r.second / div };
|
return { r.first / div, r.second / div };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class CopyOp : public osg::CopyOp
|
class CopyOp : public osg::CopyOp
|
||||||
{
|
{
|
||||||
|
|
@ -419,8 +418,9 @@ namespace MWRender
|
||||||
m->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.1f, 0.1f, 0.1f, 1.f));
|
m->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.1f, 0.1f, 0.1f, 1.f));
|
||||||
m->setColorMode(osg::Material::OFF);
|
m->setColorMode(osg::Material::OFF);
|
||||||
m->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(color));
|
m->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(color));
|
||||||
osg::ref_ptr<osg::StateSet> stateset
|
osg::ref_ptr<osg::StateSet> stateset = node.getStateSet()
|
||||||
= node.getStateSet() ? osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY) : new osg::StateSet;
|
? osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY)
|
||||||
|
: new osg::StateSet;
|
||||||
stateset->setAttribute(m);
|
stateset->setAttribute(m);
|
||||||
stateset->addUniform(new osg::Uniform("colorMode", 0));
|
stateset->addUniform(new osg::Uniform("colorMode", 0));
|
||||||
stateset->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
stateset->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
||||||
|
|
@ -447,6 +447,7 @@ namespace MWRender
|
||||||
node.getOrCreateUserDataContainer()->addUserObject(marker);
|
node.getOrCreateUserDataContainer()->addUserObject(marker);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager, ESM::RefId worldspace)
|
ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager, ESM::RefId worldspace)
|
||||||
: GenericResourceManager<ChunkId>(nullptr, Settings::cells().mCacheExpiryDelay)
|
: GenericResourceManager<ChunkId>(nullptr, Settings::cells().mCacheExpiryDelay)
|
||||||
|
|
@ -462,11 +463,33 @@ namespace MWRender
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<ESM::RefNum, ESM::CellRef> ObjectPaging::collectESM3References(
|
namespace
|
||||||
float size, const osg::Vec2i& startCell, ESM::ReadersCache& readers) const
|
|
||||||
{
|
{
|
||||||
std::map<ESM::RefNum, ESM::CellRef> refs;
|
struct PagedCellRef
|
||||||
const auto& store = MWBase::Environment::get().getWorld()->getStore();
|
{
|
||||||
|
ESM::RefId mRefId;
|
||||||
|
ESM::RefNum mRefNum;
|
||||||
|
osg::Vec3f mPosition;
|
||||||
|
osg::Vec3f mRotation;
|
||||||
|
float mScale;
|
||||||
|
};
|
||||||
|
|
||||||
|
PagedCellRef makePagedCellRef(const ESM::CellRef& value)
|
||||||
|
{
|
||||||
|
return PagedCellRef{
|
||||||
|
.mRefId = value.mRefID,
|
||||||
|
.mRefNum = value.mRefNum,
|
||||||
|
.mPosition = value.mPos.asVec3(),
|
||||||
|
.mRotation = value.mPos.asRotationVec3(),
|
||||||
|
.mScale = value.mScale,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<ESM::RefNum, PagedCellRef> collectESM3References(
|
||||||
|
float size, const osg::Vec2i& startCell, const MWWorld::ESMStore& store)
|
||||||
|
{
|
||||||
|
std::map<ESM::RefNum, PagedCellRef> refs;
|
||||||
|
ESM::ReadersCache readers;
|
||||||
for (int cellX = startCell.x(); cellX < startCell.x() + size; ++cellX)
|
for (int cellX = startCell.x(); cellX < startCell.x() + size; ++cellX)
|
||||||
{
|
{
|
||||||
for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY)
|
for (int cellY = startCell.y(); cellY < startCell.y() + size; ++cellY)
|
||||||
|
|
@ -503,7 +526,7 @@ namespace MWRender
|
||||||
refs.erase(ref.mRefNum);
|
refs.erase(ref.mRefNum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
refs[ref.mRefNum] = std::move(ref);
|
refs.insert_or_assign(ref.mRefNum, makePagedCellRef(ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
|
@ -513,7 +536,7 @@ namespace MWRender
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto [ref, deleted] : cell->mLeasedRefs)
|
for (const auto& [ref, deleted] : cell->mLeasedRefs)
|
||||||
{
|
{
|
||||||
if (deleted)
|
if (deleted)
|
||||||
{
|
{
|
||||||
|
|
@ -523,29 +546,26 @@ namespace MWRender
|
||||||
int type = store.findStatic(ref.mRefID);
|
int type = store.findStatic(ref.mRefID);
|
||||||
if (!typeFilter(type, size >= 2))
|
if (!typeFilter(type, size >= 2))
|
||||||
continue;
|
continue;
|
||||||
refs[ref.mRefNum] = std::move(ref);
|
refs.insert_or_assign(ref.mRefNum, makePagedCellRef(ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return refs;
|
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,
|
||||||
const osg::Vec3f& viewPoint, bool compile, unsigned char lod)
|
const osg::Vec3f& viewPoint, bool compile, unsigned char lod)
|
||||||
{
|
{
|
||||||
osg::Vec2i startCell = osg::Vec2i(std::floor(center.x() - size / 2.f), std::floor(center.y() - size / 2.f));
|
const osg::Vec2i startCell(std::floor(center.x() - size / 2.f), std::floor(center.y() - size / 2.f));
|
||||||
|
const MWBase::World& world = *MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::ESMStore& store = world.getStore();
|
||||||
|
|
||||||
osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * getCellSize(mWorldspace);
|
std::map<ESM::RefNum, PagedCellRef> refs;
|
||||||
osg::Vec3f relativeViewPoint = viewPoint - worldCenter;
|
|
||||||
|
|
||||||
std::map<ESM::RefNum, ESM::CellRef> refs;
|
|
||||||
ESM::ReadersCache readers;
|
|
||||||
const auto& world = MWBase::Environment::get().getWorld();
|
|
||||||
const auto& store = world->getStore();
|
|
||||||
|
|
||||||
if (mWorldspace == ESM::Cell::sDefaultWorldspaceId)
|
if (mWorldspace == ESM::Cell::sDefaultWorldspaceId)
|
||||||
{
|
{
|
||||||
refs = collectESM3References(size, startCell, readers);
|
refs = collectESM3References(size, startCell, store);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -567,17 +587,19 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec2f minBound = (center - osg::Vec2f(size / 2.f, size / 2.f));
|
const osg::Vec2f minBound = (center - osg::Vec2f(size / 2.f, size / 2.f));
|
||||||
osg::Vec2f maxBound = (center + osg::Vec2f(size / 2.f, size / 2.f));
|
const osg::Vec2f maxBound = (center + osg::Vec2f(size / 2.f, size / 2.f));
|
||||||
|
const osg::Vec2i floorMinBound(std::floor(minBound.x()), std::floor(minBound.y()));
|
||||||
|
const osg::Vec2i ceilMaxBound(std::ceil(maxBound.x()), std::ceil(maxBound.y()));
|
||||||
struct InstanceList
|
struct InstanceList
|
||||||
{
|
{
|
||||||
std::vector<const ESM::CellRef*> mInstances;
|
std::vector<const PagedCellRef*> mInstances;
|
||||||
AnalyzeVisitor::Result mAnalyzeResult;
|
AnalyzeVisitor::Result mAnalyzeResult;
|
||||||
bool mNeedCompile = false;
|
bool mNeedCompile = false;
|
||||||
};
|
};
|
||||||
typedef std::map<osg::ref_ptr<const osg::Node>, InstanceList> NodeMap;
|
typedef std::map<osg::ref_ptr<const osg::Node>, InstanceList> NodeMap;
|
||||||
NodeMap nodes;
|
NodeMap nodes;
|
||||||
osg::ref_ptr<RefnumSet> refnumSet = activeGrid ? new RefnumSet : nullptr;
|
const osg::ref_ptr<RefnumSet> refnumSet = activeGrid ? new RefnumSet : nullptr;
|
||||||
|
|
||||||
// Mask_UpdateVisitor is used in such cases in NIF loader:
|
// Mask_UpdateVisitor is used in such cases in NIF loader:
|
||||||
// 1. For collision nodes, which is not supposed to be rendered.
|
// 1. For collision nodes, which is not supposed to be rendered.
|
||||||
|
|
@ -585,47 +607,39 @@ namespace MWRender
|
||||||
// Since ObjectPaging does not handle VisController, we can just ignore both types of nodes.
|
// Since ObjectPaging does not handle VisController, we can just ignore both types of nodes.
|
||||||
constexpr auto copyMask = ~Mask_UpdateVisitor;
|
constexpr auto copyMask = ~Mask_UpdateVisitor;
|
||||||
|
|
||||||
auto cellSize = getCellSize(mWorldspace);
|
const int cellSize = getCellSize(mWorldspace);
|
||||||
const auto smallestDistanceToChunk = (size > 1 / 8.f) ? (size * cellSize) : 0.f;
|
const float smallestDistanceToChunk = (size > 1 / 8.f) ? (size * cellSize) : 0.f;
|
||||||
const auto higherDistanceToChunk = [&] {
|
const float higherDistanceToChunk
|
||||||
if (!activeGrid)
|
= activeGrid ? ((size < 1) ? 5 : 3) * cellSize * size + 1 : smallestDistanceToChunk + 1;
|
||||||
return smallestDistanceToChunk + 1;
|
|
||||||
return ((size < 1) ? 5 : 3) * cellSize * size + 1;
|
|
||||||
}();
|
|
||||||
|
|
||||||
AnalyzeVisitor analyzeVisitor(copyMask);
|
AnalyzeVisitor analyzeVisitor(copyMask);
|
||||||
float minSize = mMinSize;
|
const float minSize = mMinSizeMergeFactor ? mMinSize * mMinSizeMergeFactor : mMinSize;
|
||||||
if (mMinSizeMergeFactor)
|
for (const auto& [refNum, ref] : refs)
|
||||||
minSize *= mMinSizeMergeFactor;
|
|
||||||
for (const auto& pair : refs)
|
|
||||||
{
|
{
|
||||||
const ESM::CellRef& ref = pair.second;
|
|
||||||
|
|
||||||
osg::Vec3f pos = ref.mPos.asVec3();
|
|
||||||
if (size < 1.f)
|
if (size < 1.f)
|
||||||
{
|
{
|
||||||
osg::Vec3f cellPos = pos / cellSize;
|
const osg::Vec3f cellPos = ref.mPosition / cellSize;
|
||||||
if ((minBound.x() > std::floor(minBound.x()) && cellPos.x() < minBound.x())
|
if ((minBound.x() > floorMinBound.x() && cellPos.x() < minBound.x())
|
||||||
|| (minBound.y() > std::floor(minBound.y()) && cellPos.y() < minBound.y())
|
|| (minBound.y() > floorMinBound.y() && cellPos.y() < minBound.y())
|
||||||
|| (maxBound.x() < std::ceil(maxBound.x()) && cellPos.x() >= maxBound.x())
|
|| (maxBound.x() < ceilMaxBound.x() && cellPos.x() >= maxBound.x())
|
||||||
|| (maxBound.y() < std::ceil(maxBound.y()) && cellPos.y() >= maxBound.y()))
|
|| (maxBound.y() < ceilMaxBound.y() && cellPos.y() >= maxBound.y()))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float dSqr = (viewPoint - pos).length2();
|
const float dSqr = (viewPoint - ref.mPosition).length2();
|
||||||
if (!activeGrid)
|
if (!activeGrid)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
||||||
SizeCache::iterator found = mSizeCache.find(pair.first);
|
SizeCache::iterator found = mSizeCache.find(refNum);
|
||||||
if (found != mSizeCache.end() && found->second < dSqr * minSize * minSize)
|
if (found != mSizeCache.end() && found->second < dSqr * minSize * minSize)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Misc::ResourceHelpers::isHiddenMarker(ref.mRefID))
|
if (Misc::ResourceHelpers::isHiddenMarker(ref.mRefId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int type = store.findStatic(ref.mRefID);
|
const int type = store.findStatic(ref.mRefId);
|
||||||
std::string model = getModel(type, ref.mRefID, store);
|
std::string model = getModel(type, ref.mRefId, store);
|
||||||
if (model.empty())
|
if (model.empty())
|
||||||
continue;
|
continue;
|
||||||
model = Misc::ResourceHelpers::correctMeshPath(model);
|
model = Misc::ResourceHelpers::correctMeshPath(model);
|
||||||
|
|
@ -651,11 +665,9 @@ namespace MWRender
|
||||||
model = found->second;
|
model = found->second;
|
||||||
else
|
else
|
||||||
model = mLODNameCache
|
model = mLODNameCache
|
||||||
.insert(found,
|
.emplace_hint(found, std::move(key),
|
||||||
{ key,
|
Misc::ResourceHelpers::getLODMeshName(world.getESMVersions()[refNum.mContentFile],
|
||||||
Misc::ResourceHelpers::getLODMeshName(
|
model, mSceneManager->getVFS(), lod))
|
||||||
world->getESMVersions()[ref.mRefNum.mContentFile], model,
|
|
||||||
mSceneManager->getVFS(), lod) })
|
|
||||||
->second;
|
->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -670,38 +682,39 @@ namespace MWRender
|
||||||
&& dynamic_cast<const osgAnimation::BasicAnimationManager*>(cnode->getUpdateCallback())))
|
&& dynamic_cast<const osgAnimation::BasicAnimationManager*>(cnode->getUpdateCallback())))
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
refnumSet->mRefnums.push_back(pair.first);
|
refnumSet->mRefnums.push_back(refNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
std::lock_guard<std::mutex> lock(mRefTrackerMutex);
|
||||||
if (getRefTracker().mDisabled.count(pair.first))
|
if (getRefTracker().mDisabled.count(refNum))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float radius2 = cnode->getBound().radius2() * ref.mScale * ref.mScale;
|
const float radius2 = cnode->getBound().radius2() * ref.mScale * ref.mScale;
|
||||||
if (radius2 < dSqr * minSize * minSize && !activeGrid)
|
if (radius2 < dSqr * minSize * minSize && !activeGrid)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
std::lock_guard<std::mutex> lock(mSizeCacheMutex);
|
||||||
mSizeCache[pair.first] = radius2;
|
mSizeCache[refNum] = radius2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto emplaced = nodes.emplace(cnode, InstanceList());
|
const auto emplaced = nodes.emplace(std::move(cnode), InstanceList());
|
||||||
if (emplaced.second)
|
if (emplaced.second)
|
||||||
{
|
{
|
||||||
analyzeVisitor.mDistances = LODRange{ smallestDistanceToChunk, higherDistanceToChunk } / ref.mScale;
|
analyzeVisitor.mDistances = LODRange{ smallestDistanceToChunk, higherDistanceToChunk } / ref.mScale;
|
||||||
const_cast<osg::Node*>(cnode.get())
|
const osg::Node* const nodePtr = emplaced.first->first.get();
|
||||||
->accept(
|
// const-trickery required because there is no const version of NodeVisitor
|
||||||
analyzeVisitor); // const-trickery required because there is no const version of NodeVisitor
|
const_cast<osg::Node*>(nodePtr)->accept(analyzeVisitor);
|
||||||
emplaced.first->second.mAnalyzeResult = analyzeVisitor.retrieveResult();
|
emplaced.first->second.mAnalyzeResult = analyzeVisitor.retrieveResult();
|
||||||
emplaced.first->second.mNeedCompile = compile && cnode->referenceCount() <= 3;
|
emplaced.first->second.mNeedCompile = compile && nodePtr->referenceCount() <= 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
analyzeVisitor.addInstance(emplaced.first->second.mAnalyzeResult);
|
analyzeVisitor.addInstance(emplaced.first->second.mAnalyzeResult);
|
||||||
emplaced.first->second.mInstances.push_back(&ref);
|
emplaced.first->second.mInstances.push_back(&ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const osg::Vec3f worldCenter = osg::Vec3f(center.x(), center.y(), 0) * getCellSize(mWorldspace);
|
||||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
osg::ref_ptr<osg::Group> mergeGroup = new osg::Group;
|
osg::ref_ptr<osg::Group> mergeGroup = new osg::Group;
|
||||||
osg::ref_ptr<Resource::TemplateMultiRef> templateRefs = new Resource::TemplateMultiRef;
|
osg::ref_ptr<Resource::TemplateMultiRef> templateRefs = new Resource::TemplateMultiRef;
|
||||||
|
|
@ -714,32 +727,30 @@ namespace MWRender
|
||||||
|
|
||||||
const AnalyzeVisitor::Result& analyzeResult = pair.second.mAnalyzeResult;
|
const AnalyzeVisitor::Result& analyzeResult = pair.second.mAnalyzeResult;
|
||||||
|
|
||||||
float mergeCost = analyzeResult.mNumVerts * size;
|
const float mergeCost = analyzeResult.mNumVerts * size;
|
||||||
float mergeBenefit = analyzeVisitor.getMergeBenefit(analyzeResult) * mMergeFactor;
|
const float mergeBenefit = analyzeVisitor.getMergeBenefit(analyzeResult) * mMergeFactor;
|
||||||
bool merge = mergeBenefit > mergeCost;
|
const bool merge = mergeBenefit > mergeCost;
|
||||||
|
|
||||||
float minSizeMerged = mMinSize;
|
const float factor2
|
||||||
float factor2 = mergeBenefit > 0 ? std::min(1.f, mergeCost * mMinSizeCostMultiplier / mergeBenefit) : 1;
|
= mergeBenefit > 0 ? std::min(1.f, mergeCost * mMinSizeCostMultiplier / mergeBenefit) : 1;
|
||||||
float minSizeMergeFactor2 = (1 - factor2) * mMinSizeMergeFactor + factor2;
|
const float minSizeMergeFactor2 = (1 - factor2) * mMinSizeMergeFactor + factor2;
|
||||||
if (minSizeMergeFactor2 > 0)
|
const float minSizeMerged = minSizeMergeFactor2 > 0 ? mMinSize * minSizeMergeFactor2 : mMinSize;
|
||||||
minSizeMerged *= minSizeMergeFactor2;
|
|
||||||
|
|
||||||
unsigned int numinstances = 0;
|
unsigned int numinstances = 0;
|
||||||
for (auto cref : pair.second.mInstances)
|
for (const PagedCellRef* refPtr : pair.second.mInstances)
|
||||||
{
|
{
|
||||||
const ESM::CellRef& ref = *cref;
|
const PagedCellRef& ref = *refPtr;
|
||||||
osg::Vec3f pos = ref.mPos.asVec3();
|
|
||||||
|
|
||||||
if (!activeGrid && minSizeMerged != minSize
|
if (!activeGrid && minSizeMerged != minSize
|
||||||
&& cnode->getBound().radius2() * cref->mScale * cref->mScale
|
&& cnode->getBound().radius2() * ref.mScale * ref.mScale
|
||||||
< (viewPoint - pos).length2() * minSizeMerged * minSizeMerged)
|
< (viewPoint - ref.mPosition).length2() * minSizeMerged * minSizeMerged)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
osg::Vec3f nodePos = pos - worldCenter;
|
const osg::Vec3f nodePos = ref.mPosition - worldCenter;
|
||||||
osg::Quat nodeAttitude = osg::Quat(ref.mPos.rot[2], osg::Vec3f(0, 0, -1))
|
const osg::Quat nodeAttitude = osg::Quat(ref.mRotation.z(), osg::Vec3f(0, 0, -1))
|
||||||
* osg::Quat(ref.mPos.rot[1], osg::Vec3f(0, -1, 0))
|
* osg::Quat(ref.mRotation.y(), osg::Vec3f(0, -1, 0))
|
||||||
* osg::Quat(ref.mPos.rot[0], osg::Vec3f(-1, 0, 0));
|
* osg::Quat(ref.mRotation.x(), osg::Vec3f(-1, 0, 0));
|
||||||
osg::Vec3f nodeScale = osg::Vec3f(ref.mScale, ref.mScale, ref.mScale);
|
const osg::Vec3f nodeScale(ref.mScale, ref.mScale, ref.mScale);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> trans;
|
osg::ref_ptr<osg::Group> trans;
|
||||||
if (merge)
|
if (merge)
|
||||||
|
|
@ -792,7 +803,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Group* attachTo = merge ? mergeGroup : group;
|
osg::Group* const attachTo = merge ? mergeGroup : group;
|
||||||
attachTo->addChild(trans);
|
attachTo->addChild(trans);
|
||||||
++numinstances;
|
++numinstances;
|
||||||
}
|
}
|
||||||
|
|
@ -813,6 +824,8 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const osg::Vec3f relativeViewPoint = viewPoint - worldCenter;
|
||||||
|
|
||||||
if (mergeGroup->getNumChildren())
|
if (mergeGroup->getNumChildren())
|
||||||
{
|
{
|
||||||
SceneUtil::Optimizer optimizer;
|
SceneUtil::Optimizer optimizer;
|
||||||
|
|
@ -822,7 +835,7 @@ namespace MWRender
|
||||||
optimizer.setMergeAlphaBlending(true);
|
optimizer.setMergeAlphaBlending(true);
|
||||||
}
|
}
|
||||||
optimizer.setIsOperationPermissibleForObjectCallback(new CanOptimizeCallback);
|
optimizer.setIsOperationPermissibleForObjectCallback(new CanOptimizeCallback);
|
||||||
unsigned int options = SceneUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS
|
const unsigned int options = SceneUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS
|
||||||
| SceneUtil::Optimizer::REMOVE_REDUNDANT_NODES | SceneUtil::Optimizer::MERGE_GEOMETRY;
|
| SceneUtil::Optimizer::REMOVE_REDUNDANT_NODES | SceneUtil::Optimizer::MERGE_GEOMETRY;
|
||||||
|
|
||||||
optimizer.optimize(mergeGroup, options);
|
optimizer.optimize(mergeGroup, options);
|
||||||
|
|
@ -841,7 +854,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ico = mSceneManager->getIncrementalCompileOperation();
|
osgUtil::IncrementalCompileOperation* const ico = mSceneManager->getIncrementalCompileOperation();
|
||||||
if (!stateToCompile.empty() && ico)
|
if (!stateToCompile.empty() && ico)
|
||||||
{
|
{
|
||||||
auto compileSet = new osgUtil::IncrementalCompileOperation::CompileSet(group);
|
auto compileSet = new osgUtil::IncrementalCompileOperation::CompileSet(group);
|
||||||
|
|
@ -984,6 +997,8 @@ namespace MWRender
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
struct GetRefnumsFunctor
|
struct GetRefnumsFunctor
|
||||||
{
|
{
|
||||||
GetRefnumsFunctor(std::vector<ESM::RefNum>& output)
|
GetRefnumsFunctor(std::vector<ESM::RefNum>& output)
|
||||||
|
|
@ -995,7 +1010,7 @@ namespace MWRender
|
||||||
if (!std::get<2>(chunkId))
|
if (!std::get<2>(chunkId))
|
||||||
return;
|
return;
|
||||||
const osg::Vec2f& center = std::get<0>(chunkId);
|
const osg::Vec2f& center = std::get<0>(chunkId);
|
||||||
bool activeGrid = (center.x() > mActiveGrid.x() || center.y() > mActiveGrid.y()
|
const bool activeGrid = (center.x() > mActiveGrid.x() || center.y() > mActiveGrid.y()
|
||||||
|| center.x() < mActiveGrid.z() || center.y() < mActiveGrid.w());
|
|| center.x() < mActiveGrid.z() || center.y() < mActiveGrid.w());
|
||||||
if (!activeGrid)
|
if (!activeGrid)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1012,6 +1027,7 @@ namespace MWRender
|
||||||
osg::Vec4i mActiveGrid;
|
osg::Vec4i mActiveGrid;
|
||||||
std::vector<ESM::RefNum>& mOutput;
|
std::vector<ESM::RefNum>& mOutput;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectPaging::getPagedRefnums(const osg::Vec4i& activeGrid, std::vector<ESM::RefNum>& out)
|
void ObjectPaging::getPagedRefnums(const osg::Vec4i& activeGrid, std::vector<ESM::RefNum>& out)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef OPENMW_MWRENDER_OBJECTPAGING_H
|
#ifndef OPENMW_MWRENDER_OBJECTPAGING_H
|
||||||
#define OPENMW_MWRENDER_OBJECTPAGING_H
|
#define OPENMW_MWRENDER_OBJECTPAGING_H
|
||||||
|
|
||||||
#include <components/esm3/loadcell.hpp>
|
#include <components/esm3/refnum.hpp>
|
||||||
#include <components/resource/resourcemanager.hpp>
|
#include <components/resource/resourcemanager.hpp>
|
||||||
#include <components/terrain/quadtreeworld.hpp>
|
#include <components/terrain/quadtreeworld.hpp>
|
||||||
|
|
||||||
|
|
@ -11,15 +11,6 @@ namespace Resource
|
||||||
{
|
{
|
||||||
class SceneManager;
|
class SceneManager;
|
||||||
}
|
}
|
||||||
namespace MWWorld
|
|
||||||
{
|
|
||||||
class ESMStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ESM
|
|
||||||
{
|
|
||||||
class ReadersCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
@ -82,9 +73,6 @@ namespace MWRender
|
||||||
const RefTracker& getRefTracker() const { return mRefTracker; }
|
const RefTracker& getRefTracker() const { return mRefTracker; }
|
||||||
RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; }
|
RefTracker& getWritableRefTracker() { return mRefTrackerLocked ? mRefTrackerNew : mRefTracker; }
|
||||||
|
|
||||||
std::map<ESM::RefNum, ESM::CellRef> collectESM3References(
|
|
||||||
float size, const osg::Vec2i& startCell, ESM::ReadersCache& readers) const;
|
|
||||||
|
|
||||||
std::mutex mSizeCacheMutex;
|
std::mutex mSizeCacheMutex;
|
||||||
typedef std::map<ESM::RefNum, float> SizeCache;
|
typedef std::map<ESM::RefNum, float> SizeCache;
|
||||||
SizeCache mSizeCache;
|
SizeCache mSizeCache;
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,8 @@ namespace MWWorld
|
||||||
|
|
||||||
MWWorld::ESMStore& getStore() override { return mStore; }
|
MWWorld::ESMStore& getStore() override { return mStore; }
|
||||||
|
|
||||||
|
const MWWorld::ESMStore& getStore() const override { return mStore; }
|
||||||
|
|
||||||
const std::vector<int>& getESMVersions() const override;
|
const std::vector<int>& getESMVersions() const override;
|
||||||
|
|
||||||
LocalScripts& getLocalScripts() override;
|
LocalScripts& getLocalScripts() override;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue