Atlas: Simple undo system

This was SVN commit r2627.
This commit is contained in:
Ykkrosh 2005-08-20 15:44:50 +00:00
parent a10082d69b
commit 5d62c3f3f7
28 changed files with 482 additions and 81 deletions

View File

@ -1,8 +1,5 @@
dofile("../functions.lua")
atlas = 0 -- temporarily disabled, until the whole of Atlas
-- can be integrated into this build process
-- Set up the Project
project.name = "pyrogenesis"
project.bindir = "../../../binaries/system"
@ -20,7 +17,6 @@ function setuppackage (projectname)
exename = "sced"
objdirprefix = "obj/ScEd_"
package.build = 0 -- Don't build Sced by default
atlas = 0 -- Don't build Atlas into ScEd
else
package.name = "pyrogenesis"
exename = "ps"
@ -72,7 +68,10 @@ function setuppackage (projectname)
"terrain",
"sound",
"scripting",
"i18n"
"i18n",
"tools/atlas/GameInterface",
"tools/atlas/GameInterface/Handlers"
}
if (projectname ~= "sced") then tconcat(source_dirs, {
@ -80,11 +79,6 @@ function setuppackage (projectname)
"gui/scripting"
}) end
if (atlas == 1) then tconcat(source_dirs, {
"tools/atlas/GameInterface",
"tools/atlas/GameInterface/Handlers"
}) end
if (projectname == "sced") then tconcat(source_dirs, {
"tools/sced",
"tools/sced/ui"
@ -145,10 +139,6 @@ function setuppackage (projectname)
tinsert(package.defines, "NO_MAIN_REDIRECT")
end
if (atlas == 1) then
tinsert(package.defines, "ATLAS")
end
-- Platform Specifics
if (OS == "windows") then

View File

@ -323,7 +323,7 @@ int main(int argc, char* argv[])
ATLAS_RunIfOnCmdLine(argc, argv);
// ELSE
Init(argc, argv, true);
Init(argc, argv, true, true);
MainControllerInit();
while(!quit)
@ -341,7 +341,7 @@ int main(int argc, char* argv[])
void Init_(int argc, char** argv, bool setup_gfx)
{
g_Quickstart = true;
Init(argc, argv, setup_gfx);
Init(argc, argv, setup_gfx, false);
}
void Shutdown_()
{

View File

@ -74,9 +74,13 @@ static void ATLAS_Run(int argc, char* argv[], int flags = 0)
return;
}
void(*pStartWindow)(int argc, char* argv[]);
*(void**)&pStartWindow = dlsym(atlas_so_handle, "_StartWindow");
pStartWindow(argc, argv);
// TODO (make nicer)
extern bool BeginAtlas(int argc, char* argv[], void* dll);
if (!BeginAtlas(argc, argv, atlas_so_handle))
{
debug_warn("Atlas loading failed");
return;
}
}

View File

@ -431,7 +431,7 @@ static void InitVfs(const char* argv0)
}
static void InitPs()
static void InitPs(bool setup_gui)
{
// console
{
@ -458,7 +458,8 @@ static void InitPs()
}
// GUI uses VFS, so this must come after VFS init.
GUI_Init();
if (setup_gui)
GUI_Init();
}
@ -584,8 +585,6 @@ void Shutdown()
{
MICROLOG(L"Shutdown");
ATLAS_Shutdown();
ShutdownPs(); // Must delete g_GUI before g_ScriptingHost
if (g_Game)
@ -652,7 +651,7 @@ void Shutdown()
# pragma optimize("", off)
#endif
void Init(int argc, char* argv[], bool setup_gfx = true)
void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui)
{
debug_printf("INIT &argc=%p &argv=%p\n", &argc, &argv);
@ -700,10 +699,6 @@ void Init(int argc, char* argv[], bool setup_gfx = true)
MICROLOG(L"init i18n");
I18n::LoadLanguage(NULL);
// should be done before the bulk of GUI init because it prevents
// most loads from happening (since ATLAS_IsRunning will return true).
ATLAS_RunIfOnCmdLine(argc, argv);
// Set up the console early, so that debugging
// messages can be logged to it. (The console's size
// and fonts are set later in InitPs())
@ -749,7 +744,7 @@ void Init(int argc, char* argv[], bool setup_gfx = true)
if(!g_Quickstart)
{
WriteSystemInfo();
vfs_display();
// vfs_display(); // disabled to decrease startup time
}
else
{
@ -781,7 +776,7 @@ void Init(int argc, char* argv[], bool setup_gfx = true)
#endif
MICROLOG(L"init ps");
InitPs();
InitPs(setup_gui);
oglCheck();
InitRenderer();

View File

@ -19,4 +19,4 @@ extern void Render();
extern void Shutdown();
extern void Init(int argc, char* argv[], bool setup_gfx = true);
extern void Init(int argc, char* argv[], bool setup_gfx, bool setup_gui);

View File

@ -20,6 +20,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ColourTester", "AtlasFronte
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyrogenesis", "..\..\..\build\workspaces\vc2003\pyrogenesis.vcproj", "{CDA14ADB-57CA-DB49-A474-E7605D7922BD}"
ProjectSection(ProjectDependencies) = postProject
{E99BA969-D540-4F23-822E-37C499E8F704} = {E99BA969-D540-4F23-822E-37C499E8F704}
EndProjectSection
EndProject
Global

View File

@ -1,7 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ATLASDLLIMPEXP __declspec(dllimport)
#define ATLASDLLIMPEXP extern "C" __declspec(dllimport)
#include "AtlasUI/Misc/DLLInterface.h"

View File

@ -1,7 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ATLASDLLIMPEXP __declspec(dllimport)
#define ATLASDLLIMPEXP extern "C" __declspec(dllimport)
#include "AtlasUI/Misc/DLLInterface.h"

View File

@ -1,7 +1,7 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ATLASDLLIMPEXP __declspec(dllimport)
#define ATLASDLLIMPEXP extern "C" __declspec(dllimport)
#include "AtlasUI/Misc/DLLInterface.h"

View File

@ -4,6 +4,7 @@
Version="7.10"
Name="AtlasUI"
ProjectGUID="{E99BA969-D540-4F23-822E-37C499E8F704}"
RootNamespace="AtlasUI"
Keyword="Win32Proj">
<Platforms>
<Platform

View File

@ -13,15 +13,18 @@ class AtlasWindowCommand : public wxCommand
public:
AtlasWindowCommand(bool canUndoIt, const wxString& name)
: wxCommand(canUndoIt, name), m_Finalized(false) {}
: wxCommand(canUndoIt, name), m_Finalized(false)
{ }
virtual bool Redo() { return Do(); }
private:
// Control merging of this command with a future one (so they
// can be undone in a single step). The function should try to merge
// with the previous command, by altering that previous command and then
// returning true. If it can't, return false.
virtual bool Merge(AtlasWindowCommand* WXUNUSED(previousCommand)) { return false; }
private:
bool m_Finalized;
};

View File

@ -41,4 +41,4 @@
#endif
#define ATLASDLLIMPEXP __declspec(dllexport)
#define ATLASDLLIMPEXP extern "C" __declspec(dllexport)

View File

@ -111,15 +111,70 @@ END_EVENT_TABLE()
//////////////////////////////////////////////////////////////////////////
enum
{
ID_Quit = 1,
// ID_New,
// // ID_Import,
// // ID_Export,
// ID_Open,
// ID_Save,
// ID_SaveAs,
};
BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_CLOSE(ScenarioEditor::OnClose)
EVT_TIMER(wxID_ANY, ScenarioEditor::OnTimer)
EVT_MENU(ID_Quit, ScenarioEditor::OnQuit)
EVT_MENU(wxID_UNDO, ScenarioEditor::OnUndo)
EVT_MENU(wxID_REDO, ScenarioEditor::OnRedo)
END_EVENT_TABLE()
static AtlasWindowCommandProc g_CommandProc;
AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc; }
ScenarioEditor::ScenarioEditor()
: wxFrame(NULL, wxID_ANY, _("Atlas - Scenario Editor"), wxDefaultPosition, wxSize(1024, 768))
{
//////////////////////////////////////////////////////////////////////////
// Menu
wxMenuBar* menuBar = new wxMenuBar;
SetMenuBar(menuBar);
wxMenu *menuFile = new wxMenu;
menuBar->Append(menuFile, _("&File"));
{
// menuFile->Append(ID_New, _("&New"));
// // menuFile->Append(ID_Import, _("&Import..."));
// // menuFile->Append(ID_Export, _("&Export..."));
// menuFile->Append(ID_Open, _("&Open..."));
// menuFile->Append(ID_Save, _("&Save"));
// menuFile->Append(ID_SaveAs, _("Save &As..."));
// menuFile->AppendSeparator();//-----------
menuFile->Append(ID_Quit, _("E&xit"));
// m_FileHistory.UseMenu(menuFile);//-------
// m_FileHistory.AddFilesToMenu();
}
// m_menuItem_Save = menuFile->FindItem(ID_Save); // remember this item, to let it be greyed out
// wxASSERT(m_menuItem_Save);
wxMenu *menuEdit = new wxMenu;
menuBar->Append(menuEdit, _("&Edit"));
{
menuEdit->Append(wxID_UNDO, _("&Undo"));
menuEdit->Append(wxID_REDO, _("&Redo"));
}
GetCommandProc().SetEditMenu(menuEdit);
GetCommandProc().Initialize();
//////////////////////////////////////////////////////////////////////////
// Main window
SnapSplitterWindow* splitter = new SnapSplitterWindow(this);
// Set up GL canvas:
@ -187,6 +242,21 @@ void ScenarioEditor::OnTimer(wxTimerEvent&)
last = time;
}
void ScenarioEditor::OnQuit(wxCommandEvent&)
{
Close();
}
void ScenarioEditor::OnUndo(wxCommandEvent&)
{
GetCommandProc().Undo();
}
void ScenarioEditor::OnRedo(wxCommandEvent&)
{
GetCommandProc().Redo();
}
//////////////////////////////////////////////////////////////////////////
AtlasMessage::Position::Position(const wxPoint& pt)

