Atlas: Fixed entities-don't-move-when-terrain-is-altered. Unbroke and fixed entity memory management. Added flatten tool. Added object movement/rotation/deletion tool - but not yet finished, since 'redo' usually crashes (for known reasons).
This was SVN commit r3207.
This commit is contained in:
parent
ce3bd33d76
commit
5250814397
@ -154,7 +154,7 @@ void CEntity::kill()
|
||||
m_bounds = NULL;
|
||||
|
||||
m_destroyed = true;
|
||||
Shutdown();
|
||||
//Shutdown(); // PT: tentatively removed - this seems to be called by ~CJSComplex, and we don't want to do it twice
|
||||
|
||||
if( m_actor )
|
||||
{
|
||||
@ -617,6 +617,11 @@ void CEntity::interpolate( float relativeoffset )
|
||||
}
|
||||
}
|
||||
|
||||
void CEntity::invalidateActor()
|
||||
{
|
||||
m_actor_transform_valid = false;
|
||||
}
|
||||
|
||||
void CEntity::render()
|
||||
{
|
||||
if( !m_orderQueue.empty() )
|
||||
@ -988,6 +993,7 @@ bool CEntity::Order( JSContext* cx, uintN argc, jsval* argv, bool Queued )
|
||||
break;
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
case CEntityOrder::ORDER_HEAL:
|
||||
if( argc < 1 )
|
||||
{
|
||||
JS_ReportError( cx, "Too few parameters" );
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
float m_graphics_orientation;
|
||||
|
||||
// If the actor's current transform data is valid (i.e. the entity hasn't
|
||||
// moved since it was last calculated).
|
||||
// moved since it was last calculated, and the terrain hasn't been changed).
|
||||
bool m_actor_transform_valid;
|
||||
|
||||
//-- Scripts
|
||||
@ -167,6 +167,10 @@ public:
|
||||
// Updates graphical information for a point between the last and current simulation frame; 0 < relativeoffset < 1.
|
||||
void interpolate( float relativeoffset );
|
||||
|
||||
// Forces update of actor information during next call to 'interpolate'.
|
||||
// (Necessary when terrain might move underneath the actor.)
|
||||
void invalidateActor();
|
||||
|
||||
// Updates auras
|
||||
void UpdateAuras( size_t timestep_millis );
|
||||
|
||||
|
@ -36,6 +36,13 @@ CEntityManager::~CEntityManager()
|
||||
m_entities[i].m_entity = 0;
|
||||
m_entities[i].m_refcount = 0;
|
||||
}
|
||||
|
||||
// Delete entities that were killed, but not yet reaped by a call to updateAll,
|
||||
// to avoid memory leak warnings upon exiting
|
||||
std::vector<CEntity*>::iterator it;
|
||||
for( it = m_reaper.begin(); it < m_reaper.end(); it++ )
|
||||
delete( *it );
|
||||
m_reaper.clear();
|
||||
}
|
||||
|
||||
void CEntityManager::deleteAll()
|
||||
@ -45,6 +52,7 @@ void CEntityManager::deleteAll()
|
||||
if( m_entities[i].m_refcount )
|
||||
{
|
||||
delete( m_entities[i].m_entity );
|
||||
m_entities[i].m_entity = 0;
|
||||
m_entities[i].m_refcount = 0;
|
||||
}
|
||||
m_nextalloc = 0;
|
||||
@ -179,13 +187,17 @@ void CEntityManager::renderAll()
|
||||
m_entities[i].m_entity->render();
|
||||
}
|
||||
|
||||
void CEntityManager::invalidateAll()
|
||||
{
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
m_entities[i].m_entity->invalidateActor();
|
||||
}
|
||||
|
||||
void CEntityManager::destroy( u16 handle )
|
||||
{
|
||||
if (m_entities[handle].m_entity->me.m_handle != INVALID_HANDLE)
|
||||
{
|
||||
m_reaper.push_back( m_entities[handle].m_entity );
|
||||
m_entities[handle].m_entity->me.m_handle = INVALID_HANDLE;
|
||||
}
|
||||
m_reaper.push_back( m_entities[handle].m_entity );
|
||||
m_entities[handle].m_entity->me.m_handle = INVALID_HANDLE;
|
||||
}
|
||||
|
||||
bool CEntityManager::m_extant = false;
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
void InitializeAll();
|
||||
void TickAll();
|
||||
void renderAll();
|
||||
void invalidateAll();
|
||||
|
||||
void deleteAll();
|
||||
|
||||
|
@ -393,8 +393,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
||||
ToolButtonBar* toolbar = new ToolButtonBar(this, ID_Toolbar);
|
||||
// (button label; tooltip text; image; internal tool name)
|
||||
toolbar->AddToolButton(_("Default"), _("Default"), _T("default.png"), _T(""));
|
||||
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("MoveObject"));
|
||||
toolbar->AddToolButton(_("Move"), _("Move/rotate object"), _T("moveobject.png"), _T("TransformObject"));
|
||||
toolbar->AddToolButton(_("Elevation"), _("Alter terrain elevation"), _T("alterelevation.png"), _T("AlterElevation"));
|
||||
toolbar->AddToolButton(_("Flatten"), _("Flatten terrain elevation"), _T("flattenelevation.png"), _T("FlattenElevation"));
|
||||
toolbar->AddToolButton(_("Paint Terrain"), _("Paint terrain texture"), _T("paintterrain.png"), _T("PaintTerrain"));
|
||||
toolbar->Realize();
|
||||
SetToolBar(toolbar);
|
||||
|
@ -38,7 +38,7 @@ ObjectSidebar::ObjectSidebar(wxWindow* parent)
|
||||
|
||||
}
|
||||
|
||||
wxWindow* ObjectSidebar::GetBottomBar(wxWindow* parent)
|
||||
wxWindow* ObjectSidebar::GetBottomBar(wxWindow* WXUNUSED(parent))
|
||||
{
|
||||
if (m_BottomBar)
|
||||
return m_BottomBar;
|
||||
|
@ -23,6 +23,7 @@ TerrainSidebar::TerrainSidebar(wxWindow* parent)
|
||||
{
|
||||
wxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Elevation tools"));
|
||||
sizer->Add(new ToolButton(this, _("Modify"), _T("AlterElevation"), wxSize(50,20)));
|
||||
sizer->Add(new ToolButton(this, _("Flatten"), _T("FlattenElevation"), wxSize(50,20)));
|
||||
// sizer->Add(new ToolButton(this, _("Smooth"), _T(""), wxSize(50,20)));
|
||||
// sizer->Add(new ToolButton(this, _("Sample"), _T(""), wxSize(50,20)));
|
||||
sizer->Add(new ToolButton(this, _("Paint"), _T("PaintTerrain"), wxSize(50,20)));
|
||||
|
@ -29,6 +29,7 @@ void SetCurrentTool(const wxString& name, void* initData)
|
||||
{
|
||||
g_CurrentTool->Shutdown();
|
||||
delete g_CurrentTool;
|
||||
g_CurrentTool = &dummy;
|
||||
}
|
||||
|
||||
SetActive(false, g_CurrentToolName);
|
||||
@ -38,13 +39,13 @@ void SetCurrentTool(const wxString& name, void* initData)
|
||||
{
|
||||
tool = wxDynamicCast(wxCreateDynamicObject(name), ITool);
|
||||
wxASSERT(tool);
|
||||
tool->Init(initData);
|
||||
}
|
||||
|
||||
if (tool == NULL)
|
||||
g_CurrentTool = &dummy;
|
||||
else
|
||||
if (tool)
|
||||
{
|
||||
g_CurrentTool = tool;
|
||||
tool->Init(initData);
|
||||
}
|
||||
|
||||
g_CurrentToolName = name;
|
||||
SetActive(true, g_CurrentToolName);
|
||||
|
@ -0,0 +1,98 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Common/Tools.h"
|
||||
#include "Common/Brushes.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
using AtlasMessage::Position;
|
||||
|
||||
class FlattenElevation : public StateDrivenTool<FlattenElevation>
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS(FlattenElevation);
|
||||
|
||||
Position m_Pos;
|
||||
|
||||
public:
|
||||
FlattenElevation()
|
||||
{
|
||||
SetState(&Waiting);
|
||||
}
|
||||
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
g_Brush_Elevation.MakeActive();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(false, Position()));
|
||||
}
|
||||
|
||||
|
||||
struct sWaiting : public State
|
||||
{
|
||||
bool OnMouse(FlattenElevation* obj, wxMouseEvent& evt)
|
||||
{
|
||||
if (evt.LeftDown())
|
||||
{
|
||||
obj->m_Pos = Position(evt.GetPosition());
|
||||
SET_STATE(Flattening);
|
||||
return true;
|
||||
}
|
||||
else if (evt.Moving())
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, Position(evt.GetPosition())));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Waiting;
|
||||
|
||||
|
||||
struct sFlattening : public State
|
||||
{
|
||||
void OnEnter(FlattenElevation* obj)
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
}
|
||||
|
||||
void OnLeave(FlattenElevation*)
|
||||
{
|
||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||
}
|
||||
|
||||
bool OnMouse(FlattenElevation* obj, wxMouseEvent& evt)
|
||||
{
|
||||
if (evt.LeftUp())
|
||||
{
|
||||
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(FlattenElevation* obj, float dt)
|
||||
{
|
||||
POST_COMMAND(FlattenElevation, (obj->m_Pos, dt*4096.f*g_Brush_Elevation.GetStrength()));
|
||||
obj->m_Pos = Position::Unchanged();
|
||||
}
|
||||
}
|
||||
Flattening;
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(FlattenElevation, StateDrivenTool<FlattenElevation>);
|
@ -0,0 +1,97 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Common/Tools.h"
|
||||
#include "Common/Brushes.h"
|
||||
#include "Common/MiscState.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
using AtlasMessage::Position;
|
||||
|
||||
class TransformObject : public StateDrivenTool<TransformObject>
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS(TransformObject);
|
||||
|
||||
std::vector<AtlasMessage::ObjectID> m_Selection;
|
||||
|
||||
public:
|
||||
TransformObject()
|
||||
{
|
||||
SetState(&Waiting);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
m_Selection.clear();
|
||||
POST_MESSAGE(SetSelectionPreview(m_Selection));
|
||||
}
|
||||
|
||||
|
||||
// TODO: keys to rotate/move object?
|
||||
|
||||
struct sWaiting : public State
|
||||
{
|
||||
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
||||
{
|
||||
if (evt.LeftDown())
|
||||
{
|
||||
// TODO: multiple selection
|
||||
AtlasMessage::qSelectObject qry(Position(evt.GetPosition()));
|
||||
qry.Post();
|
||||
obj->m_Selection.clear();
|
||||
obj->m_Selection.push_back(qry.id);
|
||||
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||
SET_STATE(Dragging);
|
||||
return true;
|
||||
}
|
||||
else if (evt.Dragging() && evt.RightIsDown() || evt.RightDown())
|
||||
{
|
||||
Position pos (evt.GetPosition());
|
||||
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
|
||||
POST_COMMAND(RotateObject, (obj->m_Selection[i], true, pos, 0.f));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
||||
{
|
||||
if (type == KEY_CHAR && evt.GetKeyCode() == WXK_DELETE)
|
||||
{
|
||||
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
|
||||
POST_COMMAND(DeleteObject, (obj->m_Selection[i]));
|
||||
obj->m_Selection.clear();
|
||||
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Waiting;
|
||||
|
||||
struct sDragging : public State
|
||||
{
|
||||
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
||||
{
|
||||
if (evt.LeftUp())
|
||||
{
|
||||
SET_STATE(Waiting);
|
||||
return true;
|
||||
}
|
||||
else if (evt.Dragging())
|
||||
{
|
||||
Position pos (evt.GetPosition());
|
||||
for (size_t i = 0; i < obj->m_Selection.size(); ++i)
|
||||
POST_COMMAND(MoveObject, (obj->m_Selection[i], pos));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Dragging;
|
||||
};
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(TransformObject, StateDrivenTool<TransformObject>);
|
@ -28,7 +28,7 @@ void Brush::SetData(int w, int h, const float* data)
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
void Brush::GetBottomRight(int& x, int& y) const
|
||||
void Brush::GetCentre(int& x, int& y) const
|
||||
{
|
||||
CVector3D c = m_Centre;
|
||||
if (m_W % 2) c.X += CELL_SIZE/2.f;
|
||||
@ -36,8 +36,15 @@ void Brush::GetBottomRight(int& x, int& y) const
|
||||
i32 cx, cy;
|
||||
CTerrain::CalcFromPosition(c, cx, cy);
|
||||
|
||||
x = cx - (m_W-1)/2;
|
||||
y = cy - (m_H-1)/2;
|
||||
x = cx;
|
||||
y = cy;
|
||||
}
|
||||
|
||||
void Brush::GetBottomRight(int& x, int& y) const
|
||||
{
|
||||
GetCentre(x, y);
|
||||
x -= (m_W-1)/2;
|
||||
y -= (m_H-1)/2;
|
||||
}
|
||||
|
||||
void Brush::SetRenderEnabled(bool enabled)
|
||||
|
@ -12,6 +12,7 @@ struct Brush
|
||||
void SetRenderEnabled(bool enabled); // initial state is disabled
|
||||
void Render(); // only does anything if enabled
|
||||
|
||||
void GetCentre(int& x, int& y) const;
|
||||
void GetBottomRight(int& x, int& y) const;
|
||||
|
||||
float Get(int x, int y) const
|
||||
|
@ -44,6 +44,11 @@ CommandProc::CommandProc()
|
||||
}
|
||||
|
||||
CommandProc::~CommandProc()
|
||||
{
|
||||
debug_assert(!m_Commands.size());
|
||||
}
|
||||
|
||||
void CommandProc::Destroy()
|
||||
{
|
||||
for_each(m_Commands.begin(), m_Commands.end(), delete_fn<Command>);
|
||||
m_Commands.clear();
|
||||
|
@ -20,6 +20,10 @@ public:
|
||||
CommandProc();
|
||||
~CommandProc();
|
||||
|
||||
// Should be called before shutting down, so it can free
|
||||
// references to entities/etc that are stored in commands
|
||||
void Destroy();
|
||||
|
||||
void Submit(Command* cmd);
|
||||
|
||||
void Undo();
|
||||
@ -42,6 +46,7 @@ struct DataCommand : public Command // so commands can optionally override (De|C
|
||||
{
|
||||
void Destruct() {};
|
||||
void Construct() {};
|
||||
// MergeWithSelf should update 'prev' to include the effects of 'this'
|
||||
void MergeWithSelf(void*) { debug_warn("MergeWithSelf unimplemented in some command"); }
|
||||
};
|
||||
|
||||
|
@ -22,10 +22,16 @@
|
||||
using namespace AtlasMessage;
|
||||
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
extern void AtlasRenderSelection();
|
||||
}
|
||||
|
||||
void AtlasRender()
|
||||
{
|
||||
Render();
|
||||
g_CurrentBrush.Render();
|
||||
AtlasRenderSelection();
|
||||
}
|
||||
|
||||
|
||||
|
@ -7,45 +7,76 @@
|
||||
#include "graphics/Terrain.h"
|
||||
#include "ps/Game.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "simulation/EntityManager.h"
|
||||
|
||||
#include "../Brushes.h"
|
||||
#include "../DeltaArray.h"
|
||||
|
||||
namespace AtlasMessage {
|
||||
|
||||
BEGIN_COMMAND(AlterElevation)
|
||||
|
||||
class TerrainArray : public DeltaArray2D<u16>
|
||||
class TerrainArray : public DeltaArray2D<u16>
|
||||
{
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
m_Heightmap = g_Game->GetWorld()->GetTerrain()->GetHeightMap();
|
||||
m_VertsPerSide = g_Game->GetWorld()->GetTerrain()->GetVerticesPerSide();
|
||||
}
|
||||
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;
|
||||
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));
|
||||
}
|
||||
set(x,y, (u16)clamp(get(x,y) + amount, 0, 65535));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
void MoveVertexTowards(int x, int y, int target, int amount)
|
||||
{
|
||||
if ((unsigned)x >= m_VertsPerSide || (unsigned)y >= m_VertsPerSide)
|
||||
return;
|
||||
|
||||
u16* m_Heightmap;
|
||||
size_t m_VertsPerSide;
|
||||
};
|
||||
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;
|
||||
|
||||
@ -59,7 +90,6 @@ BEGIN_COMMAND(AlterElevation)
|
||||
|
||||
void Do()
|
||||
{
|
||||
|
||||
int amount = (int)d->amount;
|
||||
|
||||
// If the framerate is very high, 'amount' is often very
|
||||
@ -89,18 +119,21 @@ BEGIN_COMMAND(AlterElevation)
|
||||
}
|
||||
|
||||
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 MergeWithSelf(cAlterElevation* prev)
|
||||
@ -110,4 +143,66 @@ BEGIN_COMMAND(AlterElevation)
|
||||
|
||||
END_COMMAND(AlterElevation)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BEGIN_COMMAND(FlattenElevation)
|
||||
|
||||
TerrainArray m_TerrainDelta;
|
||||
|
||||
void Construct()
|
||||
{
|
||||
m_TerrainDelta.Init();
|
||||
}
|
||||
void Destruct()
|
||||
{
|
||||
}
|
||||
|
||||
void Do()
|
||||
{
|
||||
int amount = (int)d->amount;
|
||||
|
||||
static CVector3D previousPosition;
|
||||
d->pos.GetWorldSpace(g_CurrentBrush.m_Centre, 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.GetBottomRight(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 MergeWithSelf(cFlattenElevation* prev)
|
||||
{
|
||||
prev->m_TerrainDelta.OverlayWith(m_TerrainDelta);
|
||||
}
|
||||
|
||||
END_COMMAND(FlattenElevation)
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "MessageHandler.h"
|
||||
#include "../GameLoop.h"
|
||||
#include "../CommandProc.h"
|
||||
|
||||
#include "renderer/Renderer.h"
|
||||
#include "gui/GUI.h"
|
||||
@ -34,7 +35,12 @@ MESSAGEHANDLER_STR(init)
|
||||
|
||||
MESSAGEHANDLER_STR(shutdown)
|
||||
{
|
||||
// Empty the CommandProc, to get rid of its references to entities before
|
||||
// we kill the EntityManager
|
||||
GetCommandProc().Destroy();
|
||||
|
||||
Shutdown();
|
||||
|
||||
g_GameLoop->rendering = false;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Game.h"
|
||||
#include "lib/ogl.h"
|
||||
|
||||
#define LOG_CATEGORY "editor"
|
||||
|
||||
@ -31,6 +32,47 @@ QUERYHANDLER(GetEntitiesList)
|
||||
}
|
||||
|
||||
|
||||
static std::vector<ObjectID> g_Selection;
|
||||
void AtlasRenderSelection()
|
||||
{
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
for (size_t i = 0; i < g_Selection.size(); ++i)
|
||||
{
|
||||
if (g_Selection[i])
|
||||
{
|
||||
CUnit* unit = static_cast<CUnit*>(g_Selection[i]);
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->renderSelectionOutline();
|
||||
else if (unit->GetModel())
|
||||
{
|
||||
const CBound& bound = unit->GetModel()->GetBounds();
|
||||
// Expand bounds by 10% around the centre
|
||||
CVector3D centre;
|
||||
bound.GetCentre(centre);
|
||||
CVector3D a = (bound[0] - centre) * 1.1f + centre;
|
||||
CVector3D b = (bound[1] - centre) * 1.1f + centre;
|
||||
float h = g_Game->GetWorld()->GetTerrain()->getExactGroundLevel(centre.X, centre.Z);
|
||||
glColor3f(0.8f, 0.8f, 0.8f);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
glVertex3f(a.X, h, a.Z);
|
||||
glVertex3f(a.X, h, b.Z);
|
||||
glVertex3f(b.X, h, b.Z);
|
||||
glVertex3f(b.X, h, a.Z);
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
MESSAGEHANDLER(SetSelectionPreview)
|
||||
{
|
||||
g_Selection = msg->ids;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static CUnit* g_PreviewUnit = NULL;
|
||||
static CStrW g_PreviewUnitID;
|
||||
|
||||
@ -104,13 +146,6 @@ BEGIN_COMMAND(CreateEntity)
|
||||
CVector3D m_Pos;
|
||||
float m_Angle;
|
||||
|
||||
void Construct()
|
||||
{
|
||||
}
|
||||
void Destruct()
|
||||
{
|
||||
}
|
||||
|
||||
void Do()
|
||||
{
|
||||
m_Pos = GetUnitPos(d->pos);
|
||||
@ -160,4 +195,245 @@ BEGIN_COMMAND(CreateEntity)
|
||||
END_COMMAND(CreateEntity)
|
||||
|
||||
|
||||
QUERYHANDLER(SelectObject)
|
||||
{
|
||||
float x, y;
|
||||
msg->pos.GetScreenSpace(x, y);
|
||||
|
||||
CVector3D rayorigin, raydir;
|
||||
g_Game->GetView()->GetCamera()->BuildCameraRay(x, y, rayorigin, raydir);
|
||||
|
||||
CUnit* target = g_UnitMan.PickUnit(rayorigin, raydir);
|
||||
|
||||
msg->id = static_cast<void*>(target);
|
||||
}
|
||||
|
||||
|
||||
BEGIN_COMMAND(MoveObject)
|
||||
|
||||
CVector3D m_PosOld, m_PosNew;
|
||||
|
||||
void Do()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
m_PosOld = unit->GetEntity()->m_position;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
{
|
||||
CMatrix3D m = unit->GetModel()->GetTransform();
|
||||
m_PosOld = m.GetTranslation();
|
||||
}
|
||||
|
||||
m_PosNew = GetUnitPos(d->pos);
|
||||
|
||||
SetPos(m_PosNew);
|
||||
}
|
||||
|
||||
void SetPos(CVector3D& pos)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
unit->GetEntity()->m_position = pos;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
{
|
||||
CMatrix3D m = unit->GetModel()->GetTransform();
|
||||
m.Translate(pos - m.GetTranslation());
|
||||
unit->GetModel()->SetTransform(m);
|
||||
}
|
||||
}
|
||||
|
||||
void Redo()
|
||||
{
|
||||
SetPos(m_PosNew);
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
SetPos(m_PosOld);
|
||||
}
|
||||
|
||||
void MergeWithSelf(cMoveObject* prev)
|
||||
{
|
||||
// TODO: merge correctly when prev unit != this unit
|
||||
prev->m_PosNew = m_PosNew;
|
||||
}
|
||||
|
||||
END_COMMAND(MoveObject)
|
||||
|
||||
|
||||
BEGIN_COMMAND(RotateObject)
|
||||
|
||||
float m_AngleOld, m_AngleNew;
|
||||
CMatrix3D m_TransformOld, m_TransformNew;
|
||||
|
||||
void Do()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
m_AngleOld = unit->GetEntity()->m_orientation;
|
||||
if (d->usetarget)
|
||||
{
|
||||
CVector3D& pos = unit->GetEntity()->m_position;
|
||||
CVector3D target;
|
||||
d->target.GetWorldSpace(target, pos.Y);
|
||||
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
|
||||
m_AngleNew = atan2(dir.x, dir.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AngleNew = d->angle;
|
||||
}
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
{
|
||||
m_TransformOld = unit->GetModel()->GetTransform();
|
||||
|
||||
CVector3D pos = unit->GetModel()->GetTransform().GetTranslation();
|
||||
|
||||
float s, c;
|
||||
if (d->usetarget)
|
||||
{
|
||||
CVector3D target;
|
||||
d->target.GetWorldSpace(target, pos.Y);
|
||||
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
|
||||
dir = dir.normalize();
|
||||
s = dir.x;
|
||||
c = dir.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
s = sinf(d->angle);
|
||||
c = cosf(d->angle);
|
||||
}
|
||||
CMatrix3D& m = m_TransformNew;
|
||||
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = pos.X;
|
||||
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = pos.Y;
|
||||
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = pos.Z;
|
||||
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
||||
}
|
||||
|
||||
SetAngle(m_AngleNew, m_TransformNew);
|
||||
}
|
||||
|
||||
void SetAngle(float angle, CMatrix3D& transform)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
{
|
||||
unit->GetEntity()->m_orientation = angle;
|
||||
}
|
||||
else if (unit->GetModel())
|
||||
{
|
||||
unit->GetModel()->SetTransform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
void Redo()
|
||||
{
|
||||
SetAngle(m_AngleNew, m_TransformNew);
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
SetAngle(m_AngleOld, m_TransformOld);
|
||||
}
|
||||
|
||||
void MergeWithSelf(cRotateObject* prev)
|
||||
{
|
||||
// TODO: merge correctly when prev unit != this unit
|
||||
prev->m_AngleNew = m_AngleNew;
|
||||
prev->m_TransformNew = m_TransformNew;
|
||||
}
|
||||
|
||||
END_COMMAND(RotateObject)
|
||||
|
||||
|
||||
BEGIN_COMMAND(DeleteObject)
|
||||
|
||||
bool m_ObjectAlive;
|
||||
|
||||
void Construct()
|
||||
{
|
||||
m_ObjectAlive = true;
|
||||
}
|
||||
|
||||
void Destruct()
|
||||
{
|
||||
if (! m_ObjectAlive)
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->kill();
|
||||
else
|
||||
{
|
||||
g_UnitMan.RemoveUnit(unit);
|
||||
delete unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Do()
|
||||
{
|
||||
Redo();
|
||||
}
|
||||
|
||||
void Redo()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
// HACK: I don't know the proper way of undoably deleting entities...
|
||||
unit->GetEntity()->m_destroyed = true;
|
||||
|
||||
g_UnitMan.RemoveUnit(unit);
|
||||
|
||||
m_ObjectAlive = false;
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
if (! d->id)
|
||||
return;
|
||||
|
||||
CUnit* unit = static_cast<CUnit*>(d->id);
|
||||
|
||||
if (unit->GetEntity())
|
||||
unit->GetEntity()->m_destroyed = false;
|
||||
|
||||
g_UnitMan.AddUnit(unit);
|
||||
|
||||
m_ObjectAlive = true;
|
||||
}
|
||||
|
||||
END_COMMAND(DeleteObject)
|
||||
|
||||
|
||||
}
|
||||
|
@ -153,6 +153,11 @@ COMMAND(AlterElevation, MERGE,
|
||||
((float, amount))
|
||||
);
|
||||
|
||||
COMMAND(FlattenElevation, MERGE,
|
||||
((Position, pos))
|
||||
((float, amount))
|
||||
);
|
||||
|
||||
struct ePaintTerrainPriority { enum { HIGH, LOW }; };
|
||||
COMMAND(PaintTerrain, MERGE,
|
||||
((Position, pos))
|
||||
@ -162,6 +167,36 @@ COMMAND(PaintTerrain, MERGE,
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef void* ObjectID;
|
||||
|
||||
QUERY(SelectObject,
|
||||
((Position, pos))
|
||||
,
|
||||
((ObjectID, id))
|
||||
);
|
||||
|
||||
COMMAND(MoveObject, MERGE,
|
||||
((ObjectID, id))
|
||||
((Position, pos))
|
||||
);
|
||||
|
||||
COMMAND(RotateObject, MERGE,
|
||||
((ObjectID, id))
|
||||
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
|
||||
((Position, target))
|
||||
((float, angle))
|
||||
);
|
||||
|
||||
COMMAND(DeleteObject, NOMERGE,
|
||||
((ObjectID, id))
|
||||
);
|
||||
|
||||
MESSAGE(SetSelectionPreview,
|
||||
((std::vector<ObjectID>, ids))
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "MessagesSetup.h"
|
||||
|
||||
#endif // MESSAGES_H__
|
||||
|
Loading…
Reference in New Issue
Block a user