Abstracted Land data that can be used by esm3 and esm4.

macos_ci
florent.teppe 2 years ago
parent e09cf6ac61
commit e0fa15b727

@ -72,8 +72,8 @@ namespace CSVRender
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];
const ESM::LandData* landData = mData.getLand().getRecord(index).get().getLandData(ESM::Land::DATA_VHGT);
height = landData->getHeights()[inCellY * ESM::Land::LAND_SIZE + inCellX];
return mAlteredHeight[inCellY * ESM::Land::LAND_SIZE + inCellX] + height;
}
@ -152,13 +152,14 @@ namespace CSVRender
|| getHeightDifferenceToDown(col, row, heightData) >= heightWarningLimit;
}
void TerrainStorage::adjustColor(int col, int row, const ESM::Land::LandData* heightData, osg::Vec4ub& color) const
void TerrainStorage::adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const
{
// Highlight broken height changes
const ESM::Land::LandData* heightDataEsm3 = dynamic_cast<const ESM::Land::LandData*>(heightData);
int heightWarningLimit = 1024;
if (((col > 0 && row > 0) && leftOrUpIsOverTheLimit(col, row, heightWarningLimit, heightData))
if (((col > 0 && row > 0) && leftOrUpIsOverTheLimit(col, row, heightWarningLimit, heightDataEsm3))
|| ((col < ESM::Land::LAND_SIZE - 1 && row < ESM::Land::LAND_SIZE - 1)
&& rightOrDownIsOverTheLimit(col, row, heightWarningLimit, heightData)))
&& rightOrDownIsOverTheLimit(col, row, heightWarningLimit, heightDataEsm3)))
{
color.r() = 255;
color.g() = 0;

@ -56,7 +56,7 @@ namespace CSVRender
bool rightOrDownIsOverTheLimit(
int col, int row, int heightWarningLimit, const ESM::Land::LandData* heightData) const;
void adjustColor(int col, int row, const ESM::Land::LandData* heightData, osg::Vec4ub& color) const override;
void adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const override;
float getAlteredHeight(int col, int row) const override;
};

@ -397,13 +397,13 @@ namespace MWWorld
if (cellVariant.isExterior())
{
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellIndex);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
const int verts = ESM::Land::LAND_SIZE;
const int worldsize = ESM::Land::REAL_SIZE;
const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
const int verts = data->getLandSize();
const int worldsize = data->getSize();
if (data)
{
mPhysics->addHeightField(
data->mHeights, cellX, cellY, worldsize, verts, data->mMinHeight, data->mMaxHeight, land.get());
mPhysics->addHeightField(data->getHeights().data(), cellX, cellY, worldsize, verts,
data->getMinHeight(), data->getMaxHeight(), land.get());
}
else
{
@ -425,14 +425,14 @@ namespace MWWorld
else
{
DetourNavigator::HeightfieldSurface heights;
heights.mHeights = data->mHeights;
heights.mSize = static_cast<std::size_t>(ESM::Land::LAND_SIZE);
heights.mMinHeight = data->mMinHeight;
heights.mMaxHeight = data->mMaxHeight;
heights.mHeights = data->getHeights().data();
heights.mSize = static_cast<std::size_t>(data->getLandSize());
heights.mMinHeight = data->getMinHeight();
heights.mMaxHeight = data->getMaxHeight();
return heights;
}
}();
mNavigator.addHeightfield(cellPosition, ESM::Land::REAL_SIZE, shape, navigatorUpdateGuard);
mNavigator.addHeightfield(cellPosition, data->getSize(), shape, navigatorUpdateGuard);
}
}

