0ad/source/tools/atlas/GameInterface/Handlers/ElevationHandlers.cpp
janwas 73683b6109 # SwEng
. the massive renaming undertaking: camelCase functions -> PascalCase.
. add some cppdoc.
. minor additional renaming improvements: e.g. GetIsClosed -> IsClosed
. in entity code, replace constructs like "pvec = new vector; return
pvec; use *pvec; delete pvec" with a simple stack variable passed as
output parameter (avoid unnecessary dynamic allocs)
. timer: simpler handling of raw ticks vs normal timer (less #if)

This was SVN commit r5017.
2007-05-02 12:07:08 +00:00

205 lines
4.6 KiB
C++

#include "precompiled.h"
#include "MessageHandler.h"
#include "../CommandProc.h"
#include "graphics/Terrain.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "maths/MathUtil.h"
#include "simulation/EntityManager.h"
#include "graphics/RenderableObject.h"
#include "../Brushes.h"
#include "../DeltaArray.h"
namespace AtlasMessage {
class TerrainArray : public DeltaArray2D<u16>
{
public:
void Init()
{
m_Heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap();
m_VertsPerSide = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
}
void RaiseVertex(int x, int y, int amount)
{
// Ignore out-of-bounds vertices
if ((unsigned)x >= m_VertsPerSide || (unsigned)y >= m_VertsPerSide)
return;
set(x,y, (u16)clamp(get(x,y) + amount, 0, 65535));
}
void MoveVertexTowards(int x, int y, int target, int amount)
{
if ((unsigned)x >= m_VertsPerSide || (unsigned)y >= m_VertsPerSide)
return;
int h = get(x,y);
if (h < target)
h = std::min(target, h + amount);
else if (h > target)
h = std::max(target, h - amount);
else
return;
set(x,y, (u16)clamp(h, 0, 65535));
}
void SetVertex(int x, int y, u16 value)
{
if ((unsigned)x >= m_VertsPerSide || (unsigned)y >= m_VertsPerSide)
return;
set(x,y, value);
}
u16 GetVertex(int x, int y)
{
return get(clamp(x, 0, (int)m_VertsPerSide-1), clamp(y, 0, (int)m_VertsPerSide-1));
}
protected:
u16 getOld(int x, int y)
{
return m_Heightmap[y*m_VertsPerSide + x];
}
void setNew(int x, int y, const u16& val)
{
m_Heightmap[y*m_VertsPerSide + x] = val;
}
u16* m_Heightmap;
size_t m_VertsPerSide;
};
BEGIN_COMMAND(AlterElevation)
{
TerrainArray m_TerrainDelta;
cAlterElevation()
{
m_TerrainDelta.Init();
}
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;
int x0, y0;
g_CurrentBrush.GetBottomLeft(x0, y0);
for (int dy = 0; dy < g_CurrentBrush.m_H; ++dy)
for (int dx = 0; dx < g_CurrentBrush.m_W; ++dx)
{
// TODO: proper variable raise amount (store floats in terrain delta array?)
float b = g_CurrentBrush.Get(dx, dy);
if (b)
m_TerrainDelta.RaiseVertex(x0+dx, y0+dy, (int)(amount*b));
}
g_Game->GetWorld()->GetTerrain()->MakeDirty(x0, y0, x0+g_CurrentBrush.m_W, y0+g_CurrentBrush.m_H, RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Undo()
{
m_TerrainDelta.Undo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Redo()
{
m_TerrainDelta.Redo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void MergeIntoPrevious(cAlterElevation* prev)
{
prev->m_TerrainDelta.OverlayWith(m_TerrainDelta);
}
};
END_COMMAND(AlterElevation)
//////////////////////////////////////////////////////////////////////////
BEGIN_COMMAND(FlattenElevation)
{
TerrainArray m_TerrainDelta;
cFlattenElevation()
{
m_TerrainDelta.Init();
}
void Do()
{
int amount = (int)msg->amount;
static CVector3D previousPosition;
g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace(previousPosition);
previousPosition = g_CurrentBrush.m_Centre;
int xc, yc;
g_CurrentBrush.GetCentre(xc, yc);
u16 height = m_TerrainDelta.GetVertex(xc, yc);
int x0, y0;
g_CurrentBrush.GetBottomLeft(x0, y0);
for (int dy = 0; dy < g_CurrentBrush.m_H; ++dy)
for (int dx = 0; dx < g_CurrentBrush.m_W; ++dx)
{
float b = g_CurrentBrush.Get(dx, dy);
if (b)
m_TerrainDelta.MoveVertexTowards(x0+dx, y0+dy, height, 1 + (int)(b*amount));
}
g_Game->GetWorld()->GetTerrain()->MakeDirty(x0, y0, x0+g_CurrentBrush.m_W, y0+g_CurrentBrush.m_H, RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Undo()
{
m_TerrainDelta.Undo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void Redo()
{
m_TerrainDelta.Redo();
g_Game->GetWorld()->GetTerrain()->MakeDirty(RENDERDATA_UPDATE_VERTICES);
g_EntityManager.InvalidateAll();
}
void MergeIntoPrevious(cFlattenElevation* prev)
{
prev->m_TerrainDelta.OverlayWith(m_TerrainDelta);
}
};
END_COMMAND(FlattenElevation)
}