1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-27 20:41:38 +00:00

don't touch ESMTerrain::Storage

This commit is contained in:
Sebastian Fieber 2025-01-08 21:51:01 +01:00
parent 3d07b63ad8
commit fc772744d2
3 changed files with 58 additions and 84 deletions

View file

@ -13,6 +13,39 @@
namespace
{
osg::Vec3f getTextureCorrectedWorldPos(
const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize)
{
// the offset is [-0.25, +0.25] of a single texture's size
// TODO: verify whether or not this works in TES4 and beyond
float offset = (cellSize / textureSize) * 0.25;
return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f };
}
// Takes in a corrected world pos to match the visuals.
ESMTerrain::UniqueTextureId getTextureAt(const std::span<const std::uint16_t> landData, const int plugin,
const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize)
{
int cellX = static_cast<int>(std::floor(correctedWorldPos.x() / cellSize));
int cellY = static_cast<int>(std::floor(correctedWorldPos.y() / cellSize));
// Normalized position in the cell
float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize;
float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize;
int startX = static_cast<int>(nX * textureSize);
int startY = static_cast<int>(nY * textureSize);
assert(startX < ESM::Land::LAND_TEXTURE_SIZE);
assert(startY < ESM::Land::LAND_TEXTURE_SIZE);
const std::uint16_t tex = landData[startY * ESM::Land::LAND_TEXTURE_SIZE + startX];
if (tex == 0)
return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin
return { tex, plugin };
}
const ESM::RefId worldspaceAt(const osg::Vec3f& pos, sol::object cellOrName)
{
ESM::RefId worldspace;
@ -65,7 +98,7 @@ namespace MWLua
landApi["getTextureAt"] = [lua = lua](const osg::Vec3f& pos, sol::object cellOrName) {
sol::variadic_results values;
auto store = MWBase::Environment::get().getESMStore();
const auto &landStore = store->get<ESM::Land>();
const auto& landStore = store->get<ESM::Land>();
const float cellSize = ESM::getCellSize(worldspaceAt(pos, cellOrName));
// We need to read land twice. Once to get the amount of texture samples per cell edge, and the second time
@ -82,8 +115,7 @@ namespace MWLua
// Use landData to get amount of sampler per cell edge (sLandTextureSize)
// and then get the corrected position that will map to the rendered texture
const osg::Vec3f correctedPos
= ESMTerrain::Storage::getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize);
const osg::Vec3f correctedPos = getTextureCorrectedWorldPos(pos, landData->sLandTextureSize, cellSize);
const ESM::Land* correctedLand = nullptr;
const ESM::Land::LandData* correctedLandData = nullptr;
@ -93,7 +125,7 @@ namespace MWLua
// We're passing in sLandTextureSize, NOT sLandSize like with getHeightAt
const ESMTerrain::UniqueTextureId textureId
= ESMTerrain::Storage::getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(),
= getTextureAt(correctedLandData->mTextures, correctedLand->getPlugin(),
correctedLandData->sLandTextureSize, correctedPos, cellSize);
// Need to check for 0, 0 so that we can safely subtract 1 later, as per documentation on UniqueTextureId

View file

@ -6,7 +6,6 @@
#include <osg/Image>
#include <osg/Plane>
#include <osg/Vec3f>
#include <components/debug/debuglog.hpp>
#include <components/esm/esmterrain.hpp>
@ -23,19 +22,6 @@ namespace ESMTerrain
{
namespace
{
UniqueTextureId getTextureIdAt(
const std::span<const std::uint16_t> data, const int plugin, const std::size_t x, const std::size_t y)
{
assert(x < ESM::Land::LAND_TEXTURE_SIZE);
assert(y < ESM::Land::LAND_TEXTURE_SIZE);
const std::uint16_t tex = data[y * ESM::Land::LAND_TEXTURE_SIZE + x];
if (tex == 0)
return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin
return { tex, plugin };
}
UniqueTextureId getTextureIdAt(const LandObject* land, std::size_t x, std::size_t y)
{
assert(x < ESM::Land::LAND_TEXTURE_SIZE);
@ -48,7 +34,11 @@ namespace ESMTerrain
if (data == nullptr)
return { 0, 0 };
return getTextureIdAt(data->getTextures(), land->getPlugin(), x, y);
const std::uint16_t tex = data->getTextures()[y * ESM::Land::LAND_TEXTURE_SIZE + x];
if (tex == 0)
return { 0, 0 }; // vtex 0 is always the base texture, regardless of plugin
return { tex, land->getPlugin() };
}
}
@ -475,39 +465,21 @@ namespace ESMTerrain
blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend
}
// Returns a position that can be used to look up a land texture, while taking their offset into account
osg::Vec3f Storage::getTextureCorrectedWorldPos(
const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize)
{
// the offset is [-0.25, +0.25] of a single texture's size
// TODO: verify whether or not this works in TES4 and beyond
float offset = (cellSize / textureSize) * 0.25;
return uncorrectedWorldPos + osg::Vec3f{ -offset, +offset, 0.0f };
}
// Takes in a corrected world pos to match the visuals.
UniqueTextureId Storage::getTextureAt(const std::span<const std::uint16_t> landData, const int plugin,
const int textureSize, const osg::Vec3f& correctedWorldPos, const float cellSize)
{
int cellX = static_cast<int>(std::floor(correctedWorldPos.x() / cellSize));
int cellY = static_cast<int>(std::floor(correctedWorldPos.y() / cellSize));
// Normalized position in the cell
float nX = (correctedWorldPos.x() - (cellX * cellSize)) / cellSize;
float nY = (correctedWorldPos.y() - (cellY * cellSize)) / cellSize;
int startX = static_cast<int>(nX * textureSize);
int startY = static_cast<int>(nY * textureSize);
return getTextureIdAt(landData, plugin, startX, startY);
}
float Storage::getHeightAt(
const std::span<const float> data, const int landSize, const osg::Vec3f& worldPos, const float cellSize)
float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace)
{
const float cellSize = ESM::getCellSize(worldspace);
int cellX = static_cast<int>(std::floor(worldPos.x() / cellSize));
int cellY = static_cast<int>(std::floor(worldPos.y() / cellSize));
osg::ref_ptr<const LandObject> land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace));
if (!land)
return ESM::isEsm4Ext(worldspace) ? std::numeric_limits<float>::lowest() : defaultHeight;
const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT);
if (!data)
return defaultHeight;
const int landSize = data->getLandSize();
// Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition
// Normalized position in the cell
@ -544,10 +516,10 @@ namespace ESMTerrain
*/
// Build all 4 positions in normalized cell space, using point-sampled height
osg::Vec3f v0(startXTS, startYTS, Storage::getVertexHeight(data, landSize, startX, startY) / cellSize);
osg::Vec3f v1(endXTS, startYTS, Storage::getVertexHeight(data, landSize, endX, startY) / cellSize);
osg::Vec3f v2(endXTS, endYTS, Storage::getVertexHeight(data, landSize, endX, endY) / cellSize);
osg::Vec3f v3(startXTS, endYTS, Storage::getVertexHeight(data, landSize, startX, endY) / cellSize);
osg::Vec3f v0(startXTS, startYTS, getVertexHeight(data, startX, startY) / cellSize);
osg::Vec3f v1(endXTS, startYTS, getVertexHeight(data, endX, startY) / cellSize);
osg::Vec3f v2(endXTS, endYTS, getVertexHeight(data, endX, endY) / cellSize);
osg::Vec3f v3(startXTS, endYTS, getVertexHeight(data, startX, endY) / cellSize);
// define this plane in terrain space
osg::Plane plane;
// FIXME: deal with differing triangle alignment
@ -576,22 +548,6 @@ namespace ESMTerrain
return (-plane.getNormal().x() * nX - plane.getNormal().y() * nY - plane[3]) / plane.getNormal().z() * cellSize;
}
float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace)
{
const float cellSize = ESM::getCellSize(worldspace);
int cellX = static_cast<int>(std::floor(worldPos.x() / cellSize));
int cellY = static_cast<int>(std::floor(worldPos.y() / cellSize));
osg::ref_ptr<const LandObject> land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace));
if (!land)
return ESM::isEsm4Ext(worldspace) ? std::numeric_limits<float>::lowest() : defaultHeight;
const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT);
if (!data)
return defaultHeight;
return Storage::getHeightAt(data->getHeights(), data->getLandSize(), worldPos, cellSize);
}
const LandObject* Storage::getLand(ESM::ExteriorCellLocation cellLocation, LandCache& cache)
{
if (const auto land = cache.find(cellLocation.mX, cellLocation.mY))

View file

@ -114,15 +114,6 @@ namespace ESMTerrain
float getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace) override;
static float getHeightAt(
const std::span<const float> data, const int landSize, const osg::Vec3f& worldPos, const float cellSize);
static osg::Vec3f getTextureCorrectedWorldPos(
const osg::Vec3f& uncorrectedWorldPos, const int textureSize, const float cellSize);
static UniqueTextureId getTextureAt(const std::span<const std::uint16_t> landData, const int plugin,
const int textureSize, const osg::Vec3f& worldPos, const float cellSize);
/// Get the transformation factor for mapping cell units to world units.
float getCellWorldSize(ESM::RefId worldspace) override;
@ -131,17 +122,12 @@ namespace ESMTerrain
int getBlendmapScale(float chunkSize) override;
static float getVertexHeight(const ESM::LandData* data, int x, int y)
float getVertexHeight(const ESM::LandData* data, int x, int y)
{
const int landSize = data->getLandSize();
return getVertexHeight(data->getHeights(), landSize, x, y);
}
static float getVertexHeight(const std::span<const float> data, const int landSize, int x, int y)
{
assert(x < landSize);
assert(y < landSize);
return data[y * landSize + x];
return data->getHeights()[y * landSize + x];
}
private: