Merge pull request #1388 from Azaezel/alpha41/erosionBrushes

additional terrain brushes
This commit is contained in:
Brian Roberts 2025-02-20 12:08:22 -06:00 committed by GitHub
commit 7bb8587db5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 349 additions and 62 deletions

View file

@ -26,6 +26,7 @@
#include "gui/core/guiCanvas.h"
TerrainScratchPad gTerrainScratchPad;
//------------------------------------------------------------------------------
bool TerrainAction::isValid(GridInfo tile)
{
@ -746,60 +747,212 @@ void PaintNoiseAction::process(Selection * sel, const Gui3DMouseEvent &, bool se
mTerrainEditor->scheduleGridUpdate();
}
}
/*
void ThermalErosionAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
void ThermalErosionAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type type)
{
if( selChanged )
// If this is the ending
// mouse down event, then
// update the noise values.
TerrainBlock* tblock = mTerrainEditor->getActiveTerrain();
if (!tblock)
return;
F32 selRange = sel->getMaxHeight()-sel->getMinHeight();
F32 avg = sel->getAvgHeight();
if (selChanged)
{
TerrainBlock *tblock = mTerrainEditor->getActiveTerrain();
if ( !tblock )
return;
F32 height = 0;
F32 maxHeight = 0;
U32 shift = getBinLog2( TerrainBlock::BlockSize );
for ( U32 x = 0; x < TerrainBlock::BlockSize; x++ )
{
for ( U32 y = 0; y < TerrainBlock::BlockSize; y++ )
{
height = fixedToFloat( tblock->getHeight( x, y ) );
mTerrainHeights[ x + (y << 8)] = height;
if ( height > maxHeight )
maxHeight = height;
}
}
//mNoise.erodeThermal( &mTerrainHeights, &mNoiseData, 30.0f, 5.0f, 5, TerrainBlock::BlockSize, tblock->getSquareSize(), maxHeight );
mNoise.erodeHydraulic( &mTerrainHeights, &mNoiseData, 1, TerrainBlock::BlockSize );
F32 heightDiff = 0;
for( U32 i = 0; i < sel->size(); i++ )
for (U32 i = 0; i < sel->size(); i++)
{
if (!isValid((*sel)[i]))
continue;
mTerrainEditor->getUndoSel()->add((*sel)[i]);
const Point2I &gridPos = (*sel)[i].mGridPoint.gridPos;
// Need to get the height difference
// between the current height and the
// erosion height to properly apply the
// softness and pressure settings of the brush
// for this selection.
heightDiff = (*sel)[i].mHeight - mNoiseData[ gridPos.x + (gridPos.y << shift)];
F32 bias = ((*sel)[i].mHeight - avg) / selRange;
F32 nudge = mRandF(-mTerrainEditor->getBrushPressure(), mTerrainEditor->getBrushPressure());
F32 heightTarg = mRoundF((*sel)[i].mHeight - bias * nudge, mTerrainEditor->getBrushPressure() * 2.0f) ;
heightDiff = heightTarg - (*sel)[i].mHeight;
(*sel)[i].mHeight += heightDiff * (*sel)[i].mWeight;
(*sel)[i].mHeight -= (heightDiff * (*sel)[i].mWeight);
if ((*sel)[i].mHeight > mTerrainEditor->mTileMaxHeight)
(*sel)[i].mHeight = mTerrainEditor->mTileMaxHeight;
if ((*sel)[i].mHeight < mTerrainEditor->mTileMinHeight)
(*sel)[i].mHeight = mTerrainEditor->mTileMinHeight;
mTerrainEditor->setGridInfo((*sel)[i]);
}
mTerrainEditor->gridUpdateComplete();
mTerrainEditor->scheduleGridUpdate();
}
}
*/
void HydraulicErosionAction::process(Selection* sel, const Gui3DMouseEvent&, bool selChanged, Type type)
{
// If this is the ending
// mouse down event, then
// update the noise values.
TerrainBlock* tblock = mTerrainEditor->getActiveTerrain();
if (!tblock)
return;
F32 selRange = sel->getMaxHeight() - sel->getMinHeight();
F32 avg = sel->getAvgHeight();
if (selChanged)
{
F32 heightDiff = 0;
const F32 squareSize = tblock->getSquareSize();
for (U32 i = 0; i < sel->size(); i++)
{
if (!isValid((*sel)[i]))
continue;
mTerrainEditor->getUndoSel()->add((*sel)[i]);
Point2F p;
Point3F norm;
p.x = (*sel)[i].mGridPoint.gridPos.x * squareSize;
p.y = (*sel)[i].mGridPoint.gridPos.y * squareSize;
tblock->getNormal(p, &norm, true);
F32 bias = mPow(norm.z,3.0f) * ((*sel)[i].mHeight - avg) / selRange;
F32 nudge = mRandF(-mTerrainEditor->getBrushPressure(), mTerrainEditor->getBrushPressure());
heightDiff = bias * (-(*sel)[i].mHeight + bias * nudge) / tblock->getObjBox().len_z() * 2.0;
(*sel)[i].mHeight += heightDiff * (*sel)[i].mWeight;
if ((*sel)[i].mHeight > mTerrainEditor->mTileMaxHeight)
(*sel)[i].mHeight = mTerrainEditor->mTileMaxHeight;
if ((*sel)[i].mHeight < mTerrainEditor->mTileMinHeight)
(*sel)[i].mHeight = mTerrainEditor->mTileMinHeight;
mTerrainEditor->setGridInfo((*sel)[i]);
}
mTerrainEditor->scheduleGridUpdate();
}
}
void TerrainScratchPad::addTile(F32 height, U8 material)
{
mContents.push_back(new gridStub(height, material));
mBottom = mMin(height, mBottom);
mTop = mMax(height, mTop);
};
void TerrainScratchPad::clear()
{
for (U32 i = 0; i < mContents.size(); i++)
delete(mContents[i]);
mContents.clear();
mBottom = F32_MAX;
mTop = F32_MIN_EX;
}
void copyAction::process(Selection* sel, const Gui3DMouseEvent&, bool selChanged, Type type)
{
gTerrainScratchPad.clear();
for (U32 i=0;i<sel->size();i++)
{
if (isValid((*sel)[i]))
gTerrainScratchPad.addTile((*sel)[i].mHeight, (*sel)[i].mMaterial);
else
gTerrainScratchPad.addTile(0, 0);
}
}
void pasteAction::process(Selection* sel, const Gui3DMouseEvent&, bool selChanged, Type type)
{
if (gTerrainScratchPad.size() == 0)
return;
if (gTerrainScratchPad.size() != sel->size())
return;
if (type != Begin)
return;
for (U32 i = 0; i < sel->size(); i++)
{
if (isValid((*sel)[i]))
{
mTerrainEditor->getUndoSel()->add((*sel)[i]);
(*sel)[i].mHeight = gTerrainScratchPad[i]->mHeight;
(*sel)[i].mMaterial = gTerrainScratchPad[i]->mMaterial;
mTerrainEditor->setGridInfo((*sel)[i]);
}
}
mTerrainEditor->scheduleGridUpdate();
mTerrainEditor->scheduleMaterialUpdate();
}
void pasteUpAction::process(Selection* sel, const Gui3DMouseEvent&, bool selChanged, Type type)
{
if (gTerrainScratchPad.size() == 0)
return;
if (gTerrainScratchPad.size() != sel->size())
return;
if (type != Begin)
return;
F32 floor = F32_MAX;
for (U32 i = 0; i < sel->size(); i++)
{
floor = mMin((*sel)[i].mHeight, floor);
}
for (U32 i = 0; i < sel->size(); i++)
{
if (isValid((*sel)[i]))
{
mTerrainEditor->getUndoSel()->add((*sel)[i]);
(*sel)[i].mHeight = gTerrainScratchPad[i]->mHeight - gTerrainScratchPad.mBottom + floor;
(*sel)[i].mMaterial = gTerrainScratchPad[i]->mMaterial;
mTerrainEditor->setGridInfo((*sel)[i]);
}
}
mTerrainEditor->scheduleGridUpdate();
mTerrainEditor->scheduleMaterialUpdate();
}
void pasteDownAction::process(Selection* sel, const Gui3DMouseEvent&, bool selChanged, Type type)
{
if (gTerrainScratchPad.size() == 0)
return;
if (gTerrainScratchPad.size() != sel->size())
return;
if (type != Begin)
return;
F32 ceiling = F32_MIN_EX;
for (U32 i = 0; i < sel->size(); i++)
{
ceiling = mMax((*sel)[i].mHeight, ceiling);
}
for (U32 i = 0; i < sel->size(); i++)
{
if (isValid((*sel)[i]))
{
mTerrainEditor->getUndoSel()->add((*sel)[i]);
(*sel)[i].mHeight = gTerrainScratchPad[i]->mHeight - gTerrainScratchPad.mTop + ceiling;
(*sel)[i].mMaterial = gTerrainScratchPad[i]->mMaterial;
mTerrainEditor->setGridInfo((*sel)[i]);
}
}
mTerrainEditor->scheduleGridUpdate();
mTerrainEditor->scheduleMaterialUpdate();
}
IMPLEMENT_CONOBJECT( TerrainSmoothAction );

View file

@ -302,27 +302,94 @@ class PaintNoiseAction : public TerrainAction
F32 mScale;
};
/*
class ThermalErosionAction : public TerrainAction
{
public:
ThermalErosionAction(TerrainEditor * editor)
: TerrainAction(editor)
{
mNoise.setSeed( 1 );//Sim::getCurrentTime() );
mNoiseData.setSize( TerrainBlock::BlockSize * TerrainBlock::BlockSize );
mTerrainHeights.setSize( TerrainBlock::BlockSize * TerrainBlock::BlockSize );
}
}
StringTableEntry getName(){return("thermalErode");}
void process(Selection * sel, const Gui3DMouseEvent & event, bool selChanged, Type type);
Noise2D mNoise;
Vector<F32> mNoiseData;
Vector<F32> mTerrainHeights;
};
*/
class HydraulicErosionAction : public TerrainAction
{
public:
HydraulicErosionAction(TerrainEditor* editor)
: TerrainAction(editor)
{
}
StringTableEntry getName() { return("hydraulicErode"); }
void process(Selection* sel, const Gui3DMouseEvent& event, bool selChanged, Type type);
};
class TerrainScratchPad
{
public:
F32 mBottom, mTop;
TerrainScratchPad(): mBottom(F32_MAX), mTop(F32_MIN_EX){};
~TerrainScratchPad() { mContents.clear(); };
void clear();
class gridStub
{
public:
gridStub(F32 height, U8 material) : mHeight(height), mMaterial(material) {};
F32 mHeight;
U8 mMaterial;
};
void addTile(F32 height, U8 material);
U32 size() { return(mContents.size()); };
gridStub* operator [](U32 index) { return mContents[index]; };
private:
Vector<gridStub*> mContents;
};
class copyAction : public TerrainAction
{
public:
copyAction(TerrainEditor* editor)
: TerrainAction(editor)
{
}
StringTableEntry getName() { return("copy"); }
void process(Selection* sel, const Gui3DMouseEvent& event, bool selChanged, Type type);
};
class pasteAction : public TerrainAction
{
public:
pasteAction(TerrainEditor* editor)
: TerrainAction(editor)
{
}
StringTableEntry getName() { return("paste"); }
void process(Selection* sel, const Gui3DMouseEvent& event, bool selChanged, Type type);
};
class pasteUpAction : public TerrainAction
{
public:
pasteUpAction(TerrainEditor* editor)
: TerrainAction(editor)
{
}
StringTableEntry getName() { return("pasteUp"); }
void process(Selection* sel, const Gui3DMouseEvent& event, bool selChanged, Type type);
};
class pasteDownAction : public TerrainAction
{
public:
pasteDownAction(TerrainEditor* editor)
: TerrainAction(editor)
{
}
StringTableEntry getName() { return("pasteDown"); }
void process(Selection* sel, const Gui3DMouseEvent& event, bool selChanged, Type type);
};
/// An undo action used to perform terrain wide smoothing.
class TerrainSmoothAction : public UndoAction

