CS: Make painting terrain height over a cell border equalize the height

at both edge
This commit is contained in:
Marius DAVID 2025-08-27 18:08:54 +02:00
parent 77b08943a7
commit 0f500df183
7 changed files with 148 additions and 96 deletions

View File

@ -371,6 +371,11 @@ float CSVRender::Cell::getSumOfAlteredAndTrueHeight(int cellX, int cellY, int in
return mTerrainStorage->getSumOfAlteredAndTrueHeight(cellX, cellY, inCellX, inCellY);
}
std::optional<float> CSVRender::Cell::getOriginalHeight(int cellX, int cellY, int inCellX, int inCellY)
{
return mTerrainStorage->getOriginalHeight(cellX, cellY, inCellX, inCellY);
}
float* CSVRender::Cell::getAlteredHeight(int inCellX, int inCellY)
{
return mTerrainStorage->getAlteredHeight(inCellX, inCellY);

View File

@ -125,6 +125,8 @@ namespace CSVRender
float getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY);
std::optional<float> getOriginalHeight(int cellX, int cellY, int inCellX, int inCellY);
float* getAlteredHeight(int inCellX, int inCellY);
void resetAlteredHeights();

View File

@ -824,6 +824,30 @@ CSVRender::Cell* CSVRender::PagedWorldspaceWidget::getCell(const CSMWorld::CellC
return nullptr;
}
void CSVRender::PagedWorldspaceWidget::setCellAlteredAbsoluteHeight(
const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY, float absoluteHeight)
{
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
if (searchResult != mCells.end())
{
std::optional<float> baseHeight
= searchResult->second->getOriginalHeight(coords.getX(), coords.getY(), inCellX, inCellY);
if (baseHeight)
searchResult->second->setAlteredHeight(inCellX, inCellY, absoluteHeight - *baseHeight);
}
}
std::optional<float> CSVRender::PagedWorldspaceWidget::getCellOriginalHeight(
const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY)
{
std::map<CSMWorld::CellCoordinates, Cell*>::iterator searchResult = mCells.find(coords);
if (searchResult != mCells.end())
{
return searchResult->second->getOriginalHeight(coords.getX(), coords.getY(), inCellX, inCellY);
}
return {};
}
void CSVRender::PagedWorldspaceWidget::setCellAlteredHeight(
const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY, float height)
{

View File

@ -153,6 +153,11 @@ namespace CSVRender
Cell* getCell(const CSMWorld::CellCoordinates& coords) const override;
void setCellAlteredAbsoluteHeight(
const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY, float absoluteHeight);
std::optional<float> getCellOriginalHeight(const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY);
void setCellAlteredHeight(const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY, float height);
float* getCellAlteredHeight(const CSMWorld::CellCoordinates& coords, int inCellX, int inCellY);

View File

@ -609,117 +609,127 @@ void CSVRender::TerrainShapeMode::alterHeight(const CSMWorld::CellCoordinates& c
if ((inCellX != 0 && inCellY != 0 && inCellX != ESM::Land::LAND_SIZE - 1 && inCellY != ESM::Land::LAND_SIZE - 1)
|| !useAndAlterAdjacentCell)
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
if (useAndAlterAdjacentCell)
else
{
// Change values of cornering cells
if ((inCellX == 0 && inCellY == 0) && (useTool || isLandLoaded(cellUpLeftId)))
std::optional<float> originalHeight = paged->getCellOriginalHeight(cellCoords, inCellX, inCellY);
if (originalHeight)
{
if (allowLandShapeEditing(cellUpLeftId, useTool) && allowLandShapeEditing(cellLeftId, useTool)
&& allowLandShapeEditing(cellUpId, useTool))
float absoluteHeight = *originalHeight + alteredHeight;
// Change values of cornering cells
if ((inCellX == 0 && inCellY == 0) && (useTool || isLandLoaded(cellUpLeftId)))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(-1, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredHeight(
cornerCellCoords, ESM::Land::LAND_SIZE - 1, ESM::Land::LAND_SIZE - 1, alteredHeight);
if (allowLandShapeEditing(cellUpLeftId, useTool) && allowLandShapeEditing(cellLeftId, useTool)
&& allowLandShapeEditing(cellUpId, useTool))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(-1, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords)
== mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredAbsoluteHeight(
cornerCellCoords, ESM::Land::LAND_SIZE - 1, ESM::Land::LAND_SIZE - 1, absoluteHeight);
}
else
return;
}
else
return;
}
else if ((inCellX == 0 && inCellY == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellDownLeftId)))
{
if (allowLandShapeEditing(cellDownLeftId, useTool) && allowLandShapeEditing(cellLeftId, useTool)
&& allowLandShapeEditing(cellDownId, useTool))
else if ((inCellX == 0 && inCellY == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellDownLeftId)))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(-1, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredHeight(cornerCellCoords, ESM::Land::LAND_SIZE - 1, 0, alteredHeight);
if (allowLandShapeEditing(cellDownLeftId, useTool) && allowLandShapeEditing(cellLeftId, useTool)
&& allowLandShapeEditing(cellDownId, useTool))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(-1, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords)
== mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredAbsoluteHeight(cornerCellCoords, ESM::Land::LAND_SIZE - 1, 0, absoluteHeight);
}
else
return;
}
else
return;
}
else if ((inCellX == ESM::Land::LAND_SIZE - 1 && inCellY == 0) && (useTool || isLandLoaded(cellUpRightId)))
{
if (allowLandShapeEditing(cellUpRightId, useTool) && allowLandShapeEditing(cellRightId, useTool)
&& allowLandShapeEditing(cellUpId, useTool))
else if ((inCellX == ESM::Land::LAND_SIZE - 1 && inCellY == 0) && (useTool || isLandLoaded(cellUpRightId)))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(1, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredHeight(cornerCellCoords, 0, ESM::Land::LAND_SIZE - 1, alteredHeight);
if (allowLandShapeEditing(cellUpRightId, useTool) && allowLandShapeEditing(cellRightId, useTool)
&& allowLandShapeEditing(cellUpId, useTool))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(1, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords)
== mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredAbsoluteHeight(cornerCellCoords, 0, ESM::Land::LAND_SIZE - 1, absoluteHeight);
}
else
return;
}
else
return;
}
else if ((inCellX == ESM::Land::LAND_SIZE - 1 && inCellY == ESM::Land::LAND_SIZE - 1)
&& (useTool || isLandLoaded(cellDownRightId)))
{
if (allowLandShapeEditing(cellDownRightId, useTool) && allowLandShapeEditing(cellRightId, useTool)
&& allowLandShapeEditing(cellDownId, useTool))
else if ((inCellX == ESM::Land::LAND_SIZE - 1 && inCellY == ESM::Land::LAND_SIZE - 1)
&& (useTool || isLandLoaded(cellDownRightId)))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(1, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredHeight(cornerCellCoords, 0, 0, alteredHeight);
if (allowLandShapeEditing(cellDownRightId, useTool) && allowLandShapeEditing(cellRightId, useTool)
&& allowLandShapeEditing(cellDownId, useTool))
{
CSMWorld::CellCoordinates cornerCellCoords = cellCoords.move(1, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), cornerCellCoords)
== mAlteredCells.end())
mAlteredCells.emplace_back(cornerCellCoords);
paged->setCellAlteredAbsoluteHeight(cornerCellCoords, 0, 0, absoluteHeight);
}
else
return;
}
else
return;
}
// Change values of edging cells
if ((inCellX == 0) && (useTool || isLandLoaded(cellLeftId)))
{
if (allowLandShapeEditing(cellLeftId, useTool))
// Change values of edging cells
if ((inCellX == 0) && (useTool || isLandLoaded(cellLeftId)))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(-1, 0);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredHeight(edgeCellCoords, ESM::Land::LAND_SIZE - 1, inCellY, alteredHeight);
if (allowLandShapeEditing(cellLeftId, useTool))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(-1, 0);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredAbsoluteHeight(
edgeCellCoords, ESM::Land::LAND_SIZE - 1, inCellY, absoluteHeight);
}
}
}
if ((inCellY == 0) && (useTool || isLandLoaded(cellUpId)))
{
if (allowLandShapeEditing(cellUpId, useTool))
if ((inCellY == 0) && (useTool || isLandLoaded(cellUpId)))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(0, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredHeight(edgeCellCoords, inCellX, ESM::Land::LAND_SIZE - 1, alteredHeight);
if (allowLandShapeEditing(cellUpId, useTool))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(0, -1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredAbsoluteHeight(
edgeCellCoords, inCellX, ESM::Land::LAND_SIZE - 1, absoluteHeight);
}
}
}
if ((inCellX == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellRightId)))
{
if (allowLandShapeEditing(cellRightId, useTool))
if ((inCellX == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellRightId)))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(1, 0);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredHeight(edgeCellCoords, 0, inCellY, alteredHeight);
if (allowLandShapeEditing(cellRightId, useTool))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(1, 0);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredAbsoluteHeight(edgeCellCoords, 0, inCellY, absoluteHeight);
}
}
}
if ((inCellY == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellDownId)))
{
if (allowLandShapeEditing(cellDownId, useTool))
if ((inCellY == ESM::Land::LAND_SIZE - 1) && (useTool || isLandLoaded(cellDownId)))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(0, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredHeight(edgeCellCoords, inCellX, 0, alteredHeight);
if (allowLandShapeEditing(cellDownId, useTool))
{
CSMWorld::CellCoordinates edgeCellCoords = cellCoords.move(0, 1);
if (useTool
&& std::find(mAlteredCells.begin(), mAlteredCells.end(), edgeCellCoords) == mAlteredCells.end())
mAlteredCells.emplace_back(edgeCellCoords);
paged->setCellAlteredHeight(cellCoords, inCellX, inCellY, alteredHeight);
paged->setCellAlteredAbsoluteHeight(edgeCellCoords, inCellX, 0, absoluteHeight);
}
}
}
}

View File

@ -59,16 +59,21 @@ namespace CSVRender
float TerrainStorage::getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY)
{
float height = 0.f;
std::optional<float> true_height = getOriginalHeight(cellX, cellY, inCellX, inCellY);
if (true_height)
return *true_height + *getAlteredHeight(inCellX, inCellY);
return 0.0f;
}
std::optional<float> TerrainStorage::getOriginalHeight(int cellX, int cellY, int inCellX, int inCellY)
{
const int index
= mData.getLand().searchId(ESM::RefId::stringRefId(CSMWorld::Land::createUniqueRecordId(cellX, cellY)));
if (index == -1) // no land!
return height;
return {};
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;
return landData->mHeights[inCellY * ESM::Land::LAND_SIZE + inCellX];
}
float* TerrainStorage::getAlteredHeight(int inCellX, int inCellY)

View File

@ -31,6 +31,7 @@ namespace CSVRender
bool useAlteration() const override { return true; }
float getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY);
std::optional<float> getOriginalHeight(int cellX, int cellY, int inCellX, int inCellY);
float* getAlteredHeight(int inCellX, int inCellY);
private: