# Enabled some interoperability between different compiler versions for the game and the editor DLL
This was SVN commit r3790.
This commit is contained in:
parent
8bb97e63cd
commit
d9b033c85f
@ -14,6 +14,26 @@
|
||||
#include "wx/config.h"
|
||||
#include "wx/debugrpt.h"
|
||||
|
||||
// Shared memory allocation functions
|
||||
ATLASDLLIMPEXP void* ShareableMalloc(size_t n)
|
||||
{
|
||||
// TODO: make sure this is thread-safe everywhere. (It is in MSVC with the
|
||||
// multithreaded CRT.)
|
||||
return malloc(n);
|
||||
}
|
||||
ATLASDLLIMPEXP void ShareableFree(void* p)
|
||||
{
|
||||
return free(p);
|
||||
}
|
||||
// Define the function pointers that we'll use when calling those functions.
|
||||
// (The game loads the addresses of the above functions, then does the same.)
|
||||
namespace AtlasMessage
|
||||
{
|
||||
void* (*ShareableMallocFptr) (size_t) = &ShareableMalloc;
|
||||
void (*ShareableFreeFptr) (void*) = &ShareableFree;
|
||||
}
|
||||
|
||||
|
||||
// Global variables, to remember state between DllMain and StartWindow and OnInit
|
||||
wxString g_InitialWindowType;
|
||||
HINSTANCE g_Module;
|
||||
@ -22,20 +42,20 @@ bool g_IsLoaded = false;
|
||||
|
||||
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID WXUNUSED(lpReserved))
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_Module = hModule;
|
||||
return TRUE;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (g_IsLoaded)
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
g_Module = hModule;
|
||||
return TRUE;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
if (g_IsLoaded)
|
||||
{
|
||||
wxEntryCleanup();
|
||||
g_IsLoaded = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
wxEntryCleanup();
|
||||
g_IsLoaded = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -166,4 +186,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
||||
IMPLEMENT_APP_NO_MAIN(wxDLLApp)
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <wchar.h>
|
||||
|
||||
namespace AtlasMessage { class MessageHandler; }
|
||||
namespace AtlasMessage { class MessagePasser; }
|
||||
|
||||
ATLASDLLIMPEXP void Atlas_SetMessageHandler(AtlasMessage::MessageHandler*);
|
||||
ATLASDLLIMPEXP void Atlas_SetMessagePasser(AtlasMessage::MessagePasser*);
|
||||
ATLASDLLIMPEXP void Atlas_StartWindow(wchar_t* type);
|
||||
|
||||
ATLASDLLIMPEXP void Atlas_GLSetCurrent(void* context);
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
// Be careful not to send 'resize' messages to the game before we've
|
||||
// told it that this canvas exists
|
||||
if (! m_SuppressResize)
|
||||
POST_MESSAGE(ResizeScreen(GetClientSize().GetWidth(), GetClientSize().GetHeight()));
|
||||
POST_MESSAGE(ResizeScreen, (GetClientSize().GetWidth(), GetClientSize().GetHeight()));
|
||||
// TODO: fix flashing
|
||||
#endif // UI_ONLY
|
||||
}
|
||||
@ -74,14 +74,14 @@ public:
|
||||
|
||||
if (dir == -1) // changed modifier keys - update all currently-scrolling directions
|
||||
{
|
||||
if (wxGetKeyState(WXK_LEFT)) POST_MESSAGE(ScrollConstant(AtlasMessage::eScrollConstantDir::LEFT, speed));
|
||||
if (wxGetKeyState(WXK_RIGHT)) POST_MESSAGE(ScrollConstant(AtlasMessage::eScrollConstantDir::RIGHT, speed));
|
||||
if (wxGetKeyState(WXK_UP)) POST_MESSAGE(ScrollConstant(AtlasMessage::eScrollConstantDir::FORWARDS, speed));
|
||||
if (wxGetKeyState(WXK_DOWN)) POST_MESSAGE(ScrollConstant(AtlasMessage::eScrollConstantDir::BACKWARDS, speed));
|
||||
if (wxGetKeyState(WXK_LEFT)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::LEFT, speed));
|
||||
if (wxGetKeyState(WXK_RIGHT)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::RIGHT, speed));
|
||||
if (wxGetKeyState(WXK_UP)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::FORWARDS, speed));
|
||||
if (wxGetKeyState(WXK_DOWN)) POST_MESSAGE(ScrollConstant, (AtlasMessage::eScrollConstantDir::BACKWARDS, speed));
|
||||
}
|
||||
else
|
||||
{
|
||||
POST_MESSAGE(ScrollConstant(dir, enable ? speed : 0.0f));
|
||||
POST_MESSAGE(ScrollConstant, (dir, enable ? speed : 0.0f));
|
||||
}
|
||||
#endif // UI_ONLY
|
||||
return true;
|
||||
@ -130,7 +130,7 @@ public:
|
||||
float speed = 16.f;
|
||||
if (wxGetKeyState(WXK_SHIFT))
|
||||
speed *= 4.f;
|
||||
POST_MESSAGE(SmoothZoom(speed*dir));
|
||||
POST_MESSAGE(SmoothZoom, (speed*dir));
|
||||
}
|
||||
else
|
||||
evt.Skip();
|
||||
@ -210,7 +210,7 @@ public:
|
||||
else if (wxGetKeyState(WXK_SHIFT))
|
||||
speed *= 4.f;
|
||||
|
||||
POST_MESSAGE(SmoothZoom(evt.GetWheelRotation() * speed / evt.GetWheelDelta()));
|
||||
POST_MESSAGE(SmoothZoom, (evt.GetWheelRotation() * speed / evt.GetWheelDelta()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -229,8 +229,8 @@ public:
|
||||
switch (m_MouseState)
|
||||
{
|
||||
case NONE: break;
|
||||
case SCROLL: POST_MESSAGE(Scroll(AtlasMessage::eScrollType::FROM, evt.GetPosition())); break;
|
||||
case ROTATEAROUND: POST_MESSAGE(RotateAround(AtlasMessage::eRotateAroundType::FROM, evt.GetPosition())); break;
|
||||
case SCROLL: POST_MESSAGE(Scroll, (AtlasMessage::eScrollType::FROM, evt.GetPosition())); break;
|
||||
case ROTATEAROUND: POST_MESSAGE(RotateAround, (AtlasMessage::eRotateAroundType::FROM, evt.GetPosition())); break;
|
||||
default: wxFAIL;
|
||||
}
|
||||
m_LastMouseState = m_MouseState;
|
||||
@ -240,8 +240,8 @@ public:
|
||||
switch (m_MouseState)
|
||||
{
|
||||
case NONE: break;
|
||||
case SCROLL: POST_MESSAGE(Scroll(AtlasMessage::eScrollType::TO, evt.GetPosition())); break;
|
||||
case ROTATEAROUND: POST_MESSAGE(RotateAround(AtlasMessage::eRotateAroundType::TO, evt.GetPosition())); break;
|
||||
case SCROLL: POST_MESSAGE(Scroll, (AtlasMessage::eScrollType::TO, evt.GetPosition())); break;
|
||||
case ROTATEAROUND: POST_MESSAGE(RotateAround, (AtlasMessage::eRotateAroundType::TO, evt.GetPosition())); break;
|
||||
default: wxFAIL;
|
||||
}
|
||||
}
|
||||
@ -432,17 +432,17 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
||||
// Send setup messages to game engine:
|
||||
|
||||
#ifndef UI_ONLY
|
||||
POST_MESSAGE(SetContext(canvas->GetContext()));
|
||||
POST_MESSAGE(SetContext, (canvas->GetContext()));
|
||||
|
||||
POST_MESSAGE(CommandString("init"));
|
||||
POST_MESSAGE(CommandString, ("init"));
|
||||
|
||||
canvas->InitSize();
|
||||
|
||||
// Start with a blank map (so that the editor can assume there's always
|
||||
// a valid map loaded)
|
||||
POST_MESSAGE(GenerateMap(9));
|
||||
POST_MESSAGE(GenerateMap, (9));
|
||||
|
||||
POST_MESSAGE(CommandString("render_enable"));
|
||||
POST_MESSAGE(CommandString, ("render_enable"));
|
||||
#endif
|
||||
|
||||
// Set up a timer to make sure tool-updates happen frequently (in addition
|
||||
@ -458,7 +458,7 @@ void ScenarioEditor::OnClose(wxCloseEvent&)
|
||||
SetCurrentTool(_T(""));
|
||||
|
||||
#ifndef UI_ONLY
|
||||
POST_MESSAGE(CommandString("shutdown"));
|
||||
POST_MESSAGE(CommandString, ("shutdown"));
|
||||
#endif
|
||||
|
||||
AtlasMessage::qExit().Post();
|
||||
@ -510,17 +510,17 @@ void ScenarioEditor::OnRedo(wxCommandEvent&)
|
||||
|
||||
void ScenarioEditor::OnWireframe(wxCommandEvent& event)
|
||||
{
|
||||
POST_MESSAGE(RenderStyle(event.IsChecked()));
|
||||
POST_MESSAGE(RenderStyle, (event.IsChecked()));
|
||||
}
|
||||
|
||||
void ScenarioEditor::OnMessageTrace(wxCommandEvent& event)
|
||||
{
|
||||
POST_MESSAGE(MessageTrace(event.IsChecked()));
|
||||
POST_MESSAGE(MessageTrace, (event.IsChecked()));
|
||||
}
|
||||
|
||||
void ScenarioEditor::OnScreenshot(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
POST_MESSAGE(Screenshot(10));
|
||||
POST_MESSAGE(Screenshot, (10));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -25,7 +25,7 @@ static void LoadMap(void*)
|
||||
SetCurrentTool(_T(""));
|
||||
// TODO: clear the undo buffer, etc
|
||||
|
||||
POST_MESSAGE(LoadMap(map));
|
||||
POST_MESSAGE(LoadMap, (map));
|
||||
}
|
||||
|
||||
wxCHECK_RET(cwd == wxFileName::GetCwd(), _T("cwd changed"));
|
||||
@ -44,13 +44,13 @@ static void SaveMap(void*)
|
||||
{
|
||||
// TODO: Work when the map is not in .../maps/scenarios/
|
||||
std::wstring map = dlg.GetFilename().c_str();
|
||||
POST_MESSAGE(SaveMap(map));
|
||||
POST_MESSAGE(SaveMap, (map));
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateMap(void*)
|
||||
{
|
||||
POST_MESSAGE(GenerateMap(9));
|
||||
POST_MESSAGE(GenerateMap, (9));
|
||||
}
|
||||
|
||||
static void GenerateRMS(void* data)
|
||||
@ -64,7 +64,7 @@ static void GenerateRMS(void* data)
|
||||
wxExecute(argv, wxEXEC_SYNC);
|
||||
wxFileName::SetCwd(cwd);
|
||||
|
||||
POST_MESSAGE(LoadMap(L"_atlasrm.pmp"));
|
||||
POST_MESSAGE(LoadMap, (L"_atlasrm.pmp"));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -91,7 +91,7 @@ void ObjectSidebar::OnFirstDisplay()
|
||||
{
|
||||
AtlasMessage::qGetObjectsList qry;
|
||||
qry.Post();
|
||||
p->m_Objects = qry.objects;
|
||||
p->m_Objects = *qry.objects;
|
||||
SetObjectFilter(0);
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,16 @@ public:
|
||||
AtlasMessage::qGetTerrainGroupPreviews qry(m_Name.c_str(), imageWidth, imageHeight);
|
||||
qry.Post();
|
||||
|
||||
std::vector<AtlasMessage::sTerrainGroupPreview> previews = *qry.previews;
|
||||
|
||||
int i = 0;
|
||||
for (std::vector<AtlasMessage::sTerrainGroupPreview>::iterator it = qry.previews.begin(); it != qry.previews.end(); ++it)
|
||||
for (std::vector<AtlasMessage::sTerrainGroupPreview>::iterator it = previews.begin(); it != previews.end(); ++it)
|
||||
{
|
||||
wxImage img (imageWidth, imageHeight, it->imagedata);
|
||||
unsigned char* buf = (unsigned char*)(malloc(it->imagedata.GetSize()));
|
||||
// it->imagedata.GetBuffer() gives a Shareable<unsigned char>*, which
|
||||
// is stored the same as a unsigned char*, so we can just copy it.
|
||||
memcpy(buf, it->imagedata.GetBuffer(), it->imagedata.GetSize());
|
||||
wxImage img (imageWidth, imageHeight, buf);
|
||||
imglist->Add(wxBitmap(img));
|
||||
|
||||
wxListItem item;
|
||||
@ -142,7 +148,8 @@ public:
|
||||
// Get the list of terrain groups from the engine
|
||||
AtlasMessage::qGetTerrainGroups qry;
|
||||
qry.Post();
|
||||
for (std::vector<std::wstring>::iterator it = qry.groupnames.begin(); it != qry.groupnames.end(); ++it)
|
||||
std::vector<std::wstring> groupnames = *qry.groupnames;
|
||||
for (std::vector<std::wstring>::iterator it = groupnames.begin(); it != groupnames.end(); ++it)
|
||||
m_TerrainGroups.Add(it->c_str());
|
||||
|
||||
for (size_t i = 0; i < m_TerrainGroups.GetCount(); ++i)
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(false, Position()));
|
||||
POST_MESSAGE(BrushPreview, (false, Position()));
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
else if (evt.Moving())
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, Position(evt.GetPosition())));
|
||||
POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -65,7 +65,7 @@ public:
|
||||
{
|
||||
void OnEnter(AlterElevation* obj)
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
|
||||
}
|
||||
|
||||
void OnLeave(AlterElevation*)
|
||||
@ -84,7 +84,7 @@ public:
|
||||
{
|
||||
wxPoint pos = evt.GetPosition();
|
||||
obj->m_Pos = Position(pos);
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -40,12 +40,12 @@ int Brush::GetHeight() const
|
||||
return GetWidth();
|
||||
}
|
||||
|
||||
float* Brush::GetNewedData() const
|
||||
std::vector<float> Brush::GetData() const
|
||||
{
|
||||
int width = GetWidth();
|
||||
int height = GetHeight();
|
||||
|
||||
float* data = new float[width*height];
|
||||
std::vector<float> data (width*height);
|
||||
|
||||
switch (m_Shape)
|
||||
{
|
||||
@ -200,7 +200,7 @@ void Brush::MakeActive()
|
||||
void Brush::Send()
|
||||
{
|
||||
if (m_IsActive)
|
||||
POST_MESSAGE(Brush(GetWidth(), GetHeight(), GetNewedData()));
|
||||
POST_MESSAGE(Brush, (GetWidth(), GetHeight(), GetData()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
|
||||
int GetWidth() const;
|
||||
int GetHeight() const;
|
||||
float* GetNewedData() const; // freshly allocated via new[]
|
||||
std::vector<float> GetData() const;
|
||||
|
||||
float GetStrength() const;
|
||||
|
||||
|
@ -111,16 +111,20 @@ WorldCommand::WorldCommand(AtlasMessage::mWorldCommand* command)
|
||||
|
||||
WorldCommand::~WorldCommand()
|
||||
{
|
||||
// m_Command was allocated by POST_COMMAND
|
||||
delete m_Command;
|
||||
}
|
||||
|
||||
bool WorldCommand::Do()
|
||||
{
|
||||
if (m_AlreadyDone)
|
||||
POST_MESSAGE(RedoCommand());
|
||||
POST_MESSAGE(RedoCommand, ());
|
||||
else
|
||||
{
|
||||
POST_MESSAGE(DoCommand(m_Command));
|
||||
// The DoCommand message clones the data from m_Command, and posts that
|
||||
// (passing ownership to the game), so we're free to delete m_Command
|
||||
// at any time
|
||||
POST_MESSAGE(DoCommand, (m_Command));
|
||||
m_AlreadyDone = true;
|
||||
}
|
||||
return true;
|
||||
@ -128,7 +132,7 @@ bool WorldCommand::Do()
|
||||
|
||||
bool WorldCommand::Undo()
|
||||
{
|
||||
POST_MESSAGE(UndoCommand());
|
||||
POST_MESSAGE(UndoCommand, ());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -145,6 +149,6 @@ bool WorldCommand::Merge(AtlasWindowCommand* p)
|
||||
if (! m_Command->IsMergeable())
|
||||
return false;
|
||||
|
||||
POST_MESSAGE(MergeCommand());
|
||||
POST_MESSAGE(MergeCommand, ());
|
||||
return true;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(false, Position()));
|
||||
POST_MESSAGE(BrushPreview, (false, Position()));
|
||||
}
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ public:
|
||||
}
|
||||
else if (evt.Moving())
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, Position(evt.GetPosition())));
|
||||
POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -58,7 +58,7 @@ public:
|
||||
{
|
||||
void OnEnter(FlattenElevation* obj)
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
|
||||
}
|
||||
|
||||
void OnLeave(FlattenElevation*)
|
||||
@ -77,7 +77,7 @@ public:
|
||||
{
|
||||
wxPoint pos = evt.GetPosition();
|
||||
obj->m_Pos = Position(pos);
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(false, Position()));
|
||||
POST_MESSAGE(BrushPreview, (false, Position()));
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ public:
|
||||
}
|
||||
else if (evt.Moving())
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, Position(evt.GetPosition())));
|
||||
POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -96,7 +96,7 @@ public:
|
||||
|
||||
void Paint(PaintTerrain* obj)
|
||||
{
|
||||
POST_MESSAGE(BrushPreview(true, obj->m_Pos));
|
||||
POST_MESSAGE(BrushPreview, (true, obj->m_Pos));
|
||||
POST_COMMAND(PaintTerrain, (obj->m_Pos, g_SelectedTexture.c_str(), GetPriority()));
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ public:
|
||||
+ (m_ScreenPos.type1.y-m_Target.type1.y)*(m_ScreenPos.type1.y-m_Target.type1.y);
|
||||
bool useTarget = (dragDistSq >= 16*16);
|
||||
if (preview)
|
||||
POST_MESSAGE(ObjectPreview(m_ObjectID.c_str(), 0, m_ObjPos, useTarget, m_Target, g_DefaultAngle));
|
||||
POST_MESSAGE(ObjectPreview, (m_ObjectID.c_str(), 0, m_ObjPos, useTarget, m_Target, g_DefaultAngle));
|
||||
else
|
||||
POST_COMMAND(CreateObject,(m_ObjectID.c_str(), m_Player, m_ObjPos, useTarget, m_Target, g_DefaultAngle));
|
||||
POST_COMMAND(CreateObject, (m_ObjectID.c_str(), m_Player, m_ObjPos, useTarget, m_Target, g_DefaultAngle));
|
||||
}
|
||||
|
||||
virtual void Init(void* initData)
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
void OnDisable()
|
||||
{
|
||||
m_Selection.clear();
|
||||
POST_MESSAGE(SetSelectionPreview(m_Selection));
|
||||
POST_MESSAGE(SetSelectionPreview, (m_Selection));
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public:
|
||||
obj->m_dy = qry.offsety;
|
||||
SET_STATE(Dragging);
|
||||
}
|
||||
POST_MESSAGE(SetSelectionPreview(obj->m_Selection));
|
||||
POST_MESSAGE(SetSelectionPreview, (obj->m_Selection));
|
||||
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
||||
return true;
|
||||
}
|
||||
@ -68,7 +68,7 @@ public:
|
||||
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));
|
||||
POST_MESSAGE(SetSelectionPreview, (obj->m_Selection));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -49,22 +49,20 @@ public:
|
||||
};
|
||||
|
||||
Brush::Brush()
|
||||
: m_W(0), m_H(0), m_TerrainOverlay(NULL), m_Data(NULL)
|
||||
: m_W(0), m_H(0), m_TerrainOverlay(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Brush::~Brush()
|
||||
{
|
||||
delete m_TerrainOverlay;
|
||||
delete[] m_Data;
|
||||
}
|
||||
|
||||
void Brush::SetData(int w, int h, const float* data)
|
||||
void Brush::SetData(int w, int h, const std::vector<float>& data)
|
||||
{
|
||||
m_W = w;
|
||||
m_H = h;
|
||||
|
||||
delete[] m_Data;
|
||||
m_Data = data;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ struct Brush
|
||||
Brush();
|
||||
~Brush();
|
||||
|
||||
void SetData(int w, int h, const float* data);
|
||||
void SetData(int w, int h, const std::vector<float>& data);
|
||||
|
||||
void SetRenderEnabled(bool enabled); // initial state is disabled
|
||||
|
||||
@ -27,7 +27,7 @@ struct Brush
|
||||
CVector3D m_Centre;
|
||||
private:
|
||||
TerrainOverlay* m_TerrainOverlay; // NULL if rendering is not enabled
|
||||
const float* m_Data;
|
||||
std::vector<float> m_Data;
|
||||
};
|
||||
|
||||
extern Brush g_CurrentBrush;
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
@ -47,7 +49,8 @@ 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'
|
||||
// MergeWithSelf should be overriden by commands, and implemented
|
||||
// to update 'prev' to include the effects of 'this'
|
||||
void MergeWithSelf(void*) { debug_warn("MergeWithSelf unimplemented in some command"); }
|
||||
};
|
||||
|
||||
@ -57,8 +60,8 @@ struct DataCommand : public Command // so commands can optionally override (De|C
|
||||
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); } \
|
||||
~c##t() { Destruct(); AtlasMessage::ShareableDelete(d); /* d was allocated by mDoCommand() */ } \
|
||||
static Command* Create(const void* data) { return new c##t ((d##t*)data); } \
|
||||
virtual void Merge(Command* prev) { MergeWithSelf((c##t*)prev); } \
|
||||
virtual const char* GetType() const { return #t; }
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "MessagePasserImpl.h"
|
||||
#include "Messages.h"
|
||||
#include "SharedMemory.h"
|
||||
#include "Brushes.h"
|
||||
#include "Handlers/MessageHandler.h"
|
||||
|
||||
@ -41,6 +42,11 @@ void (*Atlas_SetMessagePasser)(MessagePasser*);
|
||||
void (*Atlas_GLSetCurrent)(void* context);
|
||||
void (*Atlas_GLSwapBuffers)(void* context);
|
||||
void (*Atlas_NotifyEndOfFrame)();
|
||||
namespace AtlasMessage
|
||||
{
|
||||
void* (*ShareableMallocFptr)(size_t);
|
||||
void (*ShareableFreeFptr)(void*);
|
||||
}
|
||||
|
||||
|
||||
static MessagePasserImpl msgPasser;
|
||||
@ -71,6 +77,10 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
|
||||
GET(Atlas_GLSwapBuffers);
|
||||
GET(Atlas_NotifyEndOfFrame);
|
||||
#undef GET
|
||||
#define GET(x) *(void**)&x##Fptr = dlsym(dll, #x); debug_assert(x##Fptr); if (! x##Fptr) return false;
|
||||
GET(ShareableMalloc);
|
||||
GET(ShareableFree);
|
||||
#undef GET
|
||||
|
||||
// Pass our message handler to Atlas
|
||||
Atlas_SetMessagePasser(&msgPasser);
|
||||
@ -129,7 +139,7 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
|
||||
// construct a reference to the appropriate handler for the
|
||||
// given string)
|
||||
name += "_";
|
||||
name += static_cast<mCommandString*>(msg)->name;
|
||||
name += *static_cast<mCommandString*>(msg)->name;
|
||||
// use 'static_cast' when casting messages, to make it clear
|
||||
// that something slightly dangerous is happening - we have
|
||||
// to just assume that GetName is correct, since we can't use
|
||||
@ -166,7 +176,7 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
|
||||
{
|
||||
// For non-queries, we need to delete the object, since we
|
||||
// took ownership of it.
|
||||
delete msg;
|
||||
AtlasMessage::ShareableDelete(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ namespace AtlasMessage {
|
||||
|
||||
MESSAGEHANDLER(Brush)
|
||||
{
|
||||
g_CurrentBrush.SetData(msg->width, msg->height, msg->data);
|
||||
g_CurrentBrush.SetData(msg->width, msg->height, *msg->data);
|
||||
}
|
||||
|
||||
MESSAGEHANDLER(BrushPreview)
|
||||
{
|
||||
g_CurrentBrush.SetRenderEnabled(msg->enable);
|
||||
msg->pos.GetWorldSpace(g_CurrentBrush.m_Centre);
|
||||
msg->pos->GetWorldSpace(g_CurrentBrush.m_Centre);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,14 +53,14 @@ MESSAGEHANDLER(Scroll)
|
||||
|
||||
if (msg->type == eScrollType::FROM)
|
||||
{
|
||||
msg->pos.GetWorldSpace(targetPos);
|
||||
msg->pos->GetWorldSpace(targetPos);
|
||||
targetDistance = (targetPos - camera.GetTranslation()).GetLength();
|
||||
}
|
||||
else if (msg->type == eScrollType::TO)
|
||||
{
|
||||
CVector3D origin, dir;
|
||||
float x, y;
|
||||
msg->pos.GetScreenSpace(x, y);
|
||||
msg->pos->GetScreenSpace(x, y);
|
||||
g_Game->GetView()->GetCamera()->BuildCameraRay((int)x, (int)y, origin, dir);
|
||||
dir *= targetDistance;
|
||||
camera.Translate(targetPos - dir - origin);
|
||||
@ -87,13 +87,13 @@ MESSAGEHANDLER(RotateAround)
|
||||
|
||||
if (msg->type == eRotateAroundType::FROM)
|
||||
{
|
||||
msg->pos.GetScreenSpace(lastX, lastY); // get mouse position
|
||||
msg->pos.GetWorldSpace(focusPos); // get point on terrain under mouse
|
||||
msg->pos->GetScreenSpace(lastX, lastY); // get mouse position
|
||||
msg->pos->GetWorldSpace(focusPos); // get point on terrain under mouse
|
||||
}
|
||||
else if (msg->type == eRotateAroundType::TO)
|
||||
{
|
||||
float x, y;
|
||||
msg->pos.GetScreenSpace(x, y); // get mouse position
|
||||
msg->pos->GetScreenSpace(x, y); // get mouse position
|
||||
|
||||
// Rotate around X and Y axes by amounts depending on the mouse delta
|
||||
float rotX = 6.f * (y-lastY) / g_Renderer.GetHeight();
|
||||
|
@ -10,7 +10,7 @@ namespace AtlasMessage {
|
||||
MESSAGEHANDLER(DoCommand)
|
||||
{
|
||||
Command* c = NULL;
|
||||
cmdHandlers::const_iterator it = GetCmdHandlers().find("c" + msg->name);
|
||||
cmdHandlers::const_iterator it = GetCmdHandlers().find("c" + *msg->name);
|
||||
if (it != GetCmdHandlers().end())
|
||||
{
|
||||
c = (it->second)(msg->data);
|
||||
|
@ -104,7 +104,7 @@ BEGIN_COMMAND(AlterElevation)
|
||||
}
|
||||
|
||||
static CVector3D previousPosition;
|
||||
d->pos.GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
|
||||
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
|
||||
previousPosition = g_CurrentBrush.m_Centre;
|
||||
|
||||
int x0, y0;
|
||||
@ -163,7 +163,7 @@ BEGIN_COMMAND(FlattenElevation)
|
||||
int amount = (int)d->amount;
|
||||
|
||||
static CVector3D previousPosition;
|
||||
d->pos.GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
|
||||
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition);
|
||||
previousPosition = g_CurrentBrush.m_Centre;
|
||||
|
||||
int xc, yc;
|
||||
|
@ -98,14 +98,14 @@ MESSAGEHANDLER(GenerateMap)
|
||||
|
||||
MESSAGEHANDLER(LoadMap)
|
||||
{
|
||||
InitGame(msg->filename);
|
||||
InitGame(*msg->filename);
|
||||
StartGame();
|
||||
}
|
||||
|
||||
MESSAGEHANDLER(SaveMap)
|
||||
{
|
||||
CMapWriter writer;
|
||||
writer.SaveMap(CStr(L"maps/scenarios/" + msg->filename),
|
||||
writer.SaveMap(CStr(L"maps/scenarios/" + *msg->filename),
|
||||
g_Game->GetWorld()->GetTerrain(), g_Game->GetWorld()->GetUnitManager(),
|
||||
&g_LightEnv, g_Game->GetView()->GetCamera());
|
||||
}
|
||||
|
@ -25,11 +25,12 @@ namespace AtlasMessage {
|
||||
|
||||
static bool SortObjectsList(const sObjectsListItem& a, const sObjectsListItem& b)
|
||||
{
|
||||
return a.name < b.name;
|
||||
return wcscmp(a.name.c_str(), b.name.c_str()) < 0;
|
||||
}
|
||||
|
||||
QUERYHANDLER(GetObjectsList)
|
||||
{
|
||||
std::vector<sObjectsListItem> objects;
|
||||
{
|
||||
std::vector<CStrW> names;
|
||||
g_EntityTemplateCollection.getBaseEntityNames(names);
|
||||
@ -40,7 +41,7 @@ QUERYHANDLER(GetObjectsList)
|
||||
e.id = L"(e) " + *it;
|
||||
e.name = *it; //baseent->m_Tag
|
||||
e.type = 0;
|
||||
msg->objects.push_back(e);
|
||||
objects.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,10 +55,11 @@ QUERYHANDLER(GetObjectsList)
|
||||
e.id = L"(n) " + CStrW(*it);
|
||||
e.name = CStrW(*it).AfterFirst(/*L"props/"*/ L"actors/");
|
||||
e.type = 1;
|
||||
msg->objects.push_back(e);
|
||||
objects.push_back(e);
|
||||
}
|
||||
}
|
||||
std::sort(msg->objects.begin(), msg->objects.end(), SortObjectsList);
|
||||
std::sort(objects.begin(), objects.end(), SortObjectsList);
|
||||
msg->objects = objects;
|
||||
}
|
||||
|
||||
|
||||
@ -98,7 +100,7 @@ void AtlasRenderSelection()
|
||||
|
||||
MESSAGEHANDLER(SetSelectionPreview)
|
||||
{
|
||||
g_Selection = msg->ids;
|
||||
g_Selection = *msg->ids;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -152,7 +154,7 @@ static bool ParseObjectName(const CStrW& obj, bool& isEntity, CStrW& name)
|
||||
|
||||
MESSAGEHANDLER(ObjectPreview)
|
||||
{
|
||||
if (msg->id != g_PreviewUnitID)
|
||||
if (*msg->id != g_PreviewUnitID)
|
||||
{
|
||||
// Delete old unit
|
||||
if (g_PreviewUnit)
|
||||
@ -164,7 +166,7 @@ MESSAGEHANDLER(ObjectPreview)
|
||||
|
||||
bool isEntity;
|
||||
CStrW name;
|
||||
if (ParseObjectName(msg->id, isEntity, name))
|
||||
if (ParseObjectName(*msg->id, isEntity, name))
|
||||
{
|
||||
std::set<CStrW> selections; // TODO: get selections from user
|
||||
|
||||
@ -186,7 +188,7 @@ MESSAGEHANDLER(ObjectPreview)
|
||||
}
|
||||
}
|
||||
|
||||
g_PreviewUnitID = msg->id;
|
||||
g_PreviewUnitID = *msg->id;
|
||||
}
|
||||
|
||||
if (g_PreviewUnit)
|
||||
@ -198,7 +200,7 @@ MESSAGEHANDLER(ObjectPreview)
|
||||
if (msg->usetarget)
|
||||
{
|
||||
CVector3D target;
|
||||
msg->target.GetWorldSpace(target, pos.Y);
|
||||
msg->target->GetWorldSpace(target, pos.Y);
|
||||
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
|
||||
dir = dir.normalize();
|
||||
s = dir.x;
|
||||
@ -234,7 +236,7 @@ BEGIN_COMMAND(CreateObject)
|
||||
if (d->usetarget)
|
||||
{
|
||||
CVector3D target;
|
||||
d->target.GetWorldSpace(target, m_Pos.Y);
|
||||
d->target->GetWorldSpace(target, m_Pos.Y);
|
||||
CVector2D dir(target.X-m_Pos.X, target.Z-m_Pos.Z);
|
||||
m_Angle = atan2(dir.x, dir.y);
|
||||
}
|
||||
@ -252,7 +254,7 @@ BEGIN_COMMAND(CreateObject)
|
||||
{
|
||||
bool isEntity;
|
||||
CStrW name;
|
||||
if (ParseObjectName(d->id, isEntity, name))
|
||||
if (ParseObjectName(*d->id, isEntity, name))
|
||||
{
|
||||
std::set<CStrW> selections;
|
||||
|
||||
@ -329,7 +331,7 @@ END_COMMAND(CreateObject)
|
||||
QUERYHANDLER(SelectObject)
|
||||
{
|
||||
float x, y;
|
||||
msg->pos.GetScreenSpace(x, y);
|
||||
msg->pos->GetScreenSpace(x, y);
|
||||
|
||||
CVector3D rayorigin, raydir;
|
||||
g_Game->GetView()->GetCamera()->BuildCameraRay((int)x, (int)y, rayorigin, raydir);
|
||||
@ -434,7 +436,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
{
|
||||
CVector3D& pos = unit->GetEntity()->m_position;
|
||||
CVector3D target;
|
||||
d->target.GetWorldSpace(target, pos.Y);
|
||||
d->target->GetWorldSpace(target, pos.Y);
|
||||
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
|
||||
m_AngleNew = atan2(dir.x, dir.y);
|
||||
}
|
||||
@ -453,7 +455,7 @@ BEGIN_COMMAND(RotateObject)
|
||||
if (d->usetarget)
|
||||
{
|
||||
CVector3D target;
|
||||
d->target.GetWorldSpace(target, pos.Y);
|
||||
d->target->GetWorldSpace(target, pos.Y);
|
||||
CVector2D dir(target.X-pos.X, target.Z-pos.Z);
|
||||
dir = dir.normalize();
|
||||
s = dir.x;
|
||||
|
@ -20,8 +20,10 @@ namespace AtlasMessage {
|
||||
QUERYHANDLER(GetTerrainGroups)
|
||||
{
|
||||
const CTextureManager::TerrainGroupMap &groups = g_TexMan.GetGroups();
|
||||
for (CTextureManager ::TerrainGroupMap::const_iterator it = groups.begin(); it != groups.end(); ++it)
|
||||
msg->groupnames.push_back(CStrW(it->first));
|
||||
std::vector<std::wstring> groupnames;
|
||||
for (CTextureManager::TerrainGroupMap::const_iterator it = groups.begin(); it != groups.end(); ++it)
|
||||
groupnames.push_back(CStrW(it->first));
|
||||
msg->groupnames = groupnames;
|
||||
}
|
||||
|
||||
static bool CompareTerrain(const sTerrainGroupPreview& a, const sTerrainGroupPreview& b)
|
||||
@ -31,13 +33,15 @@ static bool CompareTerrain(const sTerrainGroupPreview& a, const sTerrainGroupPre
|
||||
|
||||
QUERYHANDLER(GetTerrainGroupPreviews)
|
||||
{
|
||||
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(msg->groupname));
|
||||
std::vector<sTerrainGroupPreview> previews;
|
||||
|
||||
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupname));
|
||||
for (std::vector<CTextureEntry*>::const_iterator it = group->GetTerrains().begin(); it != group->GetTerrains().end(); ++it)
|
||||
{
|
||||
msg->previews.push_back(sTerrainGroupPreview());
|
||||
msg->previews.back().name = CStrW((*it)->GetTag());
|
||||
previews.push_back(sTerrainGroupPreview());
|
||||
previews.back().name = CStrW((*it)->GetTag());
|
||||
|
||||
unsigned char* buf = (unsigned char*)malloc(msg->imagewidth*msg->imageheight*3);
|
||||
std::vector<unsigned char> buf (msg->imagewidth*msg->imageheight*3);
|
||||
|
||||
// It's not good to shrink the entire texture to fit the small preview
|
||||
// window, since it's the fine details in the texture that are
|
||||
@ -72,7 +76,7 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
||||
// Extract the middle section (as a representative preview),
|
||||
// and copy into buf
|
||||
unsigned char* texdata_ptr = texdata + (w*(h - msg->imageheight)/2 + (w - msg->imagewidth)/2) * 3;
|
||||
unsigned char* buf_ptr = buf;
|
||||
unsigned char* buf_ptr = &buf[0];
|
||||
for (int y = 0; y < msg->imageheight; ++y)
|
||||
{
|
||||
memcpy(buf_ptr, texdata_ptr, msg->imagewidth*3);
|
||||
@ -83,11 +87,12 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
||||
delete[] texdata;
|
||||
}
|
||||
|
||||
msg->previews.back().imagedata = buf;
|
||||
previews.back().imagedata = buf;
|
||||
}
|
||||
|
||||
// Sort the list alphabetically by name
|
||||
std::sort(msg->previews.begin(), msg->previews.end(), CompareTerrain);
|
||||
std::sort(previews.begin(), previews.end(), CompareTerrain);
|
||||
msg->previews = previews;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -160,12 +165,12 @@ BEGIN_COMMAND(PaintTerrain)
|
||||
void Do()
|
||||
{
|
||||
|
||||
d->pos.GetWorldSpace(g_CurrentBrush.m_Centre);
|
||||
d->pos->GetWorldSpace(g_CurrentBrush.m_Centre);
|
||||
|
||||
int x0, y0;
|
||||
g_CurrentBrush.GetBottomLeft(x0, y0);
|
||||
|
||||
CTextureEntry* texentry = g_TexMan.FindTexture(CStrW(d->texture));
|
||||
CTextureEntry* texentry = g_TexMan.FindTexture(CStrW(*d->texture));
|
||||
if (! texentry)
|
||||
{
|
||||
debug_warn("Can't find texentry"); // TODO: nicer error handling
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef MESSAGEPASSER_H__
|
||||
#define MESSAGEPASSER_H__
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
@ -21,7 +23,7 @@ public:
|
||||
|
||||
extern MessagePasser* g_MessagePasser;
|
||||
|
||||
#define POST_MESSAGE(type) AtlasMessage::g_MessagePasser->Add(new AtlasMessage::m##type)
|
||||
#define POST_MESSAGE(type, data) AtlasMessage::g_MessagePasser->Add(SHAREABLE_NEW(AtlasMessage::m##type, data))
|
||||
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ MESSAGE(Screenshot,
|
||||
MESSAGE(Brush,
|
||||
((int, width)) // number of vertices
|
||||
((int, height))
|
||||
((float*, data)) // width*height array, allocated with new[] (handler will delete[])
|
||||
((std::vector<float>, data)) // width*height array
|
||||
);
|
||||
|
||||
MESSAGE(BrushPreview,
|
||||
@ -73,9 +73,11 @@ QUERY(GetTerrainGroups,
|
||||
|
||||
struct sTerrainGroupPreview
|
||||
{
|
||||
std::wstring name;
|
||||
unsigned char* imagedata; // RGB*size*size, allocated with malloc (querier should free)
|
||||
Shareable<std::wstring> name;
|
||||
Shareable<std::vector<unsigned char> > imagedata; // RGB*size*size
|
||||
};
|
||||
SHAREABLE_POD(sTerrainGroupPreview);
|
||||
|
||||
QUERY(GetTerrainGroupPreviews,
|
||||
((std::wstring, groupname))
|
||||
((int, imagewidth))
|
||||
@ -89,10 +91,12 @@ QUERY(GetTerrainGroupPreviews,
|
||||
|
||||
struct sObjectsListItem
|
||||
{
|
||||
std::wstring id;
|
||||
std::wstring name;
|
||||
int type; // 0 = entity, 1 = actor
|
||||
Shareable<std::wstring> id;
|
||||
Shareable<std::wstring> name;
|
||||
Shareable<int> type; // 0 = entity, 1 = actor
|
||||
};
|
||||
SHAREABLE_POD(sObjectsListItem);
|
||||
|
||||
QUERY(GetObjectsList,
|
||||
, // no inputs
|
||||
((std::vector<sObjectsListItem>, objects))
|
||||
|
@ -4,46 +4,17 @@
|
||||
#define MESSAGESSETUP_NOTFIRST
|
||||
|
||||
#include "MessagePasser.h"
|
||||
#include "SharedTypes.h"
|
||||
#include "Shareable.h"
|
||||
|
||||
// Structures in this file are passed over the DLL boundary, so some
|
||||
// carefulness and/or luck is required...
|
||||
|
||||
class wxPoint;
|
||||
class CVector3D;
|
||||
class CMutex;
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Position
|
||||
{
|
||||
Position() : type(0) { type0.x = type0.y = type0.z = 0.f; }
|
||||
Position(float x_, float y_, float z_) : type(0) { type0.x = x_; type0.y = y_; type0.z = z_; }
|
||||
Position(const wxPoint& pt); // (implementation in ScenarioEditor.cpp)
|
||||
|
||||
int type;
|
||||
union {
|
||||
struct { float x, y, z; } type0; // world-space coordinates
|
||||
struct { int x, y; } type1; // screen-space coordinates, to be projected onto terrain
|
||||
// type2: "same as previous" (e.g. for elevation-editing when the mouse hasn't moved)
|
||||
};
|
||||
|
||||
// Constructs a position with the meaning "same as previous", which is handled
|
||||
// in an unspecified way by various message handlers.
|
||||
static Position Unchanged() { Position p; p.type = 2; return p; }
|
||||
|
||||
// Only for use in the game, not the UI.
|
||||
// Implementations in Misc.cpp.
|
||||
void GetWorldSpace(CVector3D& vec) const;
|
||||
void GetWorldSpace(CVector3D& vec, float h) const;
|
||||
void GetWorldSpace(CVector3D& vec, const CVector3D& prev) const;
|
||||
void GetScreenSpace(float& x, float& y) const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct IMessage
|
||||
{
|
||||
virtual const char* GetName() const = 0;
|
||||
@ -71,8 +42,9 @@ MESSAGESTRUCT(WorldCommand)
|
||||
};
|
||||
MESSAGESTRUCT(DoCommand)
|
||||
mDoCommand(mWorldCommand* c) : name(c->GetName()), data(c->CloneData()) {}
|
||||
const std::string name;
|
||||
const void* data;
|
||||
const Shareable<std::string> name;
|
||||
const Shareable<void*> data;
|
||||
// 'data' gets deallocated by ~cWhatever in the game thread
|
||||
};
|
||||
MESSAGESTRUCT(UndoCommand) };
|
||||
MESSAGESTRUCT(RedoCommand) };
|
||||
@ -112,7 +84,7 @@ const bool NOMERGE = false;
|
||||
m##t(const d##t& d) : d##t(d) {} \
|
||||
const char* GetName() const { return #t; } \
|
||||
virtual bool IsMergeable() const { return merge; } \
|
||||
void* CloneData() const { return new d##t(*this); } \
|
||||
void* CloneData() const { return SHAREABLE_NEW(d##t, (*this)); } \
|
||||
private: \
|
||||
const m##t& operator=(const m##t&);\
|
||||
};
|
||||
@ -128,15 +100,15 @@ const bool NOMERGE = false;
|
||||
#define B_NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem)
|
||||
#define B_CONSTRUCTORARGS(r, data, n, elem) BOOST_PP_COMMA_IF(n) B_TYPE(elem) BOOST_PP_CAT(B_NAME(elem),_)
|
||||
#define B_CONSTRUCTORINIT(r, data, n, elem) BOOST_PP_COMMA_IF(n) B_NAME(elem)(BOOST_PP_CAT(B_NAME(elem),_))
|
||||
#define B_CONSTMEMBERS(r, data, n, elem) const B_TYPE(elem) B_NAME(elem);
|
||||
#define B_MEMBERS(r, data, n, elem) B_TYPE(elem) B_NAME(elem);
|
||||
#define B_CONSTMEMBERS(r, data, n, elem) const Shareable< B_TYPE(elem) > B_NAME(elem);
|
||||
#define B_MEMBERS(r, data, n, elem) Shareable< B_TYPE(elem) > B_NAME(elem);
|
||||
|
||||
/* For each message type, generate something roughly like:
|
||||
struct mBlah : public IMessage {
|
||||
const char* GetName() const { return "Blah"; }
|
||||
mBlah(int in0_, bool in1_) : in0(in0_), in1(in1_) {}
|
||||
const int in0;
|
||||
const bool in1;
|
||||
const Shareable<int> in0;
|
||||
const Shareable<bool> in1;
|
||||
}
|
||||
*/
|
||||
|
||||
|
277
source/tools/atlas/GameInterface/Shareable.h
Normal file
277
source/tools/atlas/GameInterface/Shareable.h
Normal file
@ -0,0 +1,277 @@
|
||||
#ifndef SHAREABLE_H__
|
||||
#define SHAREABLE_H__
|
||||
|
||||
/*
|
||||
|
||||
The Atlas UI DLL needs to share information with the game EXE. It's most
|
||||
convenient if they can pass STL objects, like std::wstring and std::vector;
|
||||
but that causes problems if the DLL and EXE were not compiled in exactly
|
||||
the same way.
|
||||
|
||||
So, the Shareable<T> class is used to make things a bit safer:
|
||||
Simple types (primitives, POD structs, etc) are passed as normal.
|
||||
std::string is converted to an array, using a shared (and thread-safe) memory
|
||||
allocation function so that it works when the DLL and EXE use different heaps.
|
||||
std::vector is done the same, though its element type must be Shareable too.
|
||||
|
||||
This ought to protect against:
|
||||
* Different heaps (msvcr71 vs msvcr80, debug vs release, etc).
|
||||
* Different STL class layout.
|
||||
It doesn't protect against:
|
||||
* Different data type sizes/ranges.
|
||||
* Different packing in our structs. (But they're very simple structs,
|
||||
only storing size_t and pointer values.)
|
||||
* Vtable layout - this code doesn't actually care, but the rest of Atlas does.
|
||||
|
||||
Usage should be fairly transparent - conversions from T to Shareable<T> are
|
||||
automatic, and the opposite is automatic for primitive types.
|
||||
For POD structs, use operator-> to access members (e.g. "msg->sharedstruct->value").
|
||||
For more complex things (strings, vectors), use the unary operator* to get back
|
||||
an STL object (e.g. "std::string s = *msg->sharedstring").
|
||||
(That conversion to an STL object is potentially expensive, so
|
||||
Shareable<string>.c_str() and Shareable<vector>.GetBuffer/GetSize() can be used
|
||||
if that's all you need.)
|
||||
|
||||
The supported list of primitive types is below (SHAREABLE_PRIMITIVE).
|
||||
Structs are made shareable by manually ensuring that all their members are
|
||||
shareable (i.e. primitives, PODs, Shareable<string>s, etc) and writing
|
||||
SHAREABLE_POD(StructName);
|
||||
after their definition.
|
||||
|
||||
*/
|
||||
|
||||
#include "SharedMemory.h"
|
||||
|
||||
// We want to use placement new, which breaks when compiling Debug configurations
|
||||
// in the game and in wx, and they both need different workarounds.
|
||||
// (Duplicated in SharedMemory.h)
|
||||
#ifdef new
|
||||
# define SHAREABLE_USED_NOMMGR
|
||||
# ifdef __WXWINDOWS__
|
||||
# undef new
|
||||
# else
|
||||
# include "nommgr.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
// By default, things are not shareable
|
||||
template <typename T> class Shareable
|
||||
{
|
||||
public:
|
||||
Shareable();
|
||||
enum { TypeIsShareable = 0 };
|
||||
};
|
||||
|
||||
// Primitive types just need a very simple wrapper
|
||||
#define SHAREABLE_PRIMITIVE(T) \
|
||||
template<> class Shareable<T> \
|
||||
{ \
|
||||
T m; \
|
||||
public: \
|
||||
enum { TypeIsShareable = 1 }; \
|
||||
Shareable() {} \
|
||||
Shareable(T const& rhs) { m = rhs; } \
|
||||
operator const T() const { return m; } \
|
||||
const T _Unwrap() const { return m; } \
|
||||
}
|
||||
|
||||
SHAREABLE_PRIMITIVE(unsigned char);
|
||||
SHAREABLE_PRIMITIVE(int);
|
||||
SHAREABLE_PRIMITIVE(bool);
|
||||
SHAREABLE_PRIMITIVE(float);
|
||||
SHAREABLE_PRIMITIVE(void*);
|
||||
|
||||
#undef SHAREABLE_PRIMITIVE
|
||||
|
||||
// POD types are similar to primitives, but with operator->
|
||||
#define SHAREABLE_POD(T) \
|
||||
template<> class Shareable<T> \
|
||||
{ \
|
||||
T m; \
|
||||
public: \
|
||||
enum { TypeIsShareable = 1 }; \
|
||||
Shareable() {} \
|
||||
Shareable(T const& rhs) { m = rhs; } \
|
||||
const T* operator->() const { return &m; } \
|
||||
operator const T() const { return m; } \
|
||||
const T _Unwrap() const { return m; } \
|
||||
}
|
||||
|
||||
|
||||
// Shareable containers must have shareable contents - but it's easy to forget
|
||||
// to declare them, so make sure the errors are almost readable, like:
|
||||
// "use of undefined type 'REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE<T,__formal>
|
||||
// with [ T=AtlasMessage::sTerrainGroupPreview, __formal=false ]"
|
||||
//
|
||||
// (Implementation based on boost/static_assert)
|
||||
template <typename T, bool> struct REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE;
|
||||
template <typename T> struct REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE<T, true>{};
|
||||
template<int x> struct static_assert_test{};
|
||||
#define ASSERT_TYPE_IS_SHAREABLE(T) typedef static_assert_test< \
|
||||
sizeof(REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE< T, (bool)(Shareable<T>::TypeIsShareable) >)> \
|
||||
static_assert_typedef_
|
||||
|
||||
|
||||
// Shareable strings:
|
||||
template<typename C> class Shareable< std::basic_string<C> >
|
||||
{
|
||||
typedef std::basic_string<C> wrapped_type;
|
||||
const static C null = 0; // for null strings of the right type
|
||||
|
||||
C* buf; // null-terminated string (perhaps with embedded nulls)
|
||||
size_t length; // size of buf (including null)
|
||||
public:
|
||||
enum { TypeIsShareable = 1 };
|
||||
|
||||
Shareable() : buf(NULL), length(0) {}
|
||||
|
||||
Shareable(const wrapped_type& rhs)
|
||||
{
|
||||
length = rhs.length()+1;
|
||||
buf = (C*)ShareableMallocFptr(sizeof(C)*length);
|
||||
memcpy(buf, rhs.c_str(), sizeof(C)*length);
|
||||
}
|
||||
|
||||
~Shareable()
|
||||
{
|
||||
ShareableFreeFptr(buf);
|
||||
}
|
||||
|
||||
Shareable<wrapped_type>& operator=(const Shareable<wrapped_type>& rhs)
|
||||
{
|
||||
if (&rhs == this)
|
||||
return *this;
|
||||
ShareableFreeFptr(buf);
|
||||
length = rhs.length;
|
||||
buf = (C*)ShareableMallocFptr(sizeof(C)*length);
|
||||
memcpy(buf, rhs.buf, sizeof(C)*length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Shareable(const Shareable<wrapped_type>& rhs)
|
||||
: buf(NULL), length(0)
|
||||
{
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
const wrapped_type _Unwrap() const
|
||||
{
|
||||
return buf ? wrapped_type(buf, buf+length-1) : wrapped_type();
|
||||
}
|
||||
|
||||
const wrapped_type operator*() const
|
||||
{
|
||||
return _Unwrap();
|
||||
}
|
||||
|
||||
// Minor optimisation for code that just wants to access the characters,
|
||||
// without constructing a new std::basic_string then calling c_str on that
|
||||
const C* c_str() const
|
||||
{
|
||||
return buf ? buf : &null;
|
||||
}
|
||||
};
|
||||
|
||||
// Shareable vectors:
|
||||
template<typename E> class Shareable<std::vector<E> >
|
||||
{
|
||||
ASSERT_TYPE_IS_SHAREABLE(E);
|
||||
typedef std::vector<E> wrapped_type;
|
||||
typedef Shareable<E> element_type;
|
||||
element_type* array;
|
||||
size_t size;
|
||||
|
||||
// Since we're allocating with malloc (roughly), but storing non-trivial
|
||||
// objects, we have to allocate with placement new and call destructors
|
||||
// manually. (At least the objects are usually just other Shareables, so it's
|
||||
// reasonably safe to assume there's no exceptions or other confusingness.)
|
||||
void Unalloc()
|
||||
{
|
||||
if (array == NULL)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
array[i].~element_type();
|
||||
ShareableFreeFptr(array);
|
||||
|
||||
array = NULL;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
enum { TypeIsShareable = 1 };
|
||||
|
||||
Shareable() : array(NULL), size(0) {}
|
||||
|
||||
Shareable(const wrapped_type& rhs)
|
||||
{
|
||||
size = rhs.size();
|
||||
array = static_cast<element_type*> (ShareableMallocFptr( sizeof(element_type)*size ));
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
new (&array[i]) element_type (rhs[i]);
|
||||
}
|
||||
|
||||
~Shareable()
|
||||
{
|
||||
Unalloc();
|
||||
}
|
||||
|
||||
Shareable<wrapped_type>& operator=(const Shareable<wrapped_type>& rhs)
|
||||
{
|
||||
if (&rhs == this)
|
||||
return *this;
|
||||
Unalloc();
|
||||
size = rhs.size;
|
||||
array = static_cast<element_type*> (ShareableMallocFptr( sizeof(element_type)*size ));
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
new (&array[i]) element_type (rhs.array[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Shareable(const Shareable<wrapped_type>& rhs)
|
||||
: array(NULL), size(0)
|
||||
{
|
||||
*this = rhs;
|
||||
}
|
||||
|
||||
const wrapped_type _Unwrap() const
|
||||
{
|
||||
wrapped_type r;
|
||||
r.reserve(size);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
r.push_back(array[i]._Unwrap());
|
||||
return r;
|
||||
}
|
||||
|
||||
const wrapped_type operator*() const
|
||||
{
|
||||
return _Unwrap();
|
||||
}
|
||||
|
||||
// Minor optimisation for code that just wants to access the buffer,
|
||||
// without constructing a new std::vector
|
||||
const element_type* GetBuffer() const
|
||||
{
|
||||
return array;
|
||||
}
|
||||
size_t GetSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef SHAREABLE_USED_NOMMGR
|
||||
# ifdef __WXWINDOWS__ // TODO: portability to non-Windows wx
|
||||
# define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
# else
|
||||
# include "mmgr.h"
|
||||
# endif
|
||||
# undef SHAREABLE_USED_NOMMGR
|
||||
#endif
|
||||
|
||||
#endif // SHAREABLE_H__
|
64
source/tools/atlas/GameInterface/SharedMemory.h
Normal file
64
source/tools/atlas/GameInterface/SharedMemory.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef SHAREDMEMORY_H__
|
||||
#define SHAREDMEMORY_H__
|
||||
|
||||
// We want to use placement new, which breaks when compiling Debug configurations
|
||||
// in the game and in wx, and they both need different workarounds.
|
||||
// (Duplicated in Shareable.h)
|
||||
#ifdef new
|
||||
# define SHAREABLE_USED_NOMMGR
|
||||
# ifdef __WXWINDOWS__
|
||||
# undef new
|
||||
# else
|
||||
# include "nommgr.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
// Shared pointers need to be allocated and freed from the same heap.
|
||||
// So, both sides of the Shareable interface should set these function pointers
|
||||
// to point to the same function. (The game will have to dynamically load them
|
||||
// from the DLL.)
|
||||
extern void* (*ShareableMallocFptr) (size_t n);
|
||||
extern void (*ShareableFreeFptr) (void* p);
|
||||
|
||||
// Implement shared new/delete on top of those
|
||||
template<typename T> T* ShareableNew()
|
||||
{
|
||||
T* p = (T*)ShareableMallocFptr(sizeof(T));
|
||||
new (p) T;
|
||||
return p;
|
||||
}
|
||||
template<typename T> void ShareableDelete(T* p)
|
||||
{
|
||||
p->~T();
|
||||
ShareableFreeFptr(p);
|
||||
}
|
||||
// Or maybe we want to use a non-default constructor
|
||||
#define SHAREABLE_NEW(T, data) (new ( (T*)AtlasMessage::ShareableMallocFptr(sizeof(T)) ) T data)
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef SHAREABLE_USED_NOMMGR
|
||||
// # ifdef __WXWINDOWS__ // TODO: portability to non-Windows wx
|
||||
// # define new new( _NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
// # else
|
||||
// # include "mmgr.h"
|
||||
// # endif
|
||||
// Actually, we don't want to redefine 'new', because it conflicts with all users
|
||||
// of SHAREABLE_NEW. So just leave it undefined, and put up with the less
|
||||
// informative leak messages.
|
||||
# undef SHAREABLE_USED_NOMMGR
|
||||
// Oh, but we don't want other game headers to include mmgr.h again.
|
||||
// So let's just cheat horribly and remove the options which cause it to
|
||||
// redefine new.
|
||||
# undef HAVE_VC_DEBUG_ALLOC
|
||||
# define HAVE_VC_DEBUG_ALLOC 0
|
||||
# undef CONFIG_USE_MMGR
|
||||
# define CONFIG_USE_MMGR 0
|
||||
#endif
|
||||
|
||||
|
||||
#endif // SHAREDMEMORY_H__
|
40
source/tools/atlas/GameInterface/SharedTypes.h
Normal file
40
source/tools/atlas/GameInterface/SharedTypes.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef SHAREDTYPES_H__
|
||||
#define SHAREDTYPES_H__
|
||||
|
||||
#include "Shareable.h"
|
||||
|
||||
class wxPoint;
|
||||
class CVector3D;
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
|
||||
struct Position
|
||||
{
|
||||
Position() : type(0) { type0.x = type0.y = type0.z = 0.f; }
|
||||
Position(float x_, float y_, float z_) : type(0) { type0.x = x_; type0.y = y_; type0.z = z_; }
|
||||
Position(const wxPoint& pt); // (implementation in ScenarioEditor.cpp)
|
||||
|
||||
int type;
|
||||
union {
|
||||
struct { float x, y, z; } type0; // world-space coordinates
|
||||
struct { int x, y; } type1; // screen-space coordinates, to be projected onto terrain
|
||||
// type2: "same as previous" (e.g. for elevation-editing when the mouse hasn't moved)
|
||||
};
|
||||
|
||||
// Constructs a position with the meaning "same as previous", which is handled
|
||||
// in an unspecified way by various message handlers.
|
||||
static Position Unchanged() { Position p; p.type = 2; return p; }
|
||||
|
||||
// Only for use in the game, not the UI.
|
||||
// Implementations in Misc.cpp.
|
||||
void GetWorldSpace(CVector3D& vec) const;
|
||||
void GetWorldSpace(CVector3D& vec, float h) const;
|
||||
void GetWorldSpace(CVector3D& vec, const CVector3D& prev) const;
|
||||
void GetScreenSpace(float& x, float& y) const;
|
||||
};
|
||||
SHAREABLE_POD(Position);
|
||||
|
||||
}
|
||||
|
||||
#endif // SHAREDTYPES_H__
|
Loading…
Reference in New Issue
Block a user