@ -118,7 +118,7 @@ add_component_dir (to_utf8
to_utf8
)
add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge
add_component_dir(esm attr common defs esmcommon records util luascripts format refid esmbridge esmterrain
formid
formidrefid
stringrefid

@ -0,0 +1,25 @@
#ifndef COMPONENTS_ESM_ESMTERRAIN
#define COMPONENTS_ESM_ESMTERRAIN
#include <span>
namespace ESM
{
class LandData
{
public:
typedef signed char VNML;
virtual std::span<const float> getHeights() const = 0;
virtual std::span<const VNML> getNormals() const = 0;
virtual std::span<const unsigned char> getColors() const = 0;
virtual std::span<const uint16_t> getTextures() const = 0;
virtual float getSize() const = 0;
virtual float getMinHeight() const = 0;
virtual float getMaxHeight() const = 0;
virtual int getLandSize() const = 0;
};
}
#endif // ! COMPNENTS_ESM_ESMTERRAIN

@ -7,6 +7,7 @@
#include "components/esm/defs.hpp"
#include "components/esm/esmcommon.hpp"
#include "components/esm/esmterrain.hpp"
namespace ESM
{
@ -87,9 +88,7 @@ namespace ESM
};
#pragma pack(pop)
typedef signed char VNML;
struct LandData
struct LandData : public ESM::LandData
{
LandData()
: mHeightOffset(0)
@ -124,6 +123,15 @@ namespace ESM
uint8_t mUnk2;
int mDataLoaded;
std::span<const float> getHeights() const override { return mHeights; }
std::span<const VNML> getNormals() const override { return mNormals; }
std::span<const unsigned char> getColors() const override { return mColours; }
std::span<const uint16_t> getTextures() const override { return mTextures; }
float getSize() const override { return REAL_SIZE; }
float getMinHeight() const override { return mMinHeight; }
float getMaxHeight() const { return mMaxHeight; }
int getLandSize() const { return LAND_SIZE; }
};
// low-LOD heightmap (used for rendering the global map)

@ -63,15 +63,15 @@ namespace ESMTerrain
int cellX = static_cast<int>(std::floor(origin.x()));
int cellY = static_cast<int>(std::floor(origin.y()));
osg::ref_ptr<const LandObject> land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace));
const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
int startRow = (origin.x() - cellX) * ESM::Land::LAND_SIZE;
int startColumn = (origin.y() - cellY) * ESM::Land::LAND_SIZE;
int startRow = (origin.x() - cellX) * data->getLandSize();
int startColumn = (origin.y() - cellY) * data->getLandSize();
int endRow = startRow + size * (ESM::Land::LAND_SIZE - 1) + 1;
int endColumn = startColumn + size * (ESM::Land::LAND_SIZE - 1) + 1;
int endRow = startRow + size * (data->getLandSize() - 1) + 1;
int endColumn = startColumn + size * (data->getLandSize() - 1) + 1;
osg::ref_ptr<const LandObject> land = getLand(ESM::ExteriorCellLocation(cellX, cellY, worldspace));
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
if (data)
{
min = std::numeric_limits<float>::max();
@ -80,7 +80,7 @@ namespace ESMTerrain
{
for (int col = startColumn; col < endColumn; ++col)
{
float h = data->mHeights[col * ESM::Land::LAND_SIZE + row];
float h = data->getHeights()[col * data->getLandSize() + row];
if (h > max)
max = h;
if (h < min)
@ -98,34 +98,37 @@ namespace ESMTerrain
void Storage::fixNormal(
osg::Vec3f& normal, ESM::ExteriorCellLocation cellLocation, int col, int row, LandCache& cache)
{
while (col >= ESM::Land::LAND_SIZE - 1)
const LandObject* land = getLand(cellLocation, cache);
const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VNML) : nullptr;
const int landSize = data ? data->getLandSize() : ESM::Land::LAND_SIZE;
while (col >= landSize - 1)
{
++cellLocation.mY;
col -= ESM::Land::LAND_SIZE - 1;
col -= landSize - 1;
}
while (row >= ESM::Land::LAND_SIZE - 1)
while (row >= landSize - 1)
{
++cellLocation.mX;
row -= ESM::Land::LAND_SIZE - 1;
row -= landSize - 1;
}
while (col < 0)
{
--cellLocation.mY;
col += ESM::Land::LAND_SIZE - 1;
col += landSize - 1;
}
while (row < 0)
{
--cellLocation.mX;
row += ESM::Land::LAND_SIZE - 1;
row += landSize - 1;
}
const LandObject* land = getLand(cellLocation, cache);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VNML) : nullptr;
if (data)
{
normal.x() = data->mNormals[col * ESM::Land::LAND_SIZE * 3 + row * 3];
normal.y() = data->mNormals[col * ESM::Land::LAND_SIZE * 3 + row * 3 + 1];
normal.z() = data->mNormals[col * ESM::Land::LAND_SIZE * 3 + row * 3 + 2];
normal.x() = data->getNormals()[col * landSize * 3 + row * 3];
normal.y() = data->getNormals()[col * landSize * 3 + row * 3 + 1];
normal.z() = data->getNormals()[col * landSize * 3 + row * 3 + 2];
normal.normalize();
}
else
@ -147,24 +150,26 @@ namespace ESMTerrain
void Storage::fixColour(
osg::Vec4ub& color, ESM::ExteriorCellLocation cellLocation, int col, int row, LandCache& cache)
{
if (col == ESM::Land::LAND_SIZE - 1)
const LandObject* land = getLand(cellLocation, cache);
const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VCLR) : nullptr;
const int landSize = data ? data->getLandSize() : ESM::Land::LAND_SIZE;
if (col == landSize - 1)
{
++cellLocation.mY;
col = 0;
}
if (row == ESM::Land::LAND_SIZE - 1)
if (row == landSize - 1)
{
++cellLocation.mX;
row = 0;
}
const LandObject* land = getLand(cellLocation, cache);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VCLR) : nullptr;
if (data)
{
color.r() = data->mColours[col * ESM::Land::LAND_SIZE * 3 + row * 3];
color.g() = data->mColours[col * ESM::Land::LAND_SIZE * 3 + row * 3 + 1];
color.b() = data->mColours[col * ESM::Land::LAND_SIZE * 3 + row * 3 + 2];
color.r() = data->getColors()[col * landSize * 3 + row * 3];
color.g() = data->getColors()[col * landSize * 3 + row * 3 + 1];
color.b() = data->getColors()[col * landSize * 3 + row * 3 + 2];
}
else
{
@ -210,9 +215,11 @@ namespace ESMTerrain
{
ESM::ExteriorCellLocation cellLocation(cellX, cellY, worldspace);
const LandObject* land = getLand(cellLocation, cache);
const ESM::Land::LandData* heightData = nullptr;
const ESM::Land::LandData* normalData = nullptr;
const ESM::Land::LandData* colourData = nullptr;
const ESM::LandData* heightData = nullptr;
const ESM::LandData* normalData = nullptr;
const ESM::LandData* colourData = nullptr;
const int LandSize = ESM::Land::LAND_SIZE;
const int LandSizeInUnits = Constants::CellSizeInUnits;
if (land)
{
heightData = land->getData(ESM::Land::DATA_VHGT);
@ -231,12 +238,12 @@ namespace ESMTerrain
rowStart += increment;
// Only relevant for chunks smaller than (contained in) one cell
rowStart += (origin.x() - startCellX) * ESM::Land::LAND_SIZE;
colStart += (origin.y() - startCellY) * ESM::Land::LAND_SIZE;
int rowEnd = std::min(static_cast<int>(rowStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE - 1) + 1),
static_cast<int>(ESM::Land::LAND_SIZE));
int colEnd = std::min(static_cast<int>(colStart + std::min(1.f, size) * (ESM::Land::LAND_SIZE - 1) + 1),
static_cast<int>(ESM::Land::LAND_SIZE));
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)
@ -244,27 +251,27 @@ namespace ESMTerrain
vertX = vertX_;
for (int row = rowStart; row < rowEnd; row += increment)
{
int srcArrayIndex = col * ESM::Land::LAND_SIZE * 3 + row * 3;
int srcArrayIndex = col * LandSize * 3 + row * 3;
assert(row >= 0 && row < ESM::Land::LAND_SIZE);
assert(col >= 0 && col < ESM::Land::LAND_SIZE);
assert(row >= 0 && row < LandSize);
assert(col >= 0 && col < LandSize);
assert(vertX < numVerts);
assert(vertY < numVerts);
float height = defaultHeight;
if (heightData)
height = heightData->mHeights[col * ESM::Land::LAND_SIZE + row];
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 * Constants::CellSizeInUnits,
(vertY / float(numVerts - 1) - 0.5f) * size * Constants::CellSizeInUnits, height);
= 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->mNormals[srcArrayIndex + i];
normal[i] = normalData->getNormals()[srcArrayIndex + i];
normal.normalize();
}
@ -272,12 +279,11 @@ namespace ESMTerrain
normal = osg::Vec3f(0, 0, 1);
// Normals apparently don't connect seamlessly between cells
if (col == ESM::Land::LAND_SIZE - 1 || row == ESM::Land::LAND_SIZE - 1)
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 == ESM::Land::LAND_SIZE - 1)
&& (col == 0 || col == ESM::Land::LAND_SIZE - 1))
if ((row == 0 || row == LandSize - 1) && (col == 0 || col == LandSize - 1))
averageNormal(normal, cellLocation, col, row, cache);
assert(normal.z() > 0);
@ -287,7 +293,7 @@ namespace ESMTerrain
if (colourData)
{
for (int i = 0; i < 3; ++i)
color[i] = colourData->mColours[srcArrayIndex + i];
color[i] = colourData->getColors()[srcArrayIndex + i];
}
else
{
@ -299,7 +305,7 @@ namespace ESMTerrain
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 == ESM::Land::LAND_SIZE - 1 || row == ESM::Land::LAND_SIZE - 1)
if (col == LandSize - 1 || row == LandSize - 1)
fixColour(color, cellLocation, col, row, cache);
color.a() = 255;
@ -347,10 +353,10 @@ namespace ESMTerrain
const LandObject* land = getLand(cellLocation, cache);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VTEX) : nullptr;
const ESM::LandData* data = land ? land->getData(ESM::Land::DATA_VTEX) : nullptr;
if (data)
{
int tex = data->mTextures[y * ESM::Land::LAND_TEXTURE_SIZE + x];
int tex = data->getTextures()[y * ESM::Land::LAND_TEXTURE_SIZE + x];
if (tex == 0)
return std::make_pair(0, 0); // vtex 0 is always the base texture, regardless of plugin
return std::make_pair(tex, land->getPlugin());
@ -458,7 +464,7 @@ namespace ESMTerrain
if (!land)
return defaultHeight;
const ESM::Land::LandData* data = land->getData(ESM::Land::DATA_VHGT);
const ESM::LandData* data = land->getData(ESM::Land::DATA_VHGT);
if (!data)
return defaultHeight;
@ -542,7 +548,7 @@ namespace ESMTerrain
}
}
void Storage::adjustColor(int col, int row, const ESM::Land::LandData* heightData, osg::Vec4ub& color) const {}
void Storage::adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const {}
float Storage::getAlteredHeight(int col, int row) const
{

@ -10,6 +10,11 @@
#include <components/esm3/loadland.hpp>
#include <components/esm3/loadltex.hpp>
namespace ESM4
{
struct Land;
}
namespace VFS
{
class Manager;
@ -32,7 +37,7 @@ namespace ESMTerrain
META_Object(ESMTerrain, LandObject)
inline const ESM::Land::LandData* getData(int flags) const
inline const ESM::LandData* getData(int flags) const
{
if ((mData.mDataLoaded & flags) != flags)
return nullptr;
@ -108,11 +113,11 @@ namespace ESMTerrain
int getBlendmapScale(float chunkSize) override;
float getVertexHeight(const ESM::Land::LandData* data, int x, int y)
float getVertexHeight(const ESM::LandData* data, int x, int y)
{
assert(x < ESM::Land::LAND_SIZE);
assert(y < ESM::Land::LAND_SIZE);
return data->mHeights[y * ESM::Land::LAND_SIZE + x];
return data->getHeights()[y * ESM::Land::LAND_SIZE + x];
}
private:
@ -128,7 +133,7 @@ namespace ESMTerrain
inline const LandObject* getLand(ESM::ExteriorCellLocation cellLocation, LandCache& cache);
virtual bool useAlteration() const { return false; }
virtual void adjustColor(int col, int row, const ESM::Land::LandData* heightData, osg::Vec4ub& color) const;
virtual void adjustColor(int col, int row, const ESM::LandData* heightData, osg::Vec4ub& color) const;
virtual float getAlteredHeight(int col, int row) const;
// Since plugins can define new texture palettes, we need to know the plugin index too

Loading…
Cancel
Save