View File

@ -1,12 +1,25 @@
#ifndef SCENARIOEDITOR_H__
#define SCENARIOEDITOR_H__
#include "General/AtlasWindowCommandProc.h"
class ScenarioEditor : public wxFrame
{
public:
ScenarioEditor();
void OnClose(wxCloseEvent& evt);
void OnTimer(wxTimerEvent& evt);
void OnClose(wxCloseEvent& event);
void OnTimer(wxTimerEvent& event);
void OnQuit(wxCommandEvent& event);
void OnUndo(wxCommandEvent& event);
void OnRedo(wxCommandEvent& event);
static AtlasWindowCommandProc& GetCommandProc();
private:
wxTimer m_Timer;
DECLARE_EVENT_TABLE();
};
#endif // SCENARIOEDITOR_H__

View File

@ -44,7 +44,7 @@ public:
{
if (m_IsActive)
{
ADD_COMMAND(AlterElevation(m_Pos, dt*4.096f));
ADD_WORLDCOMMAND(AlterElevation, (m_Pos, dt*4.096f));
}
}

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Tools.h"
#include "GameInterface/Messages.h"
class DummyTool : public ITool
{
@ -21,3 +22,35 @@ void SetCurrentTool(ITool* tool)
else
g_CurrentTool = tool;
}
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_CLASS(WorldCommand, AtlasWindowCommand);
WorldCommand::WorldCommand(AtlasMessage::mWorldCommand* command)
: AtlasWindowCommand(true, _("???")), m_Command(command)
{
}
WorldCommand::~WorldCommand()
{
delete m_Command;
}
bool WorldCommand::Do()
{
ADD_COMMAND(DoCommand(m_Command));
return true;
}
bool WorldCommand::Undo()
{
ADD_COMMAND(UndoCommand());
return true;
}
bool WorldCommand::Redo()
{
ADD_COMMAND(RedoCommand());
return true;
}

