Skip to content

Commit 7b992f9

Browse files
committed
Merge branch 'poisoncrank' into 'master'
Save interior fog bounds center to preserve rotation when expanding them Closes #7013 See merge request OpenMW/openmw!4466
2 parents 1dac165 + 4b93278 commit 7b992f9

File tree

6 files changed

+47
-48
lines changed

6 files changed

+47
-48
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
Bug #6992: Crossbow reloading doesn't look the same as in Morrowind
6969
Bug #6993: Shooting your last round of ammunition causes the attack animation to cancel
7070
Bug #7009: Falling actors teleport to the ground without receiving any damage on cell loading
71+
Bug #7013: Local map rendering in some cells is broken
7172
Bug #7034: Misc items defined in one content file are not treated as keys if another content file uses them as such
7273
Bug #7040: Incorrect rendering order for Rebirth's Stormfang
7374
Bug #7042: Weapon follow animations that immediately follow the hit animations cause multiple hits

apps/openmw/mwrender/localmap.cpp

+28-39
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ namespace MWRender
137137
fog->mBounds.mMinY = mBounds.yMin();
138138
fog->mBounds.mMaxY = mBounds.yMax();
139139
fog->mNorthMarkerAngle = mAngle;
140+
fog->mCenterX = mCenter.x();
141+
fog->mCenterY = mCenter.y();
140142

141143
fog->mFogTextures.reserve(segments.first * segments.second);
142144

@@ -145,15 +147,12 @@ namespace MWRender
145147
for (int y = 0; y < segments.second; ++y)
146148
{
147149
const MapSegment& segment = mInteriorSegments[std::make_pair(x, y)];
148-
149-
fog->mFogTextures.emplace_back();
150-
151-
// saving even if !segment.mHasFogState so we don't mess up the segmenting
152-
// plus, older openmw versions can't deal with empty images
153-
segment.saveFogOfWar(fog->mFogTextures.back());
154-
155-
fog->mFogTextures.back().mX = x;
156-
fog->mFogTextures.back().mY = y;
150+
if (!segment.mHasFogState)
151+
continue;
152+
ESM::FogTexture& texture = fog->mFogTextures.emplace_back();
153+
segment.saveFogOfWar(texture);
154+
texture.mX = x;
155+
texture.mY = y;
157156
}
158157
}
159158

@@ -332,31 +331,28 @@ namespace MWRender
332331

333332
float zMin = mBounds.zMin();
334333
float zMax = mBounds.zMax();
334+
mCenter = osg::Vec2f(mBounds.center().x(), mBounds.center().y());
335335

336336
// If there is fog state in the CellStore (e.g. when it came from a savegame) we need to do some checks
337337
// to see if this state is still valid.
338338
// Both the cell bounds and the NorthMarker rotation could be changed by the content files or exchanged models.
339339
// If they changed by too much then parts of the interior might not be covered by the map anymore.
340340
// The following code detects this, and discards the CellStore's fog state if it needs to.
341-
std::vector<std::pair<int, int>> segmentMappings;
342-
if (cell->getFog())
341+
int xOffset = 0;
342+
int yOffset = 0;
343+
if (const ESM::FogState* fog = cell->getFog())
343344
{
344-
ESM::FogState* fog = cell->getFog();
345-
346345
if (std::abs(mAngle - fog->mNorthMarkerAngle) < osg::DegreesToRadians(5.f))
347346
{
348347
// Expand mBounds so the saved textures fit the same grid
349-
int xOffset = 0;
350-
int yOffset = 0;
351348
if (fog->mBounds.mMinX < mBounds.xMin())
352349
{
353350
mBounds.xMin() = fog->mBounds.mMinX;
354351
}
355352
else if (fog->mBounds.mMinX > mBounds.xMin())
356353
{
357354
float diff = fog->mBounds.mMinX - mBounds.xMin();
358-
xOffset += diff / mMapWorldSize;
359-
xOffset++;
355+
xOffset = std::ceil(diff / mMapWorldSize);
360356
mBounds.xMin() = fog->mBounds.mMinX - xOffset * mMapWorldSize;
361357
}
362358
if (fog->mBounds.mMinY < mBounds.yMin())
@@ -366,8 +362,7 @@ namespace MWRender
366362
else if (fog->mBounds.mMinY > mBounds.yMin())
367363
{
368364
float diff = fog->mBounds.mMinY - mBounds.yMin();
369-
yOffset += diff / mMapWorldSize;
370-
yOffset++;
365+
yOffset = std::ceil(diff / mMapWorldSize);
371366
mBounds.yMin() = fog->mBounds.mMinY - yOffset * mMapWorldSize;
372367
}
373368
if (fog->mBounds.mMaxX > mBounds.xMax())
@@ -378,22 +373,14 @@ namespace MWRender
378373
if (xOffset != 0 || yOffset != 0)
379374
Log(Debug::Warning) << "Warning: expanding fog by " << xOffset << ", " << yOffset;
380375

381-
const auto& textures = fog->mFogTextures;
382-
segmentMappings.reserve(textures.size());
383-
osg::BoundingBox savedBounds{ fog->mBounds.mMinX, fog->mBounds.mMinY, 0, fog->mBounds.mMaxX,
384-
fog->mBounds.mMaxY, 0 };
385-
auto segments = divideIntoSegments(savedBounds, mMapWorldSize);
386-
for (int x = 0; x < segments.first; ++x)
387-
for (int y = 0; y < segments.second; ++y)
388-
segmentMappings.emplace_back(std::make_pair(x + xOffset, y + yOffset));
389-
390376
mAngle = fog->mNorthMarkerAngle;
377+
mCenter.x() = fog->mCenterX;
378+
mCenter.y() = fog->mCenterY;
391379
}
392380
}
393381

394382
osg::Vec2f min(mBounds.xMin(), mBounds.yMin());
395383

396-
osg::Vec2f center(mBounds.center().x(), mBounds.center().y());
397384
osg::Quat cameraOrient(mAngle, osg::Vec3d(0, 0, -1));
398385

399386
auto segments = divideIntoSegments(mBounds, mMapWorldSize);
@@ -404,10 +391,10 @@ namespace MWRender
404391
osg::Vec2f start = min + osg::Vec2f(mMapWorldSize * x, mMapWorldSize * y);
405392
osg::Vec2f newcenter = start + osg::Vec2f(mMapWorldSize / 2.f, mMapWorldSize / 2.f);
406393

407-
osg::Vec2f a = newcenter - center;
394+
osg::Vec2f a = newcenter - mCenter;
408395
osg::Vec3f rotatedCenter = cameraOrient * (osg::Vec3f(a.x(), a.y(), 0));
409396

410-
osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + center;
397+
osg::Vec2f pos = osg::Vec2f(rotatedCenter.x(), rotatedCenter.y()) + mCenter;
411398

412399
setupRenderToTexture(x, y, pos.x(), pos.y(), osg::Vec3f(north.x(), north.y(), 0.f), zMin, zMax);
413400

@@ -416,14 +403,16 @@ namespace MWRender
416403
if (!segment.mFogOfWarImage)
417404
{
418405
bool loaded = false;
419-
for (size_t index{}; index < segmentMappings.size(); index++)
406+
if (const ESM::FogState* fog = cell->getFog())
420407
{
421-
if (segmentMappings[index] == coords)
408+
auto match = std::find_if(
409+
fog->mFogTextures.begin(), fog->mFogTextures.end(), [&](const ESM::FogTexture& texture) {
410+
return texture.mX == x - xOffset && texture.mY == y - yOffset;
411+
});
412+
if (match != fog->mFogTextures.end())
422413
{
423-
ESM::FogState* fog = cell->getFog();
424-
segment.loadFogOfWar(fog->mFogTextures[index]);
414+
segment.loadFogOfWar(*match);
425415
loaded = true;
426-
break;
427416
}
428417
}
429418
if (!loaded)
@@ -435,7 +424,7 @@ namespace MWRender
435424

436425
void LocalMap::worldToInteriorMapPosition(osg::Vec2f pos, float& nX, float& nY, int& x, int& y)
437426
{
438-
pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), mAngle);
427+
pos = rotatePoint(pos, mCenter, mAngle);
439428

440429
osg::Vec2f min(mBounds.xMin(), mBounds.yMin());
441430

@@ -451,7 +440,7 @@ namespace MWRender
451440
osg::Vec2f min(mBounds.xMin(), mBounds.yMin());
452441
osg::Vec2f pos(mMapWorldSize * (nX + x) + min.x(), mMapWorldSize * (1.0f - nY + y) + min.y());
453442