View file

@ -712,8 +712,13 @@ TerrainEditor::TerrainEditor() :
mActions.push_back(new SmoothHeightAction(this));
mActions.push_back(new SmoothSlopeAction(this));
mActions.push_back(new PaintNoiseAction(this));
//mActions.push_back(new ThermalErosionAction(this));
mActions.push_back(new ThermalErosionAction(this));
mActions.push_back(new HydraulicErosionAction(this));
mActions.push_back(new copyAction(this));
mActions.push_back(new pasteAction(this));
mActions.push_back(new pasteUpAction(this));
mActions.push_back(new pasteDownAction(this));
// set the default action
mCurrentAction = mActions[0];

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="Copy_terr_d_image"
imageFile="@assetFile=Copy_terr_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="Copy_terr_h_image"
imageFile="@assetFile=Copy_terr_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="Copy_terr_n_image"
imageFile="@assetFile=Copy_terr_n.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeH_d_image"
imageFile="@assetFile=erodeH_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeH_h_image"
imageFile="@assetFile=erodeH_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeH_n_image"
imageFile="@assetFile=erodeH_n.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeT_d_image"
imageFile="@assetFile=erodeT_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeT_h_image"
imageFile="@assetFile=erodeT_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="erodeT_n_image"
imageFile="@assetFile=erodeT_n.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteDown_terr_d_image"
imageFile="@assetFile=pasteDown_terr_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteDown_terr_h_image"
imageFile="@assetFile=pasteDown_terr_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteDown_terr_n_image"
imageFile="@assetFile=pasteDown_terr_n.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteUp_terr_d_image"
imageFile="@assetFile=pasteUp_terr_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteUp_terr_h_image"
imageFile="@assetFile=pasteUp_terr_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="pasteUp_terr_n_image"
imageFile="@assetFile=pasteUp_terr_n.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="paste_terr_d_image"
imageFile="@assetFile=paste_terr_d.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="paste_terr_h_image"
imageFile="@assetFile=paste_terr_h.png"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