View File

@ -1,6 +1,9 @@
#ifndef TOOLS_H__
#define TOOLS_H__
#include "ScenarioEditor/ScenarioEditor.h"
#include "general/AtlasWindowCommand.h"
class wxMouseEvent;
class wxKeyEvent;
@ -22,4 +25,23 @@ public:
extern ITool* g_CurrentTool;
extern void SetCurrentTool(ITool*); // for internal use only
namespace AtlasMessage { struct mWorldCommand; }
class WorldCommand : public AtlasWindowCommand
{
DECLARE_CLASS(WorldCommand);
public:
WorldCommand(AtlasMessage::mWorldCommand* command);
~WorldCommand();
bool Do();
bool Undo();
bool Redo();
private:
AtlasMessage::mWorldCommand* m_Command;
};
#define ADD_WORLDCOMMAND(type, data) ScenarioEditor::GetCommandProc().Submit(new WorldCommand(new AtlasMessage::m##type(AtlasMessage::d##type data)))
#endif // TOOLS_H__

View File

@ -1,7 +1,5 @@
Colour tester:
* Display DDS info (compression, size)
==============================
Actor editor:
@ -81,6 +79,7 @@ General and/or unsorted miscellany:
Done: (newest at top)
* Display DDS info (compression, size)
* Copy and paste
* 'Create entity' button (take name, parent)
* Correct undo menu entry when selecting 'New' (so it's not 'Import')

View File

@ -0,0 +1,73 @@
#include "precompiled.h"
#include "CommandProc.h"
//////////////////////////////////////////////////////////////////////////
template<typename T> T next(T x) { T t = x; return ++t; }
template<typename T, typename I> void delete_erase(T list, I first, I last)
{
while (first != last)
{
delete *first;
first = list.erase(first);
}
}
//////////////////////////////////////////////////////////////////////////
using namespace AtlasMessage;
namespace AtlasMessage {
static CommandProc g_CommandProc;
CommandProc& GetCommandProc() { return g_CommandProc; }
cmdHandlers& GetCmdHandlers()
{
static cmdHandlers h;
return h;
}
}
CommandProc::CommandProc()
{
// Start the list with a NULL, so m_CurrentCommand can point at
// something even when the command stack is empty
m_Commands.push_back(NULL);
m_CurrentCommand = m_Commands.begin();
}
CommandProc::~CommandProc()
{
delete_erase(m_Commands, m_Commands.begin(), m_Commands.end());
}
void CommandProc::Submit(Command* cmd)
{
delete_erase(m_Commands, next(m_CurrentCommand), m_Commands.end());
m_CurrentCommand = m_Commands.insert(next(m_CurrentCommand), cmd);
(*m_CurrentCommand)->Do();
}
void CommandProc::Undo()
{
if (m_CurrentCommand != m_Commands.begin())
{
(*m_CurrentCommand)->Undo();
--m_CurrentCommand;
}
}
void CommandProc::Redo()
{
if (next(m_CurrentCommand) != m_Commands.end())
{
++m_CurrentCommand;
(*m_CurrentCommand)->Redo();
}
}

View File

@ -0,0 +1,59 @@
#include <list>
namespace AtlasMessage
{
struct Command
{
virtual ~Command() {}
virtual void Do() = 0;
virtual void Undo() = 0;
virtual void Redo() = 0;
// virtual void Merge(Command* prev) = 0;
};
class CommandProc
{
public:
CommandProc();
~CommandProc();
void Submit(Command* cmd);
void Undo();
void Redo();
private:
std::list<Command*> m_Commands;
std::list<Command*>::iterator m_CurrentCommand;
};
typedef Command* (*cmdHandler)(const void*);
typedef std::map<std::string, cmdHandler> cmdHandlers;
extern cmdHandlers& GetCmdHandlers();
CommandProc& GetCommandProc();
class DataCommand : public Command // so commands can optionally override (De|Con)struct
{
void Destruct() {};
void Construct() {};
};
#define BEGIN_COMMAND(t) \
class c##t : public DataCommand \
{ \
d##t* d; \
public: \
c##t(d##t* data) : d(data) { Construct(); } \
~c##t() { Destruct(); delete d; } \
static Command* Create(const void* data) { return new c##t((d##t*)data); }
#define END_COMMAND(t) \
}; \
namespace CAT2(hndlr_, __LINE__) { struct init { init() { \
bool notAlreadyRegisted = GetCmdHandlers().insert(std::pair<std::string, cmdHandler>("c"#t, &c##t##::Create)).second; \
assert(notAlreadyRegisted); \
} } init; };
}

View File

@ -21,9 +21,6 @@
using namespace AtlasMessage;
extern __declspec(dllimport) void Atlas_StartWindow(wchar_t* type);
extern __declspec(dllimport) void Atlas_SetMessagePasser(MessagePasser<mCommand>*, MessagePasser<mInput>*);
extern void Render_();
extern "C" { __declspec(dllimport) int __stdcall SwapBuffers(void*); }
@ -31,7 +28,9 @@ extern "C" { __declspec(dllimport) int __stdcall SwapBuffers(void*); }
//
// (Er, actually that's what most of this file is. Oh well.)
// Loaded from DLL:
void (*Atlas_StartWindow)(wchar_t* type);
void (*Atlas_SetMessagePasser)(MessagePasser<mCommand>*, MessagePasser<mInput>*);
static MessagePasserImpl<mCommand> msgPasser_Command;
static MessagePasserImpl<mInput> msgPasser_Input;
@ -49,8 +48,14 @@ static void* LaunchWindow(void*)
}
void BeginAtlas(int argc, char** argv)
bool BeginAtlas(int argc, char* argv[], void* dll)
{
*(void**)&Atlas_StartWindow = dlsym(dll, "Atlas_StartWindow");
*(void**)&Atlas_SetMessagePasser = dlsym(dll, "Atlas_SetMessagePasser");
if (!Atlas_StartWindow || !Atlas_SetMessagePasser)
return false;
// Pass our message handler to Atlas
Atlas_SetMessagePasser(&msgPasser_Command, &msgPasser_Input);
@ -92,7 +97,7 @@ void BeginAtlas(int argc, char** argv)
// if (!(in interactive-tool mode))
{
mCommand* msg;
while (msg = msgPasser_Command.Retrieve())
while ((msg = msgPasser_Command.Retrieve()) != NULL)
{
recent_activity = true;
@ -110,8 +115,8 @@ void BeginAtlas(int argc, char** argv)
// that it's slightly dangerous - we have to just assume that
// GetType is correct, since we can't use proper RTTI
}
handlers::const_iterator it = GetHandlers().find(name);
if (it != GetHandlers().end())
msgHandlers::const_iterator it = GetMsgHandlers().find(name);
if (it != GetMsgHandlers().end())
{
it->second(msg);
}
@ -133,13 +138,13 @@ void BeginAtlas(int argc, char** argv)
// Now do the same (roughly), for input events:
{
mInput* msg;
while (msg = msgPasser_Input.Retrieve())
while ((msg = msgPasser_Input.Retrieve()) != NULL)
{
recent_activity = true;
std::string name (msg->GetType());
handlers::const_iterator it = GetHandlers().find(name);
if (it != GetHandlers().end())
msgHandlers::const_iterator it = GetMsgHandlers().find(name);
if (it != GetMsgHandlers().end())
{
it->second(msg);
}
@ -175,4 +180,6 @@ void BeginAtlas(int argc, char** argv)
// TODO: delete all remaining messages, to avoid memory leak warnings
pthread_join(gameThread, NULL);
exit(0);
}

View File

@ -0,0 +1,44 @@
#include "precompiled.h"
#include "MessageHandler.h"
#include "../CommandProc.h"
namespace AtlasMessage {
void fDoCommand(IMessage* msg)
{
mDoCommand* cmd = static_cast<mDoCommand*>(msg);
Command* c = NULL;
cmdHandlers::const_iterator it = GetCmdHandlers().find("c" + cmd->name);
if (it != GetCmdHandlers().end())
{
c = (it->second)(cmd->data);
}
else
{
debug_warn("Unrecognised command");
return;
}
GetCommandProc().Submit(c);
}
REGISTER(DoCommand);
void fUndoCommand(IMessage*)
{
GetCommandProc().Undo();
}
REGISTER(UndoCommand);
void fRedoCommand(IMessage*)
{
GetCommandProc().Redo();
}
REGISTER(RedoCommand);
}

View File

@ -2,34 +2,64 @@
#include "MessageHandler.h"
#include "../CommandProc.h"
#include "graphics/Terrain.h"
#include "ps/Game.h"
namespace AtlasMessage {
BEGIN_COMMAND(AlterElevation)
void fAlterElevation(IMessage* msg)
{
mAlterElevation* cmd = static_cast<mAlterElevation*>(msg);
// TODO: much more efficient version of this, and without the memory leaks
u16* OldTerrain;
u16* NewTerrain;
// TODO:
// Create something like the AtlasCommandProcessor, so that undo is
// possible: Push an AlterElevationCommand onto the command stack,
// which has Do and Undo methods, and also has Merge (so multiple
// consecutive elevation-altering moments can be combined into a single
// brush stroke, to conserve memory and also so 'undo' undoes the entire
// stroke at once).
void Construct()
{
OldTerrain = NewTerrain = NULL;
}
void Destruct()
{
delete OldTerrain;
delete NewTerrain;
}
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
void Do() {
u16* heightmap = terrain->GetHeightMap();
int size = terrain->GetVerticesPerSide();
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
int x = (int)cmd->pos.x;
int z = (int)cmd->pos.z;
terrain->RaiseVertex(x, z, (int)cmd->amount);
terrain->MakeDirty(x, z, x, z);
}
REGISTER(AlterElevation);
int verts = terrain->GetVerticesPerSide()*terrain->GetVerticesPerSide();
OldTerrain = new u16[verts];
memcpy(OldTerrain, terrain->GetHeightMap(), verts*sizeof(u16));
int x = (int)d->pos.x;
int z = (int)d->pos.z;
terrain->RaiseVertex(x, z, (int)d->amount);
terrain->MakeDirty(x, z, x, z);
}
void Undo() {
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
if (! NewTerrain)
{
int verts = terrain->GetVerticesPerSide()*terrain->GetVerticesPerSide();
NewTerrain = new u16[verts];
memcpy(NewTerrain, terrain->GetHeightMap(), verts*sizeof(u16));
}
terrain->SetHeightMap(OldTerrain); // CTerrain duplicates the data
}
void Redo() {
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
terrain->SetHeightMap(NewTerrain); // CTerrain duplicates the data
}
void MergeWithSelf(cAlterElevation* prev) {
debug_warn("TODO");
}
END_COMMAND(AlterElevation);
}

View File

@ -50,6 +50,7 @@ REGISTER(CommandString_init);
void fCommandString_shutdown(IMessage*)
{
Shutdown_();
g_GameLoop->rendering = false;
}
REGISTER(CommandString_shutdown);

View File

@ -5,13 +5,13 @@
namespace AtlasMessage
{
handlers& GetHandlers()
msgHandlers& GetMsgHandlers()
{
// Make sure this is initialised when it's first required, rather than
// hoping to be lucky with static initialisation order.
// (TODO: But is it safe to be sticking things into STL containers during
// static initialisation?)
static handlers h;
static msgHandlers h;
return h;
}

View File

@ -6,15 +6,15 @@ namespace AtlasMessage
// (Random note: Be careful not to give handler .cpp files the same name
// as any other file in the project, because it makes everything very confused)
typedef void (*handler)(IMessage*);
typedef std::map<std::string, handler> handlers;
extern handlers& GetHandlers();
typedef void (*msgHandler)(IMessage*);
typedef std::map<std::string, msgHandler> msgHandlers;
extern msgHandlers& GetMsgHandlers();
#define CAT1(a,b) a##b
#define CAT2(a,b) CAT1(a,b)
#define REGISTER(t) namespace CAT2(hndlr_, __LINE__) { struct init { init() { \
bool notAlreadyRegisted = GetHandlers().insert(std::pair<std::string, handler>(#t, &f##t)).second; \
bool notAlreadyRegisted = GetMsgHandlers().insert(std::pair<std::string, msgHandler>(#t, &f##t)).second; \
assert(notAlreadyRegisted); \
} } init; };

View File

@ -2,10 +2,22 @@
#include "MessagePasserImpl.h"
#define MESSAGE_TRACE 0
#if MESSAGE_TRACE
#include "Messages.h" // for mCommand implementation
#endif
using namespace AtlasMessage;
template<typename T> void MessagePasserImpl<T>::Add(T* msg)
{
debug_assert(msg);
#if MESSAGE_TRACE
debug_printf("Add %s\n", msg->GetType());
#endif
m_Mutex.Lock();
m_Queue.push(msg);
@ -30,6 +42,10 @@ template <typename T> T* MessagePasserImpl<T>::Retrieve()
m_Mutex.Unlock();
#if MESSAGE_TRACE
if (msg) debug_printf("Retrieved %s\n", msg->GetType());
#endif
return msg;
}
@ -46,4 +62,4 @@ MessagePasser<mInput>* g_MessagePasser_Input = NULL;
// Explicit instantiation:
template MessagePasserImpl<mCommand>;
template MessagePasserImpl<mInput>;
template MessagePasserImpl<mInput>;

View File

@ -31,8 +31,8 @@ struct IMessage
struct mCommand : public IMessage {};
struct mInput : public IMessage {};
#define COMMAND(t) struct m##t : public mCommand { const char* GetType() const { return #t; }
#define INPUT(t) struct m##t : public mInput { const char* GetType() const { return #t; }
#define COMMAND(t) struct m##t : public mCommand { const char* GetType() const { return #t; } private: const m##t& operator=(const m##t&); public:
#define INPUT(t) struct m##t : public mInput { const char* GetType() const { return #t; } private: const m##t& operator=(const m##t&); public:
//////////////////////////////////////////////////////////////////////////
@ -84,11 +84,51 @@ mToolEnd() {}
};
*/
/*
COMMAND(AlterElevation)
mAlterElevation(Position pos_, float amount_) : pos(pos_), amount(amount_) {}
const Position pos;
const float amount;
};
*/
COMMAND(WorldCommand)
mWorldCommand() {}
virtual void* CloneData() const = 0;
};
COMMAND(DoCommand)
mDoCommand(mWorldCommand* c) : name(c->GetType()), data(c->CloneData()) {}
const std::string name;
const void* data;
};
COMMAND(UndoCommand)
};
COMMAND(RedoCommand)
};
#define WORLDCOMMAND(t, merge) struct m##t : public mWorldCommand, public d##t { \
m##t(const d##t& d) : d##t(d) {} \
const char* GetType() const { return #t; } \
bool IsMergeable() { return merge; } \
void* CloneData() const { return new d##t(*this); } \
private: \
const m##t& operator=(const m##t&);\
};
struct dAlterElevation {
dAlterElevation(Position pos_, float amount_) : pos(pos_), amount(amount_) {}
const Position pos;
const float amount;
private:
const dAlterElevation& operator=(const dAlterElevation&);
};
WORLDCOMMAND(AlterElevation, true)
#undef WORLDCOMMAND
//////////////////////////////////////////////////////////////////////////