diff --git a/apps/openmw_test_suite/esmterrain/testgridsampling.cpp b/apps/openmw_test_suite/esmterrain/testgridsampling.cpp index 048c3f9fc8..5695cf1a54 100644 --- a/apps/openmw_test_suite/esmterrain/testgridsampling.cpp +++ b/apps/openmw_test_suite/esmterrain/testgridsampling.cpp @@ -430,8 +430,8 @@ namespace ESMTerrain EXPECT_THAT(samples, ElementsAre( // CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 7, .mSrcCol = 0, .mDstRow = 0, .mDstCol = 0 }, - CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 1, .mDstCol = 0 }, CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 7, .mSrcCol = 1, .mDstRow = 0, .mDstCol = 1 }, + CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 1, .mDstCol = 0 }, CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 1, .mDstCol = 1 })); } @@ -468,23 +468,23 @@ namespace ESMTerrain CellSample{ .mCellX = 0, .mCellY = -2, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 4, .mDstCol = 0 }, CellSample{ .mCellX = -2, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 0, .mDstCol = 1 }, CellSample{ .mCellX = -2, .mCellY = -1, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 1, .mDstCol = 1 }, - CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 2, .mDstCol = 1 }, - CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 3, .mDstCol = 1 }, - CellSample{ .mCellX = 0, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 4, .mDstCol = 1 }, CellSample{ .mCellX = -2, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 0, .mDstCol = 2 }, CellSample{ .mCellX = -2, .mCellY = -1, .mSrcRow = 1, .mSrcCol = 1, .mDstRow = 1, .mDstCol = 2 }, + CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 2, .mDstCol = 1 }, + CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 3, .mDstCol = 1 }, CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 2, .mDstCol = 2 }, CellSample{ .mCellX = -1, .mCellY = -1, .mSrcRow = 1, .mSrcCol = 1, .mDstRow = 3, .mDstCol = 2 }, + CellSample{ .mCellX = 0, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 4, .mDstCol = 1 }, CellSample{ .mCellX = 0, .mCellY = -1, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 4, .mDstCol = 2 }, CellSample{ .mCellX = -2, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 0, .mDstCol = 3 }, CellSample{ .mCellX = -2, .mCellY = 0, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 1, .mDstCol = 3 }, - CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 2, .mDstCol = 3 }, - CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 3, .mDstCol = 3 }, - CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 4, .mDstCol = 3 }, CellSample{ .mCellX = -2, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 0, .mDstCol = 4 }, CellSample{ .mCellX = -2, .mCellY = 0, .mSrcRow = 1, .mSrcCol = 1, .mDstRow = 1, .mDstCol = 4 }, + CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 2, .mDstCol = 3 }, + CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 1, .mSrcCol = 0, .mDstRow = 3, .mDstCol = 3 }, CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 2, .mDstCol = 4 }, CellSample{ .mCellX = -1, .mCellY = 0, .mSrcRow = 1, .mSrcCol = 1, .mDstRow = 3, .mDstCol = 4 }, + CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 0, .mDstRow = 4, .mDstCol = 3 }, CellSample{ .mCellX = 0, .mCellY = 0, .mSrcRow = 0, .mSrcCol = 1, .mDstRow = 4, .mDstCol = 4 })); } } diff --git a/components/esmterrain/gridsampling.hpp b/components/esmterrain/gridsampling.hpp index be37ad1223..e71dfc5152 100644 --- a/components/esmterrain/gridsampling.hpp +++ b/components/esmterrain/gridsampling.hpp @@ -132,26 +132,16 @@ namespace ESMTerrain return static_cast(textureSize * size) + 1; } - inline void adjustTextureCoordinates(int textureSize, int& cellX, int& cellY, int& x, int& y) + inline std::pair getBlendmapLocalRange( + int cell, int minCell, int textureSize, int min, int max) { - --x; - if (x < 0) - { - --cellX; - x += textureSize; - } - - while (x >= textureSize) - { - ++cellX; - x -= textureSize; - } - - while (y >= textureSize) - { - ++cellY; - y -= textureSize; - } + const int cellMin = (cell - minCell) * textureSize; + const int cellMax = cellMin + textureSize - 1; + const std::size_t begin = min > cellMin ? min - cellMin : 0; + const std::size_t end = cellMax < max ? textureSize : max - cellMin + 1; + assert(begin < end); + assert(static_cast(end) <= textureSize); + return { begin, end }; } template @@ -163,32 +153,52 @@ namespace ESMTerrain if (textureSize <= 0) throw std::invalid_argument("Invalid texture size for blendmap sampling: " + std::to_string(textureSize)); - const int beginCellX = static_cast(std::floor(minX)); - const int beginCellY = static_cast(std::floor(minY)); - const int beginRow = static_cast((minX - beginCellX) * (textureSize + 1)); - const int beginCol = static_cast((minY - beginCellY) * (textureSize + 1)); - const int blendmapSize = getBlendmapSize(size, textureSize); + int minCellX = static_cast(std::floor(minX)); + const int minCellY = static_cast(std::floor(minY)); + int minRow = static_cast((minX - minCellX) * (textureSize + 1)) - 1; + const int minCol = static_cast((minY - minCellY) * (textureSize + 1)); - for (int y = 0; y < blendmapSize; y++) + if (minRow < 0) { - for (int x = 0; x < blendmapSize; x++) + --minCellX; + minRow += textureSize; + } + + const int maxRow = minRow + static_cast(textureSize * size); + const int maxCol = minCol + static_cast(textureSize * size); + const int maxCellX = minCellX + maxRow / textureSize; + const int maxCellY = minCellY + maxCol / textureSize; + + std::size_t baseDstCol = 0; + for (int cellY = minCellY; cellY <= maxCellY; ++cellY) + { + std::size_t baseDstRow = 0; + + const auto [localBeginCol, localEndCol] + = getBlendmapLocalRange(cellY, minCellY, textureSize, minCol, maxCol); + const std::size_t colCount = localEndCol - localBeginCol; + + for (int cellX = minCellX; cellX <= maxCellX; ++cellX) { - int cellX = beginCellX; - int cellY = beginCellY; - int srcX = x + beginRow; - int srcY = y + beginCol; - - adjustTextureCoordinates(textureSize, cellX, cellY, srcX, srcY); - - f(CellSample{ - .mCellX = cellX, - .mCellY = cellY, - .mSrcRow = static_cast(srcX), - .mSrcCol = static_cast(srcY), - .mDstRow = static_cast(x), - .mDstCol = static_cast(y), - }); + const auto [localBeginRow, localEndRow] + = getBlendmapLocalRange(cellX, minCellX, textureSize, minRow, maxRow); + const std::size_t rowCount = localEndRow - localBeginRow; + + for (std::size_t col = 0; col < colCount; ++col) + for (std::size_t row = 0; row < rowCount; ++row) + f(CellSample{ + .mCellX = cellX, + .mCellY = cellY, + .mSrcRow = localBeginRow + row, + .mSrcCol = localBeginCol + col, + .mDstRow = baseDstRow + row, + .mDstCol = baseDstCol + col, + }); + + baseDstRow += rowCount; } + + baseDstCol += colCount; } } }