mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
6.7 KiB
C++
170 lines
6.7 KiB
C++
#include "terrainstorage.hpp"
|
|
|
|
#include <components/esm3/loadltex.hpp>
|
|
#include <components/esmterrain/storage.hpp>
|
|
#include <components/resource/resourcesystem.hpp>
|
|
|
|
#include <apps/opencs/model/world/data.hpp>
|
|
#include <apps/opencs/model/world/idcollection.hpp>
|
|
#include <apps/opencs/model/world/land.hpp>
|
|
#include <apps/opencs/model/world/record.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <osg/Vec4ub>
|
|
#include <stdexcept>
|
|
#include <stdlib.h>
|
|
#include <string>
|
|
|
|
namespace CSVRender
|
|
{
|
|
TerrainStorage::TerrainStorage(const CSMWorld::Data& data)
|
|
: ESMTerrain::Storage(data.getResourceSystem()->getVFS())
|
|
, mData(data)
|
|
{
|
|
resetHeights();
|
|
}
|
|
|
|
osg::ref_ptr<const ESMTerrain::LandObject> TerrainStorage::getLand(ESM::ExteriorCellLocation cellLocation)
|
|
{
|
|
// The cell isn't guaranteed to have Land. This is because the terrain implementation
|
|
// has to wrap the vertices of the last row and column to the next cell, which may be a nonexisting cell
|
|
const int index = mData.getLand().searchId(
|
|
ESM::RefId::stringRefId(CSMWorld::Land::createUniqueRecordId(cellLocation.mX, cellLocation.mY)));
|
|
if (index == -1)
|
|
return nullptr;
|
|
|
|
const ESM::Land& land = mData.getLand().getRecord(index).get();
|
|
return new ESMTerrain::LandObject(
|
|
land, ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
|
|
}
|
|
|
|
const std::string* TerrainStorage::getLandTexture(std::uint16_t index, int plugin)
|
|
{
|
|
return mData.getLandTextures().getLandTexture(index, plugin);
|
|
}
|
|
|
|
void TerrainStorage::setAlteredHeight(int inCellX, int inCellY, float height)
|
|
{
|
|
mAlteredHeight[inCellY * ESM::Land::LAND_SIZE + inCellX]
|
|
= height - fmod(height, 8); // Limit to divisible by 8 to avoid cell seam breakage
|
|
}
|
|
|
|
void TerrainStorage::resetHeights()
|
|
{
|
|
std::fill(std::begin(mAlteredHeight), std::end(mAlteredHeight), 0);
|
|
}
|
|
|
|
float TerrainStorage::getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY)
|
|
{
|
|
float height = 0.f;
|
|
|
|
const int index
|
|
= mData.getLand().searchId(ESM::RefId::stringRefId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)));
|
|
if (index == -1) // no land!
|
|
return height;
|
|
|
|
const ESM::Land::LandData* landData = mData.getLand().getRecord(index).get().getLandData(ESM::Land::DATA_VHGT);
|
|
height = landData->mHeights[inCellY * ESM::Land::LAND_SIZE + inCellX];
|
|
return mAlteredHeight[inCellY * ESM::Land::LAND_SIZE + inCellX] + height;
|
|
}
|
|
|
|
float* TerrainStorage::getAlteredHeight(int inCellX, int inCellY)
|
|
{
|
|
return &mAlteredHeight[inCellY * ESM::Land::LAND_SIZE + inCellX];
|
|
}
|
|
|
|
void TerrainStorage::getBounds(float& minX, float& maxX, float& minY, float& maxY, ESM::RefId worldspace)
|
|
{
|
|
// not needed at the moment - this returns the bounds of the whole world, but we only edit individual cells
|
|
throw std::runtime_error("getBounds not implemented");
|
|
}
|
|
|
|
int TerrainStorage::getThisHeight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return heightData[col * ESM::Land::LAND_SIZE + row]
|
|
+ mAlteredHeight[static_cast<unsigned int>(col * ESM::Land::LAND_SIZE + row)];
|
|
}
|
|
|
|
int TerrainStorage::getLeftHeight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return heightData[(col)*ESM::Land::LAND_SIZE + row - 1]
|
|
+ mAlteredHeight[static_cast<unsigned int>((col)*ESM::Land::LAND_SIZE + row - 1)];
|
|
}
|
|
|
|
int TerrainStorage::getRightHeight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return heightData[col * ESM::Land::LAND_SIZE + row + 1]
|
|
+ mAlteredHeight[static_cast<unsigned int>(col * ESM::Land::LAND_SIZE + row + 1)];
|
|
}
|
|
|
|
int TerrainStorage::getUpHeight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return heightData[(col - 1) * ESM::Land::LAND_SIZE + row]
|
|
+ mAlteredHeight[static_cast<unsigned int>((col - 1) * ESM::Land::LAND_SIZE + row)];
|
|
}
|
|
|
|
int TerrainStorage::getDownHeight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return heightData[(col + 1) * ESM::Land::LAND_SIZE + row]
|
|
+ mAlteredHeight[static_cast<unsigned int>((col + 1) * ESM::Land::LAND_SIZE + row)];
|
|
}
|
|
|
|
int TerrainStorage::getHeightDifferenceToLeft(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return abs(getThisHeight(col, row, heightData) - getLeftHeight(col, row, heightData));
|
|
}
|
|
|
|
int TerrainStorage::getHeightDifferenceToRight(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return abs(getThisHeight(col, row, heightData) - getRightHeight(col, row, heightData));
|
|
}
|
|
|
|
int TerrainStorage::getHeightDifferenceToUp(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return abs(getThisHeight(col, row, heightData) - getUpHeight(col, row, heightData));
|
|
}
|
|
|
|
int TerrainStorage::getHeightDifferenceToDown(int col, int row, std::span<const float> heightData) const
|
|
{
|
|
return abs(getThisHeight(col, row, heightData) - getDownHeight(col, row, heightData));
|
|
}
|
|
|
|
bool TerrainStorage::leftOrUpIsOverTheLimit(
|
|
int col, int row, int heightWarningLimit, std::span<const float> heightData) const
|
|
{
|
|
return getHeightDifferenceToLeft(col, row, heightData) >= heightWarningLimit
|
|
|| getHeightDifferenceToUp(col, row, heightData) >= heightWarningLimit;
|
|
}
|
|
|
|
bool TerrainStorage::rightOrDownIsOverTheLimit(
|
|
int col, int row, int heightWarningLimit, std::span<const float> heightData) const
|
|
{
|
|
return getHeightDifferenceToRight(col, row, heightData) >= heightWarningLimit
|
|
|| getHeightDifferenceToDown(col, row, heightData) >= heightWarningLimit;
|
|
}
|
|
|
|
void TerrainStorage::adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const
|
|
{
|
|
if (!heightData)
|
|
return;
|
|
// Highlight broken height changes
|
|
int heightWarningLimit = 1024;
|
|
if (((col > 0 && row > 0) && leftOrUpIsOverTheLimit(col, row, heightWarningLimit, heightData->getHeights()))
|
|
|| ((col < ESM::Land::LAND_SIZE - 1 && row < ESM::Land::LAND_SIZE - 1)
|
|
&& rightOrDownIsOverTheLimit(col, row, heightWarningLimit, heightData->getHeights())))
|
|
{
|
|
color.r() = 255;
|
|
color.g() = 0;
|
|
color.b() = 0;
|
|
}
|
|
}
|
|
|
|
float TerrainStorage::getAlteredHeight(int col, int row) const
|
|
{
|
|
return mAlteredHeight[static_cast<unsigned int>(col * ESM::Land::LAND_SIZE + row)];
|
|
}
|
|
}
|