mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-29 15:11:35 +00:00
expose a terrain height getter
This commit is contained in:
parent
efbef1ec96
commit
910690c7e5
3 changed files with 77 additions and 17 deletions
|
@ -1,5 +1,8 @@
|
|||
#include "corebindings.hpp"
|
||||
|
||||
#include <apps/openmw/mwlua/object.hpp>
|
||||
#include <apps/openmw/mwworld/cellstore.hpp>
|
||||
#include <apps/openmw/mwworld/worldmodel.hpp>
|
||||
#include <chrono>
|
||||
#include <stdexcept>
|
||||
|
||||
|
@ -25,6 +28,9 @@
|
|||
#include "magicbindings.hpp"
|
||||
#include "soundbindings.hpp"
|
||||
#include "stats.hpp"
|
||||
#include <components/esm3/landrecorddata.hpp>
|
||||
#include <components/esm3/loadland.hpp>
|
||||
#include <components/esmterrain/storage.hpp>
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
|
@ -147,6 +153,43 @@ namespace MWLua
|
|||
{ std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
|
||||
};
|
||||
}
|
||||
api["getHeightAt"] = [](float x, float y, sol::object cellOrName) {
|
||||
ESM::RefId worldspace;
|
||||
if (cellOrName.is<GCell>())
|
||||
worldspace = cellOrName.as<GCell>().mStore->getCell()->getWorldSpace();
|
||||
else if (cellOrName.is<std::string_view>() && !cellOrName.as<std::string_view>().empty())
|
||||
worldspace = MWBase::Environment::get()
|
||||
.getWorldModel()
|
||||
->getCell(cellOrName.as<std::string_view>())
|
||||
.getCell()
|
||||
->getWorldSpace();
|
||||
else
|
||||
worldspace = ESM::Cell::sDefaultWorldspaceId;
|
||||
|
||||
const float cellSize = ESM::getCellSize(worldspace);
|
||||
int cellX = static_cast<int>(std::floor(x / cellSize));
|
||||
int cellY = static_cast<int>(std::floor(y / cellSize));
|
||||
|
||||
auto store = MWBase::Environment::get().getESMStore();
|
||||
auto landStore = store->get<ESM::Land>();
|
||||
auto land = landStore.search(cellX, cellY);
|
||||
const ESM::Land::LandData* landData = nullptr;
|
||||
if (land != nullptr)
|
||||
{
|
||||
landData = land->getLandData(ESM::Land::DATA_VHGT);
|
||||
if (landData != nullptr)
|
||||
{
|
||||
// Ensure data is loaded if necessary
|
||||
land->loadData(ESM::Land::DATA_VHGT);
|
||||
}
|
||||
}
|
||||
if (landData == nullptr)
|
||||
{
|
||||
// If we failed to load data, return the default height
|
||||
return static_cast<float>(ESM::Land::DEFAULT_HEIGHT);
|
||||
}
|
||||
return ESMTerrain::Storage::getHeightAt(landData->mHeights, landData->sLandSize, { x, y, 0 }, cellSize);
|
||||
};
|
||||
|
||||
sol::table readOnlyApi = LuaUtil::makeReadOnly(api);
|
||||
return context.setTypePackage(readOnlyApi, "openmw_core");
|
||||
|
|
|
@ -465,21 +465,14 @@ namespace ESMTerrain
|
|||
blendmaps.clear(); // If a single texture fills the whole terrain, there is no need to blend
|
||||
}
|
||||
|
||||
float Storage::getHeightAt(const osg::Vec3f& worldPos, ESM::RefId worldspace)
|
||||
float Storage::getHeightAt(
|
||||
const std::span<const float> data, const int landSize, const osg::Vec3f& worldPos, const float cellSize)
|
||||
{
|
||||
const float cellSize = ESM::getCellSize(worldspace);
|
||||
// if (!data)
|
||||
// return defaultHeight;
|
||||
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
|
||||
|
@ -516,10 +509,10 @@ namespace ESMTerrain
|
|||
*/
|
||||
|
||||
// Build all 4 positions in normalized cell space, using point-sampled height
|
||||
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);
|
||||
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);
|
||||
// define this plane in terrain space
|
||||
osg::Plane plane;
|
||||
// FIXME: deal with differing triangle alignment
|
||||
|
@ -548,6 +541,22 @@ 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))
|
||||
|
|
|
@ -114,6 +114,9 @@ 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);
|
||||
|
||||
/// Get the transformation factor for mapping cell units to world units.
|
||||
float getCellWorldSize(ESM::RefId worldspace) override;
|
||||
|
||||
|
@ -122,12 +125,17 @@ namespace ESMTerrain
|
|||
|
||||
int getBlendmapScale(float chunkSize) override;
|
||||
|
||||
float getVertexHeight(const ESM::LandData* data, int x, int y)
|
||||
static 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->getHeights()[y * landSize + x];
|
||||
return data[y * landSize + x];
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue