Improve land steepness limiting code

pull/556/head
Nelsson Huotari 5 years ago
parent c2428bc5fa
commit 54e13954e8

@ -238,6 +238,16 @@ void CSVRender::TerrainShapeMode::dragCompleted(const QPoint& pos)
undoStack.beginMacro ("Edit shape and normal records");
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
{
limitAlteredHeights(cellCoordinates);
}
std::reverse(mAlteredCells.begin(), mAlteredCells.end()); //Instead of alphabetical order, this should be fixed to sort cells by cell coordinates
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
{
limitAlteredHeights(cellCoordinates, true);
}
for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
{
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoordinates.getX(), cellCoordinates.getY());
@ -689,7 +699,8 @@ void CSVRender::TerrainShapeMode::flattenHeight(const CSMWorld::CellCoordinates&
}
void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoordinates& cellCoords, int inCellX, int inCellY, float* thisHeight,
float* thisAlteredHeight, float* leftHeight, float* leftAlteredHeight, float* upHeight, float* upAlteredHeight)
float* thisAlteredHeight, float* leftHeight, float* leftAlteredHeight, float* upHeight, float* upAlteredHeight, float* rightHeight,
float* rightAlteredHeight, float* downHeight, float* downAlteredHeight)
{
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
@ -699,13 +710,18 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY());
std::string cellLeftId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() - 1, cellCoords.getY());
std::string cellUpId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY() - 1);
std::string cellUpLeftId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() - 1, cellCoords.getY() - 1);
std::string cellRightId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() + 1, cellCoords.getY());
std::string cellDownId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY() + 1);
bool noCell = document.getData().getCells().searchId (cellId) == -1;
bool noLand = document.getData().getLand().searchId (cellId) == -1;
bool noLeftCell = document.getData().getCells().searchId (cellLeftId) == -1;
bool noLeftLand = document.getData().getLand().searchId (cellLeftId) == -1;
bool noUpCell = document.getData().getCells().searchId (cellUpId) == -1;
bool noUpLand = document.getData().getLand().searchId (cellUpId) == -1;
bool noRightCell = document.getData().getCells().searchId (cellRightId) == -1;
bool noRightLand = document.getData().getLand().searchId (cellRightId) == -1;
bool noDownCell = document.getData().getCells().searchId (cellDownId) == -1;
bool noDownLand = document.getData().getLand().searchId (cellDownId) == -1;
*thisHeight = 0.0f; // real + altered height
*thisAlteredHeight = 0.0f; // only altered height
@ -713,6 +729,10 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*leftAlteredHeight = 0.0f;
*upHeight = 0.0f;
*upAlteredHeight = 0.0f;
*rightHeight = 0.0f;
*rightAlteredHeight = 0.0f;
*downHeight = 0.0f;
*downAlteredHeight = 0.0f;
if (CSVRender::PagedWorldspaceWidget *paged =
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
@ -726,11 +746,14 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*thisAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY);
*thisHeight = landShapePointer[inCellY * landSize + inCellX] + *thisAlteredHeight;
// In case of cell edge, and touching cell/land is not found, assume that left and up -heights would be the same
// This is to prevent unnecessary action at limitHeightChange()
// Default to the same value as thisHeight, which happens in the case of cell edge where next cell/land is not found,
// which is to prevent unnecessary action at limitHeightChange().
*leftHeight = *thisHeight;
*upHeight = *thisHeight;
*rightHeight = *thisHeight;
*downHeight = *thisHeight;
//If at edge, get values from neighboring cell
if (inCellX == 0)
{
if(!noLeftCell && !noLeftLand)
@ -760,11 +783,43 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
}
}
}
if (inCellX == landSize - 1)
{
cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() + 1, cellCoords.getY());
if(!noRightCell && !noRightLand)
{
const CSMWorld::LandHeightsColumn::DataType landRightShapePointer =
landTable.data(landTable.getModelIndex(cellRightId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
*rightHeight = landRightShapePointer[inCellY * landSize + 1];
if (paged->getCellAlteredHeight(cellCoords.move(1, 0), 1, inCellY))
{
*rightAlteredHeight = *paged->getCellAlteredHeight(cellCoords.move(1, 0), 1, inCellY);
*rightHeight += *rightAlteredHeight;
}
}
}
if (inCellY == landSize - 1)
{
cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY() + 1);
if(!noDownCell && !noDownLand)
{
const CSMWorld::LandHeightsColumn::DataType landDownShapePointer =
landTable.data(landTable.getModelIndex(cellDownId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
*downHeight = landDownShapePointer[landSize + inCellX];
if (paged->getCellAlteredHeight(cellCoords.move(0, 1), inCellX, 1))
{
*downAlteredHeight = *paged->getCellAlteredHeight(cellCoords.move(0, 1), inCellX, 1);
*downHeight += *downAlteredHeight;
}
}
}
//If not at edge, get values from the same cell
if (inCellX != 0)
{
*leftHeight = landShapePointer[inCellY * landSize + inCellX - 1];
if (paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY))
*leftAlteredHeight += *paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY);
*leftAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY);
*leftHeight += *leftAlteredHeight;
}
if (inCellY != 0)
@ -774,6 +829,21 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*upAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY - 1);
*upHeight += *upAlteredHeight;
}
if (inCellX != landSize - 1)
{
*rightHeight = landShapePointer[inCellY * landSize + inCellX + 1];
if (paged->getCellAlteredHeight(cellCoords, inCellX + 1, inCellY))
*rightAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX + 1, inCellY);
*rightHeight += *rightAlteredHeight;
}
if (inCellY != landSize - 1)
{
*downHeight = landShapePointer[(inCellY + 1) * landSize + inCellX];
if (paged->getCellAlteredHeight(cellCoords, inCellX, inCellY + 1))
*downAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY + 1);
*downHeight += *downAlteredHeight;
}
}
}
}
@ -808,7 +878,7 @@ void CSVRender::TerrainShapeMode::fixEdges(const CSMWorld::CellCoordinates& cell
}
}
void CSVRender::TerrainShapeMode::limitAlteredHeights(const CSMWorld::CellCoordinates& cellCoords)
void CSVRender::TerrainShapeMode::limitAlteredHeights(const CSMWorld::CellCoordinates& cellCoords, bool reverseMode)
{
CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> (
@ -817,133 +887,125 @@ void CSVRender::TerrainShapeMode::limitAlteredHeights(const CSMWorld::CellCoordi
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY());
int limitHeightChange = 1024.0f; // Limited by save format
int limitHeightChange = 1016.0f; // Limited by save format
bool noCell = document.getData().getCells().searchId (cellId) == -1;
bool noLand = document.getData().getLand().searchId (cellId) == -1;
bool dataAlteredAtThisCell = false;
int maxPasses = 5; //Multiple passes are needed if there are consecutive height differences over the limit
if (!noCell && !noLand)
{
const CSMWorld::LandHeightsColumn::DataType landShapePointer =
landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
for (int passes = 0; passes < maxPasses; ++passes)
if (reverseMode == false)
{
for(int inCellX = 0; inCellX < landSize; ++inCellX)
for(int inCellY = 0; inCellY < landSize; ++inCellY)
{
for(int inCellY = 0; inCellY < landSize; ++inCellY)
for(int inCellX = 0; inCellX < landSize; ++inCellX)
{
// ### Variable naming key ###
// Variables here aim to hold the final value, which is (real_value + altered_value)
// this = this Cell
// left = x - 1, up = y - 1
// Altered = transient edit (in current edited)
// Binding = the last row or column, the one that binds cell land together
float thisHeight = 0.0f;
float thisAlteredHeight = 0.0f;
float leftHeight = 0.0f;
float leftAlteredHeight = 0.0f;
float upHeight = 0.0f;
float upAlteredHeight = 0.0f;
float rightHeight = 0.0f;
float rightAlteredHeight = 0.0f;
float downHeight = 0.0f;
float downAlteredHeight = 0.0f;
float* limitedAlteredHeightXAxis = nullptr;
float* limitedAlteredHeightYAxis = nullptr;
updateKeyHeightValues(cellCoords, inCellX, inCellY, &thisHeight, &thisAlteredHeight, &leftHeight, &leftAlteredHeight,
&upHeight, &upAlteredHeight);
bool doChange = false;
// Check for height limits, prioritize left over up, except in left-right -cell edges
if (thisHeight - upHeight >= limitHeightChange)
{
thisAlteredHeight = upHeight + (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
if (thisHeight - upHeight <= -limitHeightChange)
&upHeight, &upAlteredHeight, &rightHeight, &rightAlteredHeight, &downHeight, &downAlteredHeight);
// Check for height limits on x-axis
if (leftHeight - thisHeight > limitHeightChange)
limitedAlteredHeightXAxis = new float(leftHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
else if (leftHeight - thisHeight < -limitHeightChange)
limitedAlteredHeightXAxis = new float(leftHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
// Check for height limits on y-axis
if (upHeight - thisHeight > limitHeightChange)
limitedAlteredHeightYAxis = new float(upHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
else if (upHeight - thisHeight < -limitHeightChange)
limitedAlteredHeightYAxis = new float(upHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
// Limit altered height value based on x or y, whichever is the smallest
if (limitedAlteredHeightXAxis)
{
thisAlteredHeight = upHeight - (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
if (thisHeight - leftHeight >= limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1)))
{
thisAlteredHeight = leftHeight + (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
if (limitedAlteredHeightYAxis)
{
if(std::abs(*limitedAlteredHeightXAxis) >= std::abs(*limitedAlteredHeightYAxis))
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
else
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
}
else
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
}
if (thisHeight - leftHeight <= -limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1)))
else if (limitedAlteredHeightYAxis)
{
thisAlteredHeight = leftHeight - (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
// Apply limits
if (doChange == true)
{
alterHeight(cellCoords, inCellX, inCellY, thisAlteredHeight, false);
dataAlteredAtThisCell = true;
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
}
delete limitedAlteredHeightXAxis;
delete limitedAlteredHeightYAxis;
}
}
}
//Skip unneeded extra passes
if (dataAlteredAtThisCell == false)
{
passes = maxPasses;
continue;
}
//Inverse check (implement properly after default check works)
for(int inCellX = landSize - 1; inCellX >= 0; --inCellX)
if (reverseMode == true)
{
for(int inCellY = landSize - 1; inCellY >= 0; --inCellY)
{
for(int inCellY = landSize - 1; inCellY >= 0; --inCellY)
for(int inCellX = landSize - 1; inCellX >= 0; --inCellX)
{
// ### Variable naming key ###
// Variables here aim to hold the final value, which is (real_value + altered_value)
// this = this Cell
// left = x - 1, up = y - 1
// Altered = transient edit (in current edited)
// Binding = the last row or column, the one that binds cell land together
float thisHeight = 0.0f;
float thisAlteredHeight = 0.0f;
float leftHeight = 0.0f;
float leftAlteredHeight = 0.0f;
float upHeight = 0.0f;
float upAlteredHeight = 0.0f;
float rightHeight = 0.0f;
float rightAlteredHeight = 0.0f;
float downHeight = 0.0f;
float downAlteredHeight = 0.0f;
float* limitedAlteredHeightXAxis = nullptr;
float* limitedAlteredHeightYAxis = nullptr;
updateKeyHeightValues(cellCoords, inCellX, inCellY, &thisHeight, &thisAlteredHeight, &leftHeight, &leftAlteredHeight,
&upHeight, &upAlteredHeight);
bool doChange = false;
// Check for height limits, prioritize left over up, except in left-right -cell edges
if (thisHeight - upHeight >= limitHeightChange)
{
thisAlteredHeight = upHeight + limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
if (thisHeight - upHeight <= -limitHeightChange)
&upHeight, &upAlteredHeight, &rightHeight, &rightAlteredHeight, &downHeight, &downAlteredHeight);
// Check for height limits on x-axis
if (rightHeight - thisHeight > limitHeightChange)
limitedAlteredHeightXAxis = new float(rightHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
else if (rightHeight - thisHeight < -limitHeightChange)
limitedAlteredHeightXAxis = new float(rightHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
// Check for height limits on y-axis
if (downHeight - thisHeight > limitHeightChange)
limitedAlteredHeightYAxis = new float(downHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
else if (downHeight - thisHeight < -limitHeightChange)
limitedAlteredHeightYAxis = new float(downHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
// Limit altered height value based on x or y, whichever is the smallest
if (limitedAlteredHeightXAxis)
{
thisAlteredHeight = upHeight - limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
if (thisHeight - leftHeight >= limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1)))
{
thisAlteredHeight = leftHeight + limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
}
if (thisHeight - leftHeight <= -limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1)))
{
thisAlteredHeight = leftHeight - limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
if (limitedAlteredHeightYAxis)
{
if(std::abs(*limitedAlteredHeightXAxis) >= std::abs(*limitedAlteredHeightYAxis))
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
else
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
}
else
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
}
// Apply limits
if (doChange == true)
else if (limitedAlteredHeightYAxis)
{
alterHeight(cellCoords, inCellX, inCellY, thisAlteredHeight, false);
dataAlteredAtThisCell = true;
alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
}
}
delete limitedAlteredHeightXAxis;
delete limitedAlteredHeightYAxis; }
}
}
}

@ -93,15 +93,16 @@ namespace CSVRender
/// Do a single flattening height alteration for transient shape edit map
void flattenHeight(const CSMWorld::CellCoordinates& cellCoords, int inCellX, int inCellY, int toolStrength, int targetHeight);
/// Update the key values used in height calculations
/// Get altered height values around one vertex
void updateKeyHeightValues(const CSMWorld::CellCoordinates& cellCoords, int inCellX, int inCellY, float* thisHeight,
float* thisAlteredHeight, float* leftHeight, float* leftAlteredHeight, float* upHeight, float* upAlteredHeight);
float* thisAlteredHeight, float* leftHeight, float* leftAlteredHeight, float* upHeight, float* upAlteredHeight,
float* rightHeight, float* rightAlteredHeight, float* downHeight, float* downAlteredHeight);
/// Bind edge vertices to next cells
void fixEdges(const CSMWorld::CellCoordinates& cellCoords);
/// Check that the edit doesn't break save format limits, fix if necessary
void limitAlteredHeights(const CSMWorld::CellCoordinates& cellCoords);
void limitAlteredHeights(const CSMWorld::CellCoordinates& cellCoords, bool reverseMode = false);
/// Handle brush mechanics for terrain shape selection
void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation);
@ -145,7 +146,6 @@ namespace CSVRender
void passBrushTexture(std::string brushTexture);
public slots:
//void handleDropEvent(QDropEvent *event);
void setBrushSize(int brushSize);
void setBrushShape(int brushShape);
void setShapeEditTool(int shapeEditTool);

Loading…
Cancel
Save