# Add terrain smoothing tool to Atlas, based on patch from DigitalSeraphim.

Fixes #516.

This was SVN commit r7854.
This commit is contained in:
Ykkrosh 2010-08-05 20:43:31 +00:00
parent b4e409e80d
commit 40e268e06a
7 changed files with 264 additions and 0 deletions

View file

@ -129,6 +129,7 @@ function init(window, bottomWindow)
var tools = [
{ label: 'Modify', name: 'AlterElevation' },
{ label: 'Smooth', name: 'SmoothElevation' },
{ label: 'Flatten', name: 'FlattenElevation' },
{ label: 'Paint', name: 'PaintTerrain' },
];

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5a94e39d63db9302d0bbbb5b6e1dcc43a426d87823639156a7d489d6111d6764
size 2002

View file

@ -474,6 +474,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""), _T(""));
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"), _T("")/*_T("ObjectSidebar")*/);
toolbar->AddToolButton(_("Elevation"), _("Alter terrain elevation"), _T("alterelevation.png"), _T("AlterElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Smooth"), _("Smooth terrain elevation"), _T("smoothelevation.png"), _T("SmoothElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Flatten"), _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"), _T("")/*_T("TerrainSidebar")*/);
toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"), _T("paintterrain.png"), _T("PaintTerrain"), _T("")/*_T("TerrainSidebar")*/);

View file

@ -56,6 +56,7 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
{
wxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Elevation tools"));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Modify"), _T("AlterElevation"), wxSize(50,20)));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T("SmoothElevation"), wxSize(50,20)));
sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Flatten"), _T("FlattenElevation"), wxSize(50,20)));
// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Smooth"), _T(""), wxSize(50,20)));
// sizer->Add(new ToolButton(scenarioEditor.GetToolManager(), this, _("Sample"), _T(""), wxSize(50,20)));

View file

@ -0,0 +1,140 @@
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "Common/Tools.h"
#include "Common/Brushes.h"
#include "GameInterface/Messages.h"
using AtlasMessage::Position;
class SmoothElevation : public StateDrivenTool<SmoothElevation>
{
DECLARE_DYNAMIC_CLASS(SmoothElevation);
int m_Direction; // +1 = smoother, -1 = rougher
Position m_Pos;
public:
SmoothElevation()
{
SetState(&Waiting);
}
void OnEnable()
{
g_Brush_Elevation.MakeActive();
}
void OnDisable()
{
POST_MESSAGE(BrushPreview, (false, Position()));
}
struct sWaiting : public State
{
bool OnMouse(SmoothElevation* obj, wxMouseEvent& evt)
{
if (evt.LeftDown())
{
obj->m_Pos = Position(evt.GetPosition());
SET_STATE(Smoothing);
return true;
}
else if (evt.RightDown())
{
obj->m_Pos = Position(evt.GetPosition());
SET_STATE(Roughing);
return true;
}
else if (evt.Moving())
{
POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
return true;
}
else
{
return false;
}
}
}
Waiting;
struct sSmoothing_common : public State
{
void OnEnter(SmoothElevation* obj)
{
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
}
void OnLeave(SmoothElevation*)
{
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
}
bool OnMouse(SmoothElevation* obj, wxMouseEvent& evt)
{
if (IsMouseUp(evt))
{
SET_STATE(Waiting);
return true;
}
else if (evt.Dragging())
{
wxPoint pos = evt.GetPosition();
obj->m_Pos = Position(pos);
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
return true;
}
else
{
return false;
}
}
void OnTick(SmoothElevation* obj, float dt)
{
POST_COMMAND(SmoothElevation, (obj->m_Pos, dt*4096.f*GetDirection()*g_Brush_Elevation.GetStrength()));
obj->m_Pos = Position::Unchanged();
}
virtual bool IsMouseUp(wxMouseEvent& evt) = 0;
virtual int GetDirection() = 0;
};
struct sSmoothing : public sSmoothing_common
{
bool IsMouseUp(wxMouseEvent& evt) { return evt.LeftUp(); }
int GetDirection() { return +1; }
}
Smoothing;
struct sRoughing : public sSmoothing_common
{
bool IsMouseUp(wxMouseEvent& evt) { return evt.RightUp(); }
int GetDirection() { return -1; }
}
Roughing;
};
IMPLEMENT_DYNAMIC_CLASS(SmoothElevation, StateDrivenTool<SmoothElevation>);

View file

