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"); 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) for(CSMWorld::CellCoordinates cellCoordinates: mAlteredCells)
{ {
std::string cellId = CSMWorld::CellCoordinates::generateId(cellCoordinates.getX(), cellCoordinates.getY()); 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, 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(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> ( 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 cellId = CSMWorld::CellCoordinates::generateId(cellCoords.getX(), cellCoords.getY());
std::string cellLeftId = CSMWorld::CellCoordinates::generateId(cellCoords.getX() - 1, 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 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 noCell = document.getData().getCells().searchId (cellId) == -1;
bool noLand = document.getData().getLand().searchId (cellId) == -1; bool noLand = document.getData().getLand().searchId (cellId) == -1;
bool noLeftCell = document.getData().getCells().searchId (cellLeftId) == -1; bool noLeftCell = document.getData().getCells().searchId (cellLeftId) == -1;
bool noLeftLand = document.getData().getLand().searchId (cellLeftId) == -1; bool noLeftLand = document.getData().getLand().searchId (cellLeftId) == -1;
bool noUpCell = document.getData().getCells().searchId (cellUpId) == -1; bool noUpCell = document.getData().getCells().searchId (cellUpId) == -1;
bool noUpLand = document.getData().getLand().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 *thisHeight = 0.0f; // real + altered height
*thisAlteredHeight = 0.0f; // only altered height *thisAlteredHeight = 0.0f; // only altered height
@ -713,6 +729,10 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*leftAlteredHeight = 0.0f; *leftAlteredHeight = 0.0f;
*upHeight = 0.0f; *upHeight = 0.0f;
*upAlteredHeight = 0.0f; *upAlteredHeight = 0.0f;
*rightHeight = 0.0f;
*rightAlteredHeight = 0.0f;
*downHeight = 0.0f;
*downAlteredHeight = 0.0f;
if (CSVRender::PagedWorldspaceWidget *paged = if (CSVRender::PagedWorldspaceWidget *paged =
dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget())) dynamic_cast<CSVRender::PagedWorldspaceWidget *> (&getWorldspaceWidget()))
@ -726,11 +746,14 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*thisAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY); *thisAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY);
*thisHeight = landShapePointer[inCellY * landSize + inCellX] + *thisAlteredHeight; *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 // Default to the same value as thisHeight, which happens in the case of cell edge where next cell/land is not found,
// This is to prevent unnecessary action at limitHeightChange() // which is to prevent unnecessary action at limitHeightChange().
*leftHeight = *thisHeight; *leftHeight = *thisHeight;
*upHeight = *thisHeight; *upHeight = *thisHeight;
*rightHeight = *thisHeight;
*downHeight = *thisHeight;
//If at edge, get values from neighboring cell
if (inCellX == 0) if (inCellX == 0)
{ {
if(!noLeftCell && !noLeftLand) 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) if (inCellX != 0)
{ {
*leftHeight = landShapePointer[inCellY * landSize + inCellX - 1]; *leftHeight = landShapePointer[inCellY * landSize + inCellX - 1];
if (paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY)) if (paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY))
*leftAlteredHeight += *paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY); *leftAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX - 1, inCellY);
*leftHeight += *leftAlteredHeight; *leftHeight += *leftAlteredHeight;
} }
if (inCellY != 0) if (inCellY != 0)
@ -774,6 +829,21 @@ void CSVRender::TerrainShapeMode::updateKeyHeightValues(const CSMWorld::CellCoor
*upAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY - 1); *upAlteredHeight = *paged->getCellAlteredHeight(cellCoords, inCellX, inCellY - 1);
*upHeight += *upAlteredHeight; *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(); CSMDoc::Document& document = getWorldspaceWidget().getDocument();
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> ( 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()); 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 noCell = document.getData().getCells().searchId (cellId) == -1;
bool noLand = document.getData().getLand().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) if (!noCell && !noLand)
{ {
const CSMWorld::LandHeightsColumn::DataType landShapePointer = const CSMWorld::LandHeightsColumn::DataType landShapePointer =
landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>(); 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 thisHeight = 0.0f;
float thisAlteredHeight = 0.0f; float thisAlteredHeight = 0.0f;
float leftHeight = 0.0f; float leftHeight = 0.0f;
float leftAlteredHeight = 0.0f; float leftAlteredHeight = 0.0f;
float upHeight = 0.0f; float upHeight = 0.0f;
float upAlteredHeight = 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, updateKeyHeightValues(cellCoords, inCellX, inCellY, &thisHeight, &thisAlteredHeight, &leftHeight, &leftAlteredHeight,
&upHeight, &upAlteredHeight); &upHeight, &upAlteredHeight, &rightHeight, &rightAlteredHeight, &downHeight, &downAlteredHeight);
bool doChange = false; // Check for height limits on x-axis
if (leftHeight - thisHeight > limitHeightChange)
// Check for height limits, prioritize left over up, except in left-right -cell edges limitedAlteredHeightXAxis = new float(leftHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
if (thisHeight - upHeight >= limitHeightChange) else if (leftHeight - thisHeight < -limitHeightChange)
{ limitedAlteredHeightXAxis = new float(leftHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
thisAlteredHeight = upHeight + (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX];
doChange = true; // Check for height limits on y-axis
} if (upHeight - thisHeight > limitHeightChange)
if (thisHeight - upHeight <= -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]; if (limitedAlteredHeightYAxis)
doChange = true; {
} if(std::abs(*limitedAlteredHeightXAxis) >= std::abs(*limitedAlteredHeightYAxis))
if (thisHeight - leftHeight >= limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1))) alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
{ else
thisAlteredHeight = leftHeight + (limitHeightChange / 2) - landShapePointer[inCellY * landSize + inCellX]; alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
doChange = true; }
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]; alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
doChange = true;
}
// Apply limits
if (doChange == true)
{
alterHeight(cellCoords, inCellX, inCellY, thisAlteredHeight, false);
dataAlteredAtThisCell = true;
} }
delete limitedAlteredHeightXAxis;
delete limitedAlteredHeightYAxis;
} }
} }
}
//Skip unneeded extra passes if (reverseMode == true)
if (dataAlteredAtThisCell == false) {
{ for(int inCellY = landSize - 1; inCellY >= 0; --inCellY)
passes = maxPasses;
continue;
}
//Inverse check (implement properly after default check works)
for(int inCellX = landSize - 1; inCellX >= 0; --inCellX)
{ {
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 thisHeight = 0.0f;
float thisAlteredHeight = 0.0f; float thisAlteredHeight = 0.0f;
float leftHeight = 0.0f; float leftHeight = 0.0f;
float leftAlteredHeight = 0.0f; float leftAlteredHeight = 0.0f;
float upHeight = 0.0f; float upHeight = 0.0f;
float upAlteredHeight = 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, updateKeyHeightValues(cellCoords, inCellX, inCellY, &thisHeight, &thisAlteredHeight, &leftHeight, &leftAlteredHeight,
&upHeight, &upAlteredHeight); &upHeight, &upAlteredHeight, &rightHeight, &rightAlteredHeight, &downHeight, &downAlteredHeight);
bool doChange = false; // Check for height limits on x-axis
if (rightHeight - thisHeight > limitHeightChange)
// Check for height limits, prioritize left over up, except in left-right -cell edges limitedAlteredHeightXAxis = new float(rightHeight - limitHeightChange - (thisHeight - thisAlteredHeight));
if (thisHeight - upHeight >= limitHeightChange) else if (rightHeight - thisHeight < -limitHeightChange)
{ limitedAlteredHeightXAxis = new float(rightHeight + limitHeightChange - (thisHeight - thisAlteredHeight));
thisAlteredHeight = upHeight + limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true; // Check for height limits on y-axis
} if (downHeight - thisHeight > limitHeightChange)
if (thisHeight - upHeight <= -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]; if (limitedAlteredHeightYAxis)
doChange = true; {
} if(std::abs(*limitedAlteredHeightXAxis) >= std::abs(*limitedAlteredHeightYAxis))
if (thisHeight - leftHeight >= limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1))) alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
{ else
thisAlteredHeight = leftHeight + limitHeightChange - landShapePointer[inCellY * landSize + inCellX]; alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
doChange = true; }
} else
if (thisHeight - leftHeight <= -limitHeightChange && !(doChange == true && (inCellX == 0 || inCellX == landSize - 1))) alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightXAxis, false);
{
thisAlteredHeight = leftHeight - limitHeightChange - landShapePointer[inCellY * landSize + inCellX];
doChange = true;
} }
else if (limitedAlteredHeightYAxis)
// Apply limits
if (doChange == true)
{ {
alterHeight(cellCoords, inCellX, inCellY, thisAlteredHeight, false); alterHeight(cellCoords, inCellX, inCellY, *limitedAlteredHeightYAxis, false);
dataAlteredAtThisCell = true;
} }
} delete limitedAlteredHeightXAxis;
delete limitedAlteredHeightYAxis; }
} }
} }
} }

@ -93,15 +93,16 @@ namespace CSVRender
/// Do a single flattening height alteration for transient shape edit map /// 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); 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, 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 /// Bind edge vertices to next cells
void fixEdges(const CSMWorld::CellCoordinates& cellCoords); void fixEdges(const CSMWorld::CellCoordinates& cellCoords);
/// Check that the edit doesn't break save format limits, fix if necessary /// 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 /// Handle brush mechanics for terrain shape selection
void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation); void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation);
@ -145,7 +146,6 @@ namespace CSVRender
void passBrushTexture(std::string brushTexture); void passBrushTexture(std::string brushTexture);
public slots: public slots:
//void handleDropEvent(QDropEvent *event);
void setBrushSize(int brushSize); void setBrushSize(int brushSize);
void setBrushShape(int brushShape); void setBrushShape(int brushShape);
void setShapeEditTool(int shapeEditTool); void setShapeEditTool(int shapeEditTool);

Loading…
Cancel
Save