mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 18:35:20 +00:00
Merge branch 'fix_esm4_terrain' into 'master'
Support terrain sample size greater than cell size (#7505) Closes #7505 See merge request OpenMW/openmw!3313
This commit is contained in:
commit
e4a6f70011
@ -67,6 +67,7 @@
|
||||
Bug #7450: Evading obstacles does not work for actors missing certain animations
|
||||
Bug #7459: Icons get stacked on the cursor when picking up multiple items simultaneously
|
||||
Bug #7472: Crash when enchanting last projectiles
|
||||
Bug #7505: Distant terrain does not support sample size greater than cell size
|
||||
Feature #3537: Shader-based water ripples
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #6447: Add LOD support to Object Paging
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "terrainstorage.hpp"
|
||||
|
||||
#include <components/esm3/loadltex.hpp>
|
||||
#include <components/esm3terrain/storage.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
#include <apps/opencs/model/world/data.hpp>
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esm3/loadltex.hpp>
|
||||
#include <components/esm3terrain/storage.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace CSMWorld
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <osg/Object>
|
||||
|
||||
#include <components/esm/util.hpp>
|
||||
#include <components/esm3terrain/storage.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
#include <components/resource/resourcemanager.hpp>
|
||||
|
||||
namespace ESM
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <components/esm3terrain/storage.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
|
@ -92,6 +92,8 @@ file(GLOB UNITTEST_SRC_FILES
|
||||
esm3/testinfoorder.cpp
|
||||
|
||||
nifosg/testnifloader.cpp
|
||||
|
||||
esmterrain/testgridsampling.cpp
|
||||
)
|
||||
|
||||
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
|
||||
|
366
apps/openmw_test_suite/esmterrain/testgridsampling.cpp
Normal file
366
apps/openmw_test_suite/esmterrain/testgridsampling.cpp
Normal file
@ -0,0 +1,366 @@
|
||||
#include <components/esmterrain/gridsampling.hpp>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace ESMTerrain
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using namespace testing;
|
||||
|
||||
struct Sample
|
||||
{
|
||||
std::size_t mCellX = 0;
|
||||
std::size_t mCellY = 0;
|
||||
std::size_t mLocalX = 0;
|
||||
std::size_t mLocalY = 0;
|
||||
std::size_t mVertexX = 0;
|
||||
std::size_t mVertexY = 0;
|
||||
};
|
||||
|
||||
auto tie(const Sample& v)
|
||||
{
|
||||
return std::tie(v.mCellX, v.mCellY, v.mLocalX, v.mLocalY, v.mVertexX, v.mVertexY);
|
||||
}
|
||||
|
||||
bool operator==(const Sample& l, const Sample& r)
|
||||
{
|
||||
return tie(l) == tie(r);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Sample& v)
|
||||
{
|
||||
return stream << "Sample{.mCellX = " << v.mCellX << ", .mCellY = " << v.mCellY
|
||||
<< ", .mLocalX = " << v.mLocalX << ", .mLocalY = " << v.mLocalY
|
||||
<< ", .mVertexX = " << v.mVertexX << ", .mVertexY = " << v.mVertexY << "}";
|
||||
}
|
||||
|
||||
struct Collect
|
||||
{
|
||||
std::vector<Sample>& mSamples;
|
||||
|
||||
void operator()(std::size_t cellX, std::size_t cellY, std::size_t localX, std::size_t localY,
|
||||
std::size_t vertexX, std::size_t vertexY)
|
||||
{
|
||||
mSamples.push_back(Sample{
|
||||
.mCellX = cellX,
|
||||
.mCellY = cellY,
|
||||
.mLocalX = localX,
|
||||
.mLocalY = localY,
|
||||
.mVertexX = vertexX,
|
||||
.mVertexY = vertexY,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCellSizeLessThanTwo)
|
||||
{
|
||||
const std::size_t cellSize = 2;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, 0, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCellSizeMinusOneNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 4;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, 0, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportZeroSampleSize)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 0;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportSampleSizeNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 3;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, 0, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCountLessThanTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t distance = 2;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, distance, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, doesNotSupportCountMinusOneNotPowerOfTwo)
|
||||
{
|
||||
const std::size_t cellSize = 1;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t distance = 4;
|
||||
EXPECT_THROW(sampleCellGrid(cellSize, sampleSize, 0, 0, distance, [](auto...) {}), std::invalid_argument);
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeOneShouldProduceNumberOfSamplesEqualToCellSize)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, countShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginYAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginAndCountShouldLimitScope)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginAndCountShouldLimitScopeInTheMiddleOfCell)
|
||||
{
|
||||
const std::size_t cellSize = 5;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 1;
|
||||
const std::size_t distance = 2;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountLessThanCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 5;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 3;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 3, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 4, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountEqualToCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, beginXWithCountGreaterThanCellSizeShouldLimitScopeAcrossCellBorder)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 1;
|
||||
const std::size_t beginX = 1;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 5;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 3, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 1, .mVertexX = 3, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 3, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 0, .mVertexX = 4, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 1, .mVertexX = 4, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 2, .mCellY = 0, .mLocalX = 1, .mLocalY = 2, .mVertexX = 4, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 0, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 1, .mVertexX = 1, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 0, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 2, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 1, .mVertexX = 3, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 2, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 3, .mVertexY = 4 },
|
||||
Sample{ .mCellX = 2, .mCellY = 1, .mLocalX = 1, .mLocalY = 1, .mVertexX = 4, .mVertexY = 3 },
|
||||
Sample{ .mCellX = 2, .mCellY = 1, .mLocalX = 1, .mLocalY = 2, .mVertexX = 4, .mVertexY = 4 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThanOneShouldSkipPoints)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 2;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 3;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, shouldGroupByCell)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 2;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 5;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThanCellSizeShouldPickSinglePointPerCell)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 4;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 9;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 1, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 3, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 2, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 1, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 1, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 3, .mCellY = 1, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 0, .mCellY = 3, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 1, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 2 },
|
||||
Sample{ .mCellX = 3, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 2, .mVertexY = 2 }));
|
||||
}
|
||||
|
||||
TEST(ESMTerrainSampleCellGrid, sampleSizeGreaterThan2CellSizeShouldSkipCells)
|
||||
{
|
||||
const std::size_t cellSize = 3;
|
||||
const std::size_t sampleSize = 8;
|
||||
const std::size_t beginX = 0;
|
||||
const std::size_t beginY = 0;
|
||||
const std::size_t distance = 9;
|
||||
std::vector<Sample> samples;
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, Collect{ samples });
|
||||
EXPECT_THAT(samples,
|
||||
ElementsAre( //
|
||||
Sample{ .mCellX = 0, .mCellY = 0, .mLocalX = 0, .mLocalY = 0, .mVertexX = 0, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 3, .mCellY = 0, .mLocalX = 2, .mLocalY = 0, .mVertexX = 1, .mVertexY = 0 },
|
||||
Sample{ .mCellX = 0, .mCellY = 3, .mLocalX = 0, .mLocalY = 2, .mVertexX = 0, .mVertexY = 1 },
|
||||
Sample{ .mCellX = 3, .mCellY = 3, .mLocalX = 2, .mLocalY = 2, .mVertexX = 1, .mVertexY = 1 }));
|
||||
}
|
||||
}
|
||||
}
|
@ -145,7 +145,7 @@ add_component_dir (esm3
|
||||
infoorder timestamp
|
||||
)
|
||||
|
||||
add_component_dir (esm3terrain
|
||||
add_component_dir (esmterrain
|
||||
storage
|
||||
)
|
||||
|
||||
|
120
components/esmterrain/gridsampling.hpp
Normal file
120
components/esmterrain/gridsampling.hpp
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef OPENMW_COMPONENTS_ESMTERRAIN_GRIDSAMPLING_H
|
||||
#define OPENMW_COMPONENTS_ESMTERRAIN_GRIDSAMPLING_H
|
||||
|
||||
#include <components/misc/mathutil.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ESMTerrain
|
||||
{
|
||||
inline std::pair<std::size_t, std::size_t> toCellAndLocal(
|
||||
std::size_t begin, std::size_t global, std::size_t cellSize)
|
||||
{
|
||||
std::size_t cell = global / (cellSize - 1);
|
||||
std::size_t local = global & (cellSize - 2);
|
||||
if (global != begin && local == 0)
|
||||
{
|
||||
--cell;
|
||||
local = cellSize - 1;
|
||||
}
|
||||
return { cell, local };
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleGrid(
|
||||
std::size_t sampleSize, std::size_t beginX, std::size_t beginY, std::size_t endX, std::size_t endY, F&& f)
|
||||
{
|
||||
std::size_t vertY = 0;
|
||||
for (std::size_t y = beginY; y < endY; y += sampleSize)
|
||||
{
|
||||
std::size_t vertX = 0;
|
||||
for (std::size_t x = beginX; x < endX; x += sampleSize)
|
||||
f(x, y, vertX++, vertY);
|
||||
++vertY;
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleCellGridSimple(std::size_t cellSize, std::size_t sampleSize, std::size_t beginX, std::size_t beginY,
|
||||
std::size_t endX, std::size_t endY, F&& f)
|
||||
{
|
||||
assert(cellSize > 1);
|
||||
assert(Misc::isPowerOfTwo(cellSize - 1));
|
||||
assert(sampleSize != 0);
|
||||
|
||||
sampleGrid(sampleSize, beginX, beginY, endX, endY,
|
||||
[&](std::size_t globalX, std::size_t globalY, std::size_t vertX, std::size_t vertY) {
|
||||
const auto [cellX, x] = toCellAndLocal(beginX, globalX, cellSize);
|
||||
const auto [cellY, y] = toCellAndLocal(beginY, globalY, cellSize);
|
||||
f(cellX, cellY, x, y, vertX, vertY);
|
||||
});
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void sampleCellGrid(std::size_t cellSize, std::size_t sampleSize, std::size_t beginX, std::size_t beginY,
|
||||
std::size_t distance, F&& f)
|
||||
{
|
||||
if (cellSize < 2 || !Misc::isPowerOfTwo(cellSize - 1))
|
||||
throw std::invalid_argument("Invalid cell size for cell grid sampling: " + std::to_string(cellSize));
|
||||
|
||||
if (sampleSize == 0 || !Misc::isPowerOfTwo(sampleSize))
|
||||
throw std::invalid_argument("Invalid sample size for cell grid sampling: " + std::to_string(sampleSize));
|
||||
|
||||
if (distance < 2 || !Misc::isPowerOfTwo(distance - 1))
|
||||
throw std::invalid_argument("Invalid count for cell grid sampling: " + std::to_string(distance));
|
||||
|
||||
const std::size_t endX = beginX + distance;
|
||||
const std::size_t endY = beginY + distance;
|
||||
|
||||
if (distance < cellSize || sampleSize > cellSize - 1)
|
||||
return sampleCellGridSimple(cellSize, sampleSize, beginX, beginY, endX, endY, f);
|
||||
|
||||
const std::size_t beginCellX = beginX / (cellSize - 1);
|
||||
const std::size_t beginCellY = beginY / (cellSize - 1);
|
||||
const std::size_t endCellX = endX / (cellSize - 1);
|
||||
const std::size_t endCellY = endY / (cellSize - 1);
|
||||
|
||||
std::size_t baseVertY = 0;
|
||||
|
||||
for (std::size_t cellY = beginCellY; cellY < endCellY; ++cellY)
|
||||
{
|
||||
const std::size_t offsetY = cellY * (cellSize - 1);
|
||||
const std::size_t globalBeginY = offsetY <= beginY ? beginY : offsetY + sampleSize;
|
||||
const std::size_t globalEndY = endY <= offsetY + cellSize ? endY : offsetY + cellSize;
|
||||
|
||||
assert(globalBeginY < globalEndY);
|
||||
|
||||
std::size_t baseVertX = 0;
|
||||
std::size_t vertY = baseVertY;
|
||||
|
||||
for (std::size_t cellX = beginCellX; cellX < endCellX; ++cellX)
|
||||
{
|
||||
const std::size_t offsetX = cellX * (cellSize - 1);
|
||||
const std::size_t globalBeginX = offsetX <= beginX ? beginX : offsetX + sampleSize;
|
||||
const std::size_t globalEndX = endX <= offsetX + cellSize ? endX : offsetX + cellSize;
|
||||
|
||||
assert(globalBeginX < globalEndX);
|
||||
|
||||
vertY = baseVertY;
|
||||
std::size_t vertX = baseVertX;
|
||||
|
||||
sampleGrid(sampleSize, globalBeginX, globalBeginY, globalEndX, globalEndY,
|
||||
[&](std::size_t globalX, std::size_t globalY, std::size_t localVertX, std::size_t localVertY) {
|
||||
vertX = baseVertX + localVertX;
|
||||
vertY = baseVertY + localVertY;
|
||||
f(cellX, cellY, globalX - offsetX, globalY - offsetY, vertX, vertY);
|
||||
});
|
||||
|
||||
baseVertX = vertX + 1;
|
||||
}
|
||||
|
||||
baseVertY = vertY + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,7 @@
|
||||
#include "storage.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osg/Image>
|
||||
#include <osg/Plane>
|
||||
@ -12,6 +13,8 @@
|
||||
#include <components/misc/strings/algorithm.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
||||
#include "gridsampling.hpp"
|
||||
|
||||
namespace ESMTerrain
|
||||
{
|
||||
|
||||
@ -184,47 +187,52 @@ namespace ESMTerrain
|
||||
}
|
||||
|
||||
void Storage::fillVertexBuffers(int lodLevel, float size, const osg::Vec2f& center, ESM::RefId worldspace,
|
||||
osg::ref_ptr<osg::Vec3Array> positions, osg::ref_ptr<osg::Vec3Array> normals,
|
||||
osg::ref_ptr<osg::Vec4ubArray> colours)
|
||||
osg::Vec3Array& positions, osg::Vec3Array& normals, osg::Vec4ubArray& colours)
|
||||
{
|
||||
if (lodLevel < 0 || 63 < lodLevel)
|
||||
throw std::invalid_argument("Invalid terrain lod level: " + std::to_string(lodLevel));
|
||||
|
||||
if (size <= 0)
|
||||
throw std::invalid_argument("Invalid terrain size: " + std::to_string(size));
|
||||
|
||||
// LOD level n means every 2^n-th vertex is kept
|
||||
size_t increment = static_cast<size_t>(1) << lodLevel;
|
||||
const std::size_t sampleSize = std::size_t{ 1 } << lodLevel;
|
||||
const std::size_t cellSize = static_cast<std::size_t>(ESM::getLandSize(worldspace));
|
||||
const std::size_t numVerts = static_cast<std::size_t>(size * (cellSize - 1) / sampleSize) + 1;
|
||||
|
||||
osg::Vec2f origin = center - osg::Vec2f(size / 2.f, size / 2.f);
|
||||
|
||||
int startCellX = static_cast<int>(std::floor(origin.x()));
|
||||
int startCellY = static_cast<int>(std::floor(origin.y()));
|
||||
const int landSize = ESM::getLandSize(worldspace);
|
||||
const int LandSizeInUnits = ESM::getCellSize(worldspace);
|
||||
|
||||
size_t numVerts = static_cast<size_t>(size * (landSize - 1) / increment + 1);
|
||||
|
||||
positions->resize(numVerts * numVerts);
|
||||
normals->resize(numVerts * numVerts);
|
||||
colours->resize(numVerts * numVerts);
|
||||
|
||||
osg::Vec3f normal;
|
||||
osg::Vec4ub color;
|
||||
|
||||
float vertY = 0;
|
||||
float vertX = 0;
|
||||
positions.resize(numVerts * numVerts);
|
||||
normals.resize(numVerts * numVerts);
|
||||
colours.resize(numVerts * numVerts);
|
||||
|
||||
LandCache cache;
|
||||
|
||||
bool alteration = useAlteration();
|
||||
const bool alteration = useAlteration();
|
||||
const int landSizeInUnits = ESM::getCellSize(worldspace);
|
||||
const osg::Vec2f origin = center - osg::Vec2f(size, size) * 0.5f;
|
||||
const int startCellX = static_cast<int>(std::floor(origin.x()));
|
||||
const int startCellY = static_cast<int>(std::floor(origin.y()));
|
||||
ESM::ExteriorCellLocation lastCellLocation(startCellX - 1, startCellY - 1, worldspace);
|
||||
const LandObject* land = nullptr;
|
||||
const ESM::LandData* heightData = nullptr;
|
||||
const ESM::LandData* normalData = nullptr;
|
||||
const ESM::LandData* colourData = nullptr;
|
||||
bool validHeightDataExists = false;
|
||||
float vertY_ = 0; // of current cell corner
|
||||
for (int cellY = startCellY; cellY < startCellY + std::ceil(size); ++cellY)
|
||||
{
|
||||
float vertX_ = 0; // of current cell corner
|
||||
for (int cellX = startCellX; cellX < startCellX + std::ceil(size); ++cellX)
|
||||
|
||||
const auto handleSample = [&](std::size_t cellShiftX, std::size_t cellShiftY, std::size_t row, std::size_t col,
|
||||
std::size_t vertX, std::size_t vertY) {
|
||||
const int cellX = startCellX + cellShiftX;
|
||||
const int cellY = startCellY + cellShiftY;
|
||||
const ESM::ExteriorCellLocation cellLocation(cellX, cellY, worldspace);
|
||||
|
||||
if (lastCellLocation != cellLocation)
|
||||
{
|
||||
ESM::ExteriorCellLocation cellLocation(cellX, cellY, worldspace);
|
||||
const LandObject* land = getLand(cellLocation, cache);
|
||||
const ESM::LandData* heightData = nullptr;
|
||||
const ESM::LandData* normalData = nullptr;
|
||||
const ESM::LandData* colourData = nullptr;
|
||||
if (land)
|
||||
land = getLand(cellLocation, cache);
|
||||
|
||||
heightData = nullptr;
|
||||
normalData = nullptr;
|
||||
colourData = nullptr;
|
||||
|
||||
if (land != nullptr)
|
||||
{
|
||||
heightData = land->getData(ESM::Land::DATA_VHGT);
|
||||
normalData = land->getData(ESM::Land::DATA_VNML);
|
||||
@ -232,110 +240,70 @@ namespace ESMTerrain
|
||||
validHeightDataExists = true;
|
||||
}
|
||||
|
||||
int rowStart = 0;
|
||||
int colStart = 0;
|
||||
// Skip the first row / column unless we're at a chunk edge,
|
||||
// since this row / column is already contained in a previous cell
|
||||
// This is only relevant if we're creating a chunk spanning multiple cells
|
||||
if (vertY_ != 0)
|
||||
colStart += increment;
|
||||
if (vertX_ != 0)
|
||||
rowStart += increment;
|
||||
|
||||
// Only relevant for chunks smaller than (contained in) one cell
|
||||
rowStart += (origin.x() - startCellX) * landSize;
|
||||
colStart += (origin.y() - startCellY) * landSize;
|
||||
int rowEnd = std::min(
|
||||
static_cast<int>(rowStart + std::min(1.f, size) * (landSize - 1) + 1), static_cast<int>(landSize));
|
||||
int colEnd = std::min(
|
||||
static_cast<int>(colStart + std::min(1.f, size) * (landSize - 1) + 1), static_cast<int>(landSize));
|
||||
|
||||
vertY = vertY_;
|
||||
for (int col = colStart; col < colEnd; col += increment)
|
||||
{
|
||||
vertX = vertX_;
|
||||
for (int row = rowStart; row < rowEnd; row += increment)
|
||||
{
|
||||
int srcArrayIndex = col * landSize * 3 + row * 3;
|
||||
|
||||
assert(row >= 0 && row < landSize);
|
||||
assert(col >= 0 && col < landSize);
|
||||
|
||||
assert(vertX < numVerts);
|
||||
assert(vertY < numVerts);
|
||||
|
||||
float height = defaultHeight;
|
||||
if (heightData)
|
||||
height = heightData->getHeights()[col * landSize + row];
|
||||
if (alteration)
|
||||
height += getAlteredHeight(col, row);
|
||||
(*positions)[static_cast<unsigned int>(vertX * numVerts + vertY)]
|
||||
= osg::Vec3f((vertX / float(numVerts - 1) - 0.5f) * size * LandSizeInUnits,
|
||||
(vertY / float(numVerts - 1) - 0.5f) * size * LandSizeInUnits, height);
|
||||
|
||||
if (normalData)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
normal[i] = normalData->getNormals()[srcArrayIndex + i];
|
||||
|
||||
normal.normalize();
|
||||
}
|
||||
else
|
||||
normal = osg::Vec3f(0, 0, 1);
|
||||
|
||||
// Normals apparently don't connect seamlessly between cells
|
||||
if (col == landSize - 1 || row == landSize - 1)
|
||||
fixNormal(normal, cellLocation, col, row, cache);
|
||||
|
||||
// some corner normals appear to be complete garbage (z < 0)
|
||||
if ((row == 0 || row == landSize - 1) && (col == 0 || col == landSize - 1))
|
||||
averageNormal(normal, cellLocation, col, row, cache);
|
||||
|
||||
assert(normal.z() > 0);
|
||||
|
||||
(*normals)[static_cast<unsigned int>(vertX * numVerts + vertY)] = normal;
|
||||
|
||||
if (colourData)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
color[i] = colourData->getColors()[srcArrayIndex + i];
|
||||
}
|
||||
else
|
||||
{
|
||||
color.r() = 255;
|
||||
color.g() = 255;
|
||||
color.b() = 255;
|
||||
}
|
||||
if (alteration)
|
||||
adjustColor(col, row, heightData, color); // Does nothing by default, override in OpenMW-CS
|
||||
|
||||
// Unlike normals, colors mostly connect seamlessly between cells, but not always...
|
||||
if (col == landSize - 1 || row == landSize - 1)
|
||||
fixColour(color, cellLocation, col, row, cache);
|
||||
|
||||
color.a() = 255;
|
||||
|
||||
(*colours)[static_cast<unsigned int>(vertX * numVerts + vertY)] = color;
|
||||
|
||||
++vertX;
|
||||
}
|
||||
++vertY;
|
||||
}
|
||||
vertX_ = vertX;
|
||||
lastCellLocation = cellLocation;
|
||||
}
|
||||
vertY_ = vertY;
|
||||
|
||||
assert(vertX_ == numVerts); // Ensure we covered whole area
|
||||
}
|
||||
assert(vertY_ == numVerts); // Ensure we covered whole area
|
||||
float height = defaultHeight;
|
||||
if (heightData != nullptr)
|
||||
height = heightData->getHeights()[col * cellSize + row];
|
||||
if (alteration)
|
||||
height += getAlteredHeight(col, row);
|
||||
|
||||
const std::size_t vertIndex = vertX * numVerts + vertY;
|
||||
|
||||
positions[vertIndex]
|
||||
= osg::Vec3f((vertX / static_cast<float>(numVerts - 1) - 0.5f) * size * landSizeInUnits,
|
||||
(vertY / static_cast<float>(numVerts - 1) - 0.5f) * size * landSizeInUnits, height);
|
||||
|
||||
const std::size_t srcArrayIndex = col * cellSize * 3 + row * 3;
|
||||
|
||||
osg::Vec3f normal(0, 0, 1);
|
||||
|
||||
if (normalData != nullptr)
|
||||
{
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
normal[i] = normalData->getNormals()[srcArrayIndex + i];
|
||||
|
||||
normal.normalize();
|
||||
}
|
||||
|
||||
// Normals apparently don't connect seamlessly between cells
|
||||
if (col == cellSize - 1 || row == cellSize - 1)
|
||||
fixNormal(normal, cellLocation, col, row, cache);
|
||||
|
||||
// some corner normals appear to be complete garbage (z < 0)
|
||||
if ((row == 0 || row == cellSize - 1) && (col == 0 || col == cellSize - 1))
|
||||
averageNormal(normal, cellLocation, col, row, cache);
|
||||
|
||||
assert(normal.z() > 0);
|
||||
|
||||
normals[vertIndex] = normal;
|
||||
|
||||
osg::Vec4ub color(255, 255, 255, 255);
|
||||
|
||||
if (colourData != nullptr)
|
||||
for (std::size_t i = 0; i < 3; ++i)
|
||||
color[i] = colourData->getColors()[srcArrayIndex + i];
|
||||
|
||||
// Does nothing by default, override in OpenMW-CS
|
||||
if (alteration)
|
||||
adjustColor(col, row, heightData, color);
|
||||
|
||||
// Unlike normals, colors mostly connect seamlessly between cells, but not always...
|
||||
if (col == cellSize - 1 || row == cellSize - 1)
|
||||
fixColour(color, cellLocation, col, row, cache);
|
||||
|
||||
colours[vertIndex] = color;
|
||||
};
|
||||
|
||||
const std::size_t beginX = static_cast<std::size_t>((origin.x() - startCellX) * cellSize);
|
||||
const std::size_t beginY = static_cast<std::size_t>((origin.y() - startCellY) * cellSize);
|
||||
const std::size_t distance = static_cast<std::size_t>(size * (cellSize - 1)) + 1;
|
||||
|
||||
sampleCellGrid(cellSize, sampleSize, beginX, beginY, distance, handleSample);
|
||||
|
||||
if (!validHeightDataExists && ESM::isEsm4Ext(worldspace))
|
||||
{
|
||||
for (unsigned int iVert = 0; iVert < numVerts * numVerts; iVert++)
|
||||
{
|
||||
(*positions)[static_cast<unsigned int>(iVert)] = osg::Vec3f(0.f, 0.f, 0.f);
|
||||
}
|
||||
}
|
||||
std::fill(positions.begin(), positions.end(), osg::Vec3f());
|
||||
}
|
||||
|
||||
Storage::UniqueTextureId Storage::getVtexIndexAt(
|
@ -1,5 +1,5 @@
|
||||
#ifndef COMPONENTS_ESM_TERRAIN_STORAGE_H
|
||||
#define COMPONENTS_ESM_TERRAIN_STORAGE_H
|
||||
#ifndef OPENMW_COMPONENTS_ESMTERRAIN_STORAGE_H
|
||||
#define OPENMW_COMPONENTS_ESMTERRAIN_STORAGE_H
|
||||
|
||||
#include <cassert>
|
||||
#include <mutex>
|
||||
@ -99,8 +99,7 @@ namespace ESMTerrain
|
||||
/// @param normals buffer to write vertex normals
|
||||
/// @param colours buffer to write vertex colours
|
||||
void fillVertexBuffers(int lodLevel, float size, const osg::Vec2f& center, ESM::RefId worldspace,
|
||||
osg::ref_ptr<osg::Vec3Array> positions, osg::ref_ptr<osg::Vec3Array> normals,
|
||||
osg::ref_ptr<osg::Vec4ubArray> colours) override;
|
||||
osg::Vec3Array& positions, osg::Vec3Array& normals, osg::Vec4ubArray& colours) override;
|
||||
|
||||
/// Create textures holding layer blend values for a terrain chunk.
|
||||
/// @note The terrain chunk shouldn't be larger than one cell since otherwise we might
|
@ -7,6 +7,8 @@
|
||||
#include <osg/Vec2f>
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
|
||||
@ -63,8 +65,10 @@ namespace Misc
|
||||
return toEulerAnglesZYX(forward, up);
|
||||
}
|
||||
|
||||
inline bool isPowerOfTwo(int x)
|
||||
template <class T>
|
||||
bool isPowerOfTwo(T x)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>);
|
||||
return ((x > 0) && ((x & (x - 1)) == 0));
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,7 @@ namespace Terrain
|
||||
osg::ref_ptr<osg::Vec4ubArray> colors(new osg::Vec4ubArray);
|
||||
colors->setNormalize(true);
|
||||
|
||||
mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, mWorldspace, positions, normals, colors);
|
||||
mStorage->fillVertexBuffers(lod, chunkSize, chunkCenter, mWorldspace, *positions, *normals, *colors);
|
||||
|
||||
osg::ref_ptr<osg::VertexBufferObject> vbo(new osg::VertexBufferObject);
|
||||
positions->setVertexBufferObject(vbo);
|
||||
|
@ -64,8 +64,7 @@ namespace Terrain
|
||||
/// @param normals buffer to write vertex normals
|
||||
/// @param colours buffer to write vertex colours
|
||||
virtual void fillVertexBuffers(int lodLevel, float size, const osg::Vec2f& center, ESM::RefId worldspace,
|
||||
osg::ref_ptr<osg::Vec3Array> positions, osg::ref_ptr<osg::Vec3Array> normals,
|
||||
osg::ref_ptr<osg::Vec4ubArray> colours)
|
||||
osg::Vec3Array& positions, osg::Vec3Array& normals, osg::Vec4ubArray& colours)
|
||||
= 0;
|
||||
|
||||
typedef std::vector<osg::ref_ptr<osg::Image>> ImageVector;
|
||||
|
Loading…
x
Reference in New Issue
Block a user