mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-09-27 14:10:46 -04:00
Merge branch 'fix_local_map_update' into 'master'
Update cell local map on different neighbour cells (#7140) See merge request OpenMW/openmw!3012
This commit is contained in:
commit
242ac21b38
@ -61,9 +61,6 @@ namespace MWRender
|
|||||||
|
|
||||||
void setDefaults(osg::Camera* camera) override;
|
void setDefaults(osg::Camera* camera) override;
|
||||||
|
|
||||||
bool isActive() { return mActive; }
|
|
||||||
void setIsActive(bool active) { mActive = active; }
|
|
||||||
|
|
||||||
osg::Node* mSceneRoot;
|
osg::Node* mSceneRoot;
|
||||||
osg::Matrix mProjectionMatrix;
|
osg::Matrix mProjectionMatrix;
|
||||||
osg::Matrix mViewMatrix;
|
osg::Matrix mViewMatrix;
|
||||||
@ -182,29 +179,28 @@ namespace MWRender
|
|||||||
|
|
||||||
void LocalMap::requestMap(const MWWorld::CellStore* cell)
|
void LocalMap::requestMap(const MWWorld::CellStore* cell)
|
||||||
{
|
{
|
||||||
if (cell->isExterior())
|
if (!cell->isExterior())
|
||||||
{
|
{
|
||||||
int cellX = cell->getCell()->getGridX();
|
|
||||||
int cellY = cell->getCell()->getGridY();
|
|
||||||
|
|
||||||
MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)];
|
|
||||||
if (!segment.needUpdate)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
requestExteriorMap(cell);
|
|
||||||
segment.needUpdate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
requestInteriorMap(cell);
|
requestInteriorMap(cell);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cellX = cell->getCell()->getGridX();
|
||||||
|
int cellY = cell->getCell()->getGridY();
|
||||||
|
|
||||||
|
MapSegment& segment = mExteriorSegments[std::make_pair(cellX, cellY)];
|
||||||
|
const std::uint8_t neighbourFlags = getExteriorNeighbourFlags(cellX, cellY);
|
||||||
|
if ((segment.mLastRenderNeighbourFlags & neighbourFlags) == neighbourFlags)
|
||||||
|
return;
|
||||||
|
requestExteriorMap(cell, segment);
|
||||||
|
segment.mLastRenderNeighbourFlags = neighbourFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::addCell(MWWorld::CellStore* cell)
|
void LocalMap::addCell(MWWorld::CellStore* cell)
|
||||||
{
|
{
|
||||||
if (cell->isExterior())
|
if (cell->isExterior())
|
||||||
mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())].needUpdate
|
mExteriorSegments.emplace(
|
||||||
= true;
|
std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY()), MapSegment{});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::removeExteriorCell(int x, int y)
|
void LocalMap::removeExteriorCell(int x, int y)
|
||||||
@ -216,7 +212,9 @@ namespace MWRender
|
|||||||
{
|
{
|
||||||
saveFogOfWar(cell);
|
saveFogOfWar(cell);
|
||||||
|
|
||||||
if (!cell->isExterior())
|
if (cell->isExterior())
|
||||||
|
mExteriorSegments.erase({ cell->getCell()->getGridX(), cell->getCell()->getGridY() });
|
||||||
|
else
|
||||||
mInteriorSegments.clear();
|
mInteriorSegments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +243,7 @@ namespace MWRender
|
|||||||
auto it = mLocalMapRTTs.begin();
|
auto it = mLocalMapRTTs.begin();
|
||||||
while (it != mLocalMapRTTs.end())
|
while (it != mLocalMapRTTs.end())
|
||||||
{
|
{
|
||||||
if (!(*it)->isActive())
|
if (!(*it)->mActive)
|
||||||
{
|
{
|
||||||
mRoot->removeChild(*it);
|
mRoot->removeChild(*it);
|
||||||
it = mLocalMapRTTs.erase(it);
|
it = mLocalMapRTTs.erase(it);
|
||||||
@ -255,30 +253,27 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell)
|
void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell, MapSegment& segment)
|
||||||
{
|
{
|
||||||
mInterior = false;
|
mInterior = false;
|
||||||
|
|
||||||
int x = cell->getCell()->getGridX();
|
const int x = cell->getCell()->getGridX();
|
||||||
int y = cell->getCell()->getGridY();
|
const int y = cell->getCell()->getGridY();
|
||||||
|
|
||||||
osg::BoundingSphere bound = mSceneRoot->getBound();
|
osg::BoundingSphere bound = mSceneRoot->getBound();
|
||||||
float zmin = bound.center().z() - bound.radius();
|
float zmin = bound.center().z() - bound.radius();
|
||||||
float zmax = bound.center().z() + bound.radius();
|
float zmax = bound.center().z() + bound.radius();
|
||||||
|
|
||||||
setupRenderToTexture(cell->getCell()->getGridX(), cell->getCell()->getGridY(),
|
setupRenderToTexture(x, y, x * mMapWorldSize + mMapWorldSize / 2.f, y * mMapWorldSize + mMapWorldSize / 2.f,
|
||||||
x * mMapWorldSize + mMapWorldSize / 2.f, y * mMapWorldSize + mMapWorldSize / 2.f, osg::Vec3d(0, 1, 0), zmin,
|
osg::Vec3d(0, 1, 0), zmin, zmax);
|
||||||
zmax);
|
|
||||||
|
|
||||||
MapSegment& segment
|
if (segment.mFogOfWarImage != nullptr)
|
||||||
= mExteriorSegments[std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY())];
|
return;
|
||||||
if (!segment.mFogOfWarImage)
|
|
||||||
{
|
if (cell->getFog())
|
||||||
if (cell->getFog())
|
segment.loadFogOfWar(cell->getFog()->mFogTextures.back());
|
||||||
segment.loadFogOfWar(cell->getFog()->mFogTextures.back());
|
else
|
||||||
else
|
segment.initFogOfWar();
|
||||||
segment.initFogOfWar();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static osg::Vec2f getNorthVector(const MWWorld::CellStore* cell)
|
static osg::Vec2f getNorthVector(const MWWorld::CellStore* cell)
|
||||||
@ -476,7 +471,8 @@ namespace MWRender
|
|||||||
int texU = static_cast<int>((sFogOfWarResolution - 1) * nX);
|
int texU = static_cast<int>((sFogOfWarResolution - 1) * nX);
|
||||||
int texV = static_cast<int>((sFogOfWarResolution - 1) * nY);
|
int texV = static_cast<int>((sFogOfWarResolution - 1) * nY);
|
||||||
|
|
||||||
uint32_t clr = ((const uint32_t*)segment.mFogOfWarImage->data())[texV * sFogOfWarResolution + texU];
|
const std::uint32_t clr
|
||||||
|
= reinterpret_cast<const uint32_t*>(segment.mFogOfWarImage->data())[texV * sFogOfWarResolution + texU];
|
||||||
uint8_t alpha = (clr >> 24);
|
uint8_t alpha = (clr >> 24);
|
||||||
return alpha < 200;
|
return alpha < 200;
|
||||||
}
|
}
|
||||||
@ -544,7 +540,7 @@ namespace MWRender
|
|||||||
if (!segment.mFogOfWarImage || !segment.mMapTexture)
|
if (!segment.mFogOfWarImage || !segment.mMapTexture)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32_t* data = (uint32_t*)segment.mFogOfWarImage->data();
|
std::uint32_t* data = reinterpret_cast<std::uint32_t*>(segment.mFogOfWarImage->data());
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (int texV = 0; texV < sFogOfWarResolution; ++texV)
|
for (int texV = 0; texV < sFogOfWarResolution; ++texV)
|
||||||
{
|
{
|
||||||
@ -553,10 +549,9 @@ namespace MWRender
|
|||||||
float sqrDist = square((texU + mx * (sFogOfWarResolution - 1)) - u * (sFogOfWarResolution - 1))
|
float sqrDist = square((texU + mx * (sFogOfWarResolution - 1)) - u * (sFogOfWarResolution - 1))
|
||||||
+ square((texV + my * (sFogOfWarResolution - 1)) - v * (sFogOfWarResolution - 1));
|
+ square((texV + my * (sFogOfWarResolution - 1)) - v * (sFogOfWarResolution - 1));
|
||||||
|
|
||||||
uint32_t clr = *(uint32_t*)data;
|
const std::uint8_t alpha = std::min<std::uint8_t>(
|
||||||
uint8_t alpha = (clr >> 24);
|
*data >> 24, std::clamp(sqrDist / sqrExploreRadius, 0.f, 1.f) * 255);
|
||||||
alpha = std::min(alpha, (uint8_t)(std::clamp(sqrDist / sqrExploreRadius, 0.f, 1.f) * 255));
|
std::uint32_t val = static_cast<std::uint32_t>(alpha << 24);
|
||||||
uint32_t val = (uint32_t)(alpha << 24);
|
|
||||||
if (*data != val)
|
if (*data != val)
|
||||||
{
|
{
|
||||||
*data = val;
|
*data = val;
|
||||||
@ -576,9 +571,23 @@ namespace MWRender
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalMap::MapSegment::MapSegment()
|
std::uint8_t LocalMap::getExteriorNeighbourFlags(int cellX, int cellY) const
|
||||||
: mHasFogState(false)
|
|
||||||
{
|
{
|
||||||
|
constexpr std::tuple<NeighbourCellFlag, int, int> flags[] = {
|
||||||
|
{ NeighbourCellTopLeft, -1, -1 },
|
||||||
|
{ NeighbourCellTopCenter, 0, -1 },
|
||||||
|
{ NeighbourCellTopRight, 1, -1 },
|
||||||
|
{ NeighbourCellMiddleLeft, -1, 0 },
|
||||||
|
{ NeighbourCellMiddleRight, 1, 0 },
|
||||||
|
{ NeighbourCellBottomLeft, -1, 1 },
|
||||||
|
{ NeighbourCellBottomCenter, 0, 1 },
|
||||||
|
{ NeighbourCellBottomRight, 1, 1 },
|
||||||
|
};
|
||||||
|
std::uint8_t result = 0;
|
||||||
|
for (const auto& [flag, dx, dy] : flags)
|
||||||
|
if (mExteriorSegments.contains(std::pair(cellX + dx, cellY + dy)))
|
||||||
|
result |= flag;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMap::MapSegment::createFogOfWarTexture()
|
void LocalMap::MapSegment::createFogOfWarTexture()
|
||||||
@ -768,13 +777,10 @@ namespace MWRender
|
|||||||
|
|
||||||
void CameraLocalUpdateCallback::operator()(LocalMapRenderToTexture* node, osg::NodeVisitor* nv)
|
void CameraLocalUpdateCallback::operator()(LocalMapRenderToTexture* node, osg::NodeVisitor* nv)
|
||||||
{
|
{
|
||||||
if (!node->isActive())
|
if (!node->mActive)
|
||||||
node->setNodeMask(0);
|
node->setNodeMask(0);
|
||||||
|
|
||||||
if (node->isActive())
|
node->mActive = false;
|
||||||
{
|
|
||||||
node->setIsActive(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rtt-nodes do not forward update traversal to their cameras so we can traverse safely.
|
// Rtt-nodes do not forward update traversal to their cameras so we can traverse safely.
|
||||||
// Traverse in case there are nested callbacks.
|
// Traverse in case there are nested callbacks.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef GAME_RENDER_LOCALMAP_H
|
#ifndef GAME_RENDER_LOCALMAP_H
|
||||||
#define GAME_RENDER_LOCALMAP_H
|
#define GAME_RENDER_LOCALMAP_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -107,23 +108,30 @@ namespace MWRender
|
|||||||
typedef std::set<std::pair<int, int>> Grid;
|
typedef std::set<std::pair<int, int>> Grid;
|
||||||
Grid mCurrentGrid;
|
Grid mCurrentGrid;
|
||||||
|
|
||||||
|
enum NeighbourCellFlag : std::uint8_t
|
||||||
|
{
|
||||||
|
NeighbourCellTopLeft = 1,
|
||||||
|
NeighbourCellTopCenter = 1 << 1,
|
||||||
|
NeighbourCellTopRight = 1 << 2,
|
||||||
|
NeighbourCellMiddleLeft = 1 << 3,
|
||||||
|
NeighbourCellMiddleRight = 1 << 4,
|
||||||
|
NeighbourCellBottomLeft = 1 << 5,
|
||||||
|
NeighbourCellBottomCenter = 1 << 6,
|
||||||
|
NeighbourCellBottomRight = 1 << 7,
|
||||||
|
};
|
||||||
|
|
||||||
struct MapSegment
|
struct MapSegment
|
||||||
{
|
{
|
||||||
MapSegment();
|
|
||||||
~MapSegment() = default;
|
|
||||||
|
|
||||||
void initFogOfWar();
|
void initFogOfWar();
|
||||||
void loadFogOfWar(const ESM::FogTexture& fog);
|
void loadFogOfWar(const ESM::FogTexture& fog);
|
||||||
void saveFogOfWar(ESM::FogTexture& fog) const;
|
void saveFogOfWar(ESM::FogTexture& fog) const;
|
||||||
void createFogOfWarTexture();
|
void createFogOfWarTexture();
|
||||||
|
|
||||||
|
std::uint8_t mLastRenderNeighbourFlags = 0;
|
||||||
|
bool mHasFogState = false;
|
||||||
osg::ref_ptr<osg::Texture2D> mMapTexture;
|
osg::ref_ptr<osg::Texture2D> mMapTexture;
|
||||||
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
|
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
|
||||||
osg::ref_ptr<osg::Image> mFogOfWarImage;
|
osg::ref_ptr<osg::Image> mFogOfWarImage;
|
||||||
|
|
||||||
bool needUpdate = true;
|
|
||||||
|
|
||||||
bool mHasFogState;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::pair<int, int>, MapSegment> SegmentMap;
|
typedef std::map<std::pair<int, int>, MapSegment> SegmentMap;
|
||||||
@ -143,7 +151,7 @@ namespace MWRender
|
|||||||
float mAngle;
|
float mAngle;
|
||||||
const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle);
|
const osg::Vec2f rotatePoint(const osg::Vec2f& point, const osg::Vec2f& center, const float angle);
|
||||||
|
|
||||||
void requestExteriorMap(const MWWorld::CellStore* cell);
|
void requestExteriorMap(const MWWorld::CellStore* cell, MapSegment& segment);
|
||||||
void requestInteriorMap(const MWWorld::CellStore* cell);
|
void requestInteriorMap(const MWWorld::CellStore* cell);
|
||||||
|
|
||||||
void setupRenderToTexture(
|
void setupRenderToTexture(
|
||||||
@ -151,6 +159,8 @@ namespace MWRender
|
|||||||
|
|
||||||
bool mInterior;
|
bool mInterior;
|
||||||
osg::BoundingBox mBounds;
|
osg::BoundingBox mBounds;
|
||||||
|
|
||||||
|
std::uint8_t getExteriorNeighbourFlags(int cellX, int cellY) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user