#include "terrainstorage.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace CSVRender { TerrainStorage::TerrainStorage(const CSMWorld::Data& data) : ESMTerrain::Storage(data.getResourceSystem()->getVFS()) , mData(data) { resetHeights(); } osg::ref_ptr 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 heightData) const { return heightData[col * ESM::Land::LAND_SIZE + row] + mAlteredHeight[static_cast(col * ESM::Land::LAND_SIZE + row)]; } int TerrainStorage::getLeftHeight(int col, int row, std::span heightData) const { return heightData[(col)*ESM::Land::LAND_SIZE + row - 1] + mAlteredHeight[static_cast((col)*ESM::Land::LAND_SIZE + row - 1)]; } int TerrainStorage::getRightHeight(int col, int row, std::span heightData) const { return heightData[col * ESM::Land::LAND_SIZE + row + 1] + mAlteredHeight[static_cast(col * ESM::Land::LAND_SIZE + row + 1)]; } int TerrainStorage::getUpHeight(int col, int row, std::span heightData) const { return heightData[(col - 1) * ESM::Land::LAND_SIZE + row] + mAlteredHeight[static_cast((col - 1) * ESM::Land::LAND_SIZE + row)]; } int TerrainStorage::getDownHeight(int col, int row, std::span heightData) const { return heightData[(col + 1) * ESM::Land::LAND_SIZE + row] + mAlteredHeight[static_cast((col + 1) * ESM::Land::LAND_SIZE + row)]; } int TerrainStorage::getHeightDifferenceToLeft(int col, int row, std::span heightData) const { return abs(getThisHeight(col, row, heightData) - getLeftHeight(col, row, heightData)); } int TerrainStorage::getHeightDifferenceToRight(int col, int row, std::span heightData) const { return abs(getThisHeight(col, row, heightData) - getRightHeight(col, row, heightData)); } int TerrainStorage::getHeightDifferenceToUp(int col, int row, std::span heightData) const { return abs(getThisHeight(col, row, heightData) - getUpHeight(col, row, heightData)); } int TerrainStorage::getHeightDifferenceToDown(int col, int row, std::span heightData) const { return abs(getThisHeight(col, row, heightData) - getDownHeight(col, row, heightData)); } bool TerrainStorage::leftOrUpIsOverTheLimit( int col, int row, int heightWarningLimit, std::span heightData) const { return getHeightDifferenceToLeft(col, row, heightData) >= heightWarningLimit || getHeightDifferenceToUp(col, row, heightData) >= heightWarningLimit; } bool TerrainStorage::rightOrDownIsOverTheLimit( int col, int row, int heightWarningLimit, std::span 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(col * ESM::Land::LAND_SIZE + row)]; } }