454-
pos = rotatePoint(pos, osg::Vec2f(mBounds.center().x(), mBounds.center().y()), -mAngle);
443+
pos = rotatePoint(pos, mCenter, -mAngle);
455444
return pos;
456445
}
457446

@@ -590,7 +579,7 @@ namespace MWRender
590579
MyGUI::IntRect LocalMap::getInteriorGrid() const
591580
{
592581
auto segments = divideIntoSegments(mBounds, mMapWorldSize);
593-
return { 0, 0, segments.first - 1, segments.second - 1 };
582+
return { -1, -1, segments.first, segments.second };
594583
}
595584

596585
void LocalMap::MapSegment::createFogOfWarTexture()

apps/openmw/mwrender/localmap.hpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ namespace MWRender
108108
typedef std::vector<osg::ref_ptr<LocalMapRenderToTexture>> RTTVector;
109109
RTTVector mLocalMapRTTs;
110110

111-
typedef std::set<std::pair<int, int>> Grid;
112-
Grid mCurrentGrid;
113-
114111
enum NeighbourCellFlag : std::uint8_t
115112
{
116113
NeighbourCellTopLeft = 1,
@@ -160,8 +157,9 @@ namespace MWRender
160157
void setupRenderToTexture(
161158
int segment_x, int segment_y, float left, float top, const osg::Vec3d& upVector, float zmin, float zmax);
162159

163-
bool mInterior;
164160
osg::BoundingBox mBounds;
161+
osg::Vec2f mCenter;
162+
bool mInterior;
165163

166164
std::uint8_t getExteriorNeighbourFlags(int cellX, int cellY) const;
167165
};

components/esm3/fogstate.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ namespace ESM
6161
if (esm.isNextSub("BOUN"))
6262
esm.getHT(mBounds.mMinX, mBounds.mMinY, mBounds.mMaxX, mBounds.mMaxY);
6363
esm.getHNOT(mNorthMarkerAngle, "ANGL");
64+
if (!esm.getHNOT("CNTR", mCenterX, mCenterY))
65+
{
66+
mCenterX = (mBounds.mMinX + mBounds.mMaxX) / 2;
67+
mCenterY = (mBounds.mMinY + mBounds.mMaxY) / 2;
68+
}
6469
const FormatVersion dataFormat = esm.getFormatVersion();
6570
while (esm.isNextSub("FTEX"))
6671
{
@@ -87,13 +92,17 @@ namespace ESM
8792
{
8893
esm.writeHNT("BOUN", mBounds);
8994
esm.writeHNT("ANGL", mNorthMarkerAngle);
95+
esm.startSubRecord("CNTR");
96+
esm.writeT(mCenterX);
97+
esm.writeT(mCenterY);
98+
esm.endRecord("CNTR");
9099
}
91-
for (std::vector<FogTexture>::const_iterator it = mFogTextures.begin(); it != mFogTextures.end(); ++it)
100+
for (const FogTexture& texture : mFogTextures)
92101
{
93102
esm.startSubRecord("FTEX");
94-
esm.writeT(it->mX);
95-
esm.writeT(it->mY);
96-
esm.write(it->mImageData.data(), it->mImageData.size());
103+
esm.writeT(texture.mX);
104+
esm.writeT(texture.mY);
105+
esm.write(texture.mImageData.data(), texture.mImageData.size());
97106
esm.endRecord("FTEX");
98107
}
99108
}

components/esm3/fogstate.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ namespace ESM
2828
float mMaxX;
2929
float mMaxY;
3030
} mBounds;
31+
float mCenterX;
32+
float mCenterY;
3133

3234
std::vector<FogTexture> mFogTextures;
3335

components/esm3/formatversion.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace ESM
2828
inline constexpr FormatVersion MaxOldCountFormatVersion = 30;
2929
inline constexpr FormatVersion MaxActiveSpellTypeVersion = 31;
3030
inline constexpr FormatVersion MaxPlayerBeforeCellDataFormatVersion = 32;
31-
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 33;
31+
inline constexpr FormatVersion CurrentSaveGameFormatVersion = 34;
3232

3333
inline constexpr FormatVersion MinSupportedSaveGameFormatVersion = 5;
3434
inline constexpr FormatVersion OpenMW0_48SaveGameFormatVersion = 21;

0 commit comments

Comments
 (0)