View file

@ -0,0 +1,3 @@
<ImageAsset
AssetName="paste_terr_n_image"
imageFile="@assetFile=paste_terr_n.png"/>

View file

@ -1205,10 +1205,12 @@ function TerrainEditorPlugin::onWorldEditorStartup( %this )
%map.bindCmd( keyboard, "4", "ToolsPaletteArray->smoothHeight.performClick();", "" ); // Average Height
%map.bindCmd( keyboard, "5", "ToolsPaletteArray->smoothSlope.performClick();", "" ); // Smooth Slope
%map.bindCmd( keyboard, "6", "ToolsPaletteArray->paintNoise.performClick();", "" ); // Noise
%map.bindCmd( keyboard, "7", "ToolsPaletteArray->flattenHeight.performClick();", "" ); // Flatten
%map.bindCmd( keyboard, "8", "ToolsPaletteArray->setHeight.performClick();", "" ); // Set Height
%map.bindCmd( keyboard, "9", "ToolsPaletteArray->setEmpty.performClick();", "" ); // Clear Terrain
%map.bindCmd( keyboard, "0", "ToolsPaletteArray->clearEmpty.performClick();", "" ); // Restore Terrain
%map.bindCmd( keyboard, "6", "ToolsPaletteArray->thermalErode.performClick();", "" ); // Noise
%map.bindCmd( keyboard, "7", "ToolsPaletteArray->hydraulicErode.performClick();", "" ); // Noise
%map.bindCmd( keyboard, "8", "ToolsPaletteArray->flattenHeight.performClick();", "" ); // Flatten
%map.bindCmd( keyboard, "9", "ToolsPaletteArray->setHeight.performClick();", "" ); // Set Height
%map.bindCmd( keyboard, "0", "ToolsPaletteArray->setEmpty.performClick();", "" ); // Clear Terrain
%map.bindCmd( keyboard, "shift 0", "ToolsPaletteArray->clearEmpty.performClick();", "" ); // Restore Terrain
%map.bindCmd( keyboard, "v", "EWTerrainEditToolbarBrushType->ellipse.performClick();", "" );// Circle Brush
%map.bindCmd( keyboard, "b", "EWTerrainEditToolbarBrushType->box.performClick();", "" );// Box Brush
%map.bindCmd( keyboard, "=", "TerrainEditorPlugin.keyboardModifyBrushSize(1);", "" );// +1 Brush Size
@ -1248,11 +1250,17 @@ function EditorGui::SetTerrainPalletBar()
EWToolsPaletteWindow.addButton("LowerHeight", "ToolsModule:lowerHeight_n_image", "ETerrainEditor.switchAction( lowerHeight );", "", "Lower Height", "3");
EWToolsPaletteWindow.addButton("SmoothHeight", "ToolsModule:smoothHeight_n_image", "ETerrainEditor.switchAction( smoothHeight );", "", "Smooth Height", "4");
EWToolsPaletteWindow.addButton("SmoothSlope", "ToolsModule:softCurve_n_image", "ETerrainEditor.switchAction( smoothSlope );", "", "Smooth Slope", "5");
EWToolsPaletteWindow.addButton("PaintNoise", "ToolsModule:brushPaintNoise_n_image", "ETerrainEditor.switchAction( paintNoise );", "", "Paint Noise", "6");
EWToolsPaletteWindow.addButton("FlattenHeight", "ToolsModule:flattenHeight_n_image", "ETerrainEditor.switchAction( flattenHeight );", "", "Flatten Height", "7");
EWToolsPaletteWindow.addButton("SetHeight", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( setHeight );", "", "Set Height", "8");
EWToolsPaletteWindow.addButton("SetEmpty", "ToolsModule:setEmpty_n_image", "ETerrainEditor.switchAction( setEmpty );", "", "Set Empty", "9");
EWToolsPaletteWindow.addButton("ClearEmpty", "ToolsModule:clearEmpty_n_image", "ETerrainEditor.switchAction( clearEmpty );", "", "Clear Empty", "0");
EWToolsPaletteWindow.addButton("PaintNoise", "ToolsModule:brushPaintNoise_n_image", "ETerrainEditor.switchAction( paintNoise );", "", "Paint Noise", "6");
EWToolsPaletteWindow.addButton("thermalErode", "ToolsModule:brushPaintNoise_n_image", "ETerrainEditor.switchAction( thermalErode );", "", "thermal Erode", "7");
EWToolsPaletteWindow.addButton("hydraulicErode", "ToolsModule:brushPaintNoise_n_image", "ETerrainEditor.switchAction( hydraulicErode );", "", "hydraulic Erode", "8");
EWToolsPaletteWindow.addButton("FlattenHeight", "ToolsModule:flattenHeight_n_image", "ETerrainEditor.switchAction( flattenHeight );", "", "Flatten Height", "9");
EWToolsPaletteWindow.addButton("SetHeight", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( setHeight );", "", "Set Height", "0");
EWToolsPaletteWindow.addButton("SetEmpty", "ToolsModule:setEmpty_n_image", "ETerrainEditor.switchAction( setEmpty );", "", "Set Empty", "0");
EWToolsPaletteWindow.addButton("ClearEmpty", "ToolsModule:clearEmpty_n_image", "ETerrainEditor.switchAction( clearEmpty );", "", "Clear Empty", "shift 0");
EWToolsPaletteWindow.addButton("Copy", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( copy );", "", "copy", "ctrl C");
EWToolsPaletteWindow.addButton("Paste", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( paste );", "", "paste", "ctrl v");
EWToolsPaletteWindow.addButton("pasteUp", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( pasteUp );", "", "pasteUp", "ctrl b");
EWToolsPaletteWindow.addButton("PasteDown", "ToolsModule:setHeight_n_image", "ETerrainEditor.switchAction( pasteDown );", "", "pasteDown", "ctrl n");
EWToolsPaletteWindow.refresh();
}