@ -96,6 +96,7 @@ protected:
ssize_t m_VertsPerSide;
};
//////////////////////////////////////////////////////////////////////////
BEGIN_COMMAND(AlterElevation)
{
@ -177,6 +178,118 @@ BEGIN_COMMAND(AlterElevation)
};
END_COMMAND(AlterElevation)
//////////////////////////////////////////////////////////////////////////
BEGIN_COMMAND(SmoothElevation)
{
TerrainArray m_TerrainDelta;
ssize_t m_i0, m_j0, m_i1, m_j1;
cSmoothElevation()
{
m_TerrainDelta.Init();
}
void MakeDirty()
{
g_Game->GetWorld()->GetTerrain()->MakeDirty(m_i0, m_j0, m_i1, m_j1, RENDERDATA_UPDATE_VERTICES);
CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
if (!cmpTerrain.null())
cmpTerrain->MakeDirty(m_i0, m_j0, m_i1, m_j1);
}
void Do()
{
int amount = (int)msg->amount;
// If the framerate is very high, 'amount' is often very
// small (even zero) so the integer truncation is significant
static float roundingError = 0.0;
roundingError += msg->amount - (float)amount;
if (roundingError >= 1.f)
{
amount += (int)roundingError;
roundingError -= (float)(int)roundingError;
}
static CVector3D previousPosition;
g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(previousPosition);
previousPosition = g_CurrentBrush.m_Centre;
ssize_t x0, y0;
g_CurrentBrush.GetBottomLeft(x0, y0);
if (g_CurrentBrush.m_H > 2)
{
std::vector<float> terrainDeltas;
ssize_t num = (g_CurrentBrush.m_H - 2) * (g_CurrentBrush.m_W - 2);
terrainDeltas.resize(num);
// For each vertex, compute the average of the 9 adjacent vertices
for (ssize_t dy = 0; dy < g_CurrentBrush.m_H; ++dy)
{
for (ssize_t dx = 0; dx < g_CurrentBrush.m_W; ++dx)
{
float delta = m_TerrainDelta.GetVertex(x0+dx, y0+dy) / 9.0f;
ssize_t x1_min = std::max((ssize_t)1, dx - 1);
ssize_t x1_max = std::min(dx + 1, g_CurrentBrush.m_W - 2);
ssize_t y1_min = std::max((ssize_t)1, dy - 1);
ssize_t y1_max = std::min(dy + 1, g_CurrentBrush.m_H - 2);
for (ssize_t yy = y1_min; yy <= y1_max; ++yy)
{
for (ssize_t xx = x1_min; xx <= x1_max; ++xx)
{
ssize_t index = (yy-1)*(g_CurrentBrush.m_W-2) + (xx-1);
terrainDeltas[index] += delta;
}
}
}
}
// Move each vertex towards the computed average of its neighbours
for (ssize_t dy = 1; dy < g_CurrentBrush.m_H - 1; ++dy)
{
for (ssize_t dx = 1; dx < g_CurrentBrush.m_W - 1; ++dx)
{
ssize_t index = (dy-1)*(g_CurrentBrush.m_W-2) + (dx-1);
float b = g_CurrentBrush.Get(dx, dy);
if (b)
m_TerrainDelta.MoveVertexTowards(x0+dx, y0+dy, (int)terrainDeltas[index], (int)(amount*b));
}
}
}
m_i0 = x0;
m_j0 = y0;
m_i1 = x0 + g_CurrentBrush.m_W;
m_j1 = y0 + g_CurrentBrush.m_H;
MakeDirty();
}
void Undo()
{
m_TerrainDelta.Undo();
MakeDirty();
}
void Redo()
{
m_TerrainDelta.Redo();
MakeDirty();
}
void MergeIntoPrevious(cSmoothElevation* prev)
{
prev->m_TerrainDelta.OverlayWith(m_TerrainDelta);
prev->m_i0 = std::min(prev->m_i0, m_i0);
prev->m_j0 = std::min(prev->m_j0, m_j0);
prev->m_i1 = std::max(prev->m_i1, m_i1);
prev->m_j1 = std::max(prev->m_j1, m_j1);
}
};
END_COMMAND(SmoothElevation)
//////////////////////////////////////////////////////////////////////////
BEGIN_COMMAND(FlattenElevation)

View file

@ -372,6 +372,11 @@ COMMAND(AlterElevation, MERGE,
((float, amount))
);
COMMAND(SmoothElevation, MERGE,
((Position, pos))
((float, amount))
);
COMMAND(FlattenElevation, MERGE,
((Position, pos))
((float, amount))