diff --git a/source/tools/atlas/AtlasUI/AtlasUI.vcproj b/source/tools/atlas/AtlasUI/AtlasUI.vcproj
index 2e052c6290..28bef702f2 100644
--- a/source/tools/atlas/AtlasUI/AtlasUI.vcproj
+++ b/source/tools/atlas/AtlasUI/AtlasUI.vcproj
@@ -281,6 +281,16 @@
RelativePath=".\CustomControls\FileHistory\FileHistory.h">
+
+
+
+
+
+
SetCurrent();
+}
+
+ATLASDLLIMPEXP void Atlas_GLSwapBuffers(void* context)
+{
+ ((wxGLContext*)context)->SwapBuffers();
+}
+
+
//////////////////////////////////////////////////////////////////////////
+
+volatile bool g_FrameHasEnded;
+// Called from game thread
+ATLASDLLIMPEXP void Atlas_NotifyEndOfFrame()
+{
+ g_FrameHasEnded = true;
+}
+
enum
{
ID_Quit = 1,
@@ -133,6 +159,8 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
EVT_MENU(wxID_REDO, ScenarioEditor::OnRedo)
EVT_MENU(ID_Wireframe, ScenarioEditor::OnWireframe)
+
+ EVT_IDLE(ScenarioEditor::OnIdle)
END_EVENT_TABLE()
@@ -213,7 +241,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
// Send setup messages to game engine:
#ifndef UI_ONLY
- ADD_COMMAND(SetContext(canvas->GetHDC(), canvas->GetContext()->GetGLRC()));
+ ADD_COMMAND(SetContext(canvas->GetContext()));
ADD_COMMAND(CommandString("init"));
@@ -225,8 +253,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
// XXX
USE_TOOL(AlterElevation);
+ // Set up a timer to make sure tool-updates happen even when there's no idle time
m_Timer.SetOwner(this);
- m_Timer.Start(50);
+ m_Timer.Start(20);
}
@@ -244,13 +273,26 @@ void ScenarioEditor::OnClose(wxCloseEvent&)
}
+static void UpdateTool()
+{
+ // Don't keep posting events if the game can't keep up
+ if (g_FrameHasEnded)
+ {
+ g_FrameHasEnded = false; // (threadiness doesn't matter here)
+ // TODO: Smoother timing stuff?
+ static double last = g_Timer.GetTime();
+ double time = g_Timer.GetTime();
+ g_CurrentTool->OnTick(time-last);
+ last = time;
+ }
+}
void ScenarioEditor::OnTimer(wxTimerEvent&)
{
- // TODO: Improve timer stuff - smoother, etc
- static wxLongLong last = wxGetLocalTimeMillis();
- wxLongLong time = wxGetLocalTimeMillis();
- g_CurrentTool->OnTick((time-last).ToLong());
- last = time;
+ UpdateTool();
+}
+void ScenarioEditor::OnIdle(wxIdleEvent&)
+{
+ UpdateTool();
}
void ScenarioEditor::OnQuit(wxCommandEvent&)
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h
index 6f9ef0a527..57436c9cad 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h
@@ -9,6 +9,7 @@ public:
ScenarioEditor(wxWindow* parent);
void OnClose(wxCloseEvent& event);
void OnTimer(wxTimerEvent& event);
+ void OnIdle(wxIdleEvent& event);
void OnQuit(wxCommandEvent& event);
void OnUndo(wxCommandEvent& event);
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp
index bf3d3f9f0a..c79704f727 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp
@@ -10,7 +10,7 @@ class AlterElevation : public ITool
{
public:
AlterElevation()
- : m_IsActive(false)
+ : m_Direction(0)
{
}
@@ -19,13 +19,19 @@ public:
if (evt.LeftDown())
{
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
- m_IsActive = true;
+ m_Direction = +1;
m_Pos = Position(evt.GetPosition());
}
- else if (evt.LeftUp())
+ else if (evt.RightDown())
{
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
- m_IsActive = false;
+ m_Direction = -1;
+ m_Pos = Position(evt.GetPosition());
+ }
+ else if (evt.LeftUp() || evt.RightUp())
+ {
+ ScenarioEditor::GetCommandProc().FinaliseLastCommand();
+ m_Direction = 0;
}
else if (evt.Dragging())
{
@@ -44,15 +50,18 @@ public:
void OnTick(float dt)
{
- if (m_IsActive)
+ if (m_Direction)
{
- ADD_WORLDCOMMAND(AlterElevation, (m_Pos, dt*4.096f));
+ // TODO: If the mouse hasn't been moved in this stroke, use the
+ // same tile position as last time (else it's annoying when digging
+ // deep holes or building tall hills.)
+ ADD_WORLDCOMMAND(AlterElevation, (m_Pos, dt*4096.f*m_Direction));
}
}
private:
- bool m_IsActive;
+ int m_Direction; // +1 = raise, -1 = lower, 0 = inactive
Position m_Pos;
};
diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Tools.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Tools.h
index 440ebb1f5c..dbe5c2d67a 100644
--- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Tools.h
+++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Tools.h
@@ -14,7 +14,7 @@ public:
virtual void OnMouse(wxMouseEvent& evt) = 0;
virtual void OnKey(wxKeyEvent& evt, int dir) = 0;
- virtual void OnTick(float dt) = 0;
+ virtual void OnTick(float dt) = 0; // dt in seconds
virtual ~ITool() {};
};
diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp
index 7db7b67a0f..9b5837c0b7 100644
--- a/source/tools/atlas/GameInterface/GameLoop.cpp
+++ b/source/tools/atlas/GameInterface/GameLoop.cpp
@@ -13,23 +13,17 @@
#include "lib/timer.h"
#include "ps/CLogger.h"
-#include
-
using namespace AtlasMessage;
extern void Render_();
-#define __declspec(spec_)
-#define __stdcall
-
-extern "C" { __declspec(dllimport) int __stdcall SwapBuffers(void*); }
- // HACK (and not exactly portable)
- //
- // (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*, MessagePasser*);
+void (*Atlas_GLSetCurrent)(void* context);
+void (*Atlas_GLSwapBuffers)(void* context);
+void (*Atlas_NotifyEndOfFrame)();
+
static MessagePasserImpl msgPasser_Command;
static MessagePasserImpl msgPasser_Input;
@@ -49,11 +43,14 @@ static void* LaunchWindow(void*)
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;
+ // Load required symbols from the DLL
+#define GET(x) *(void**)&x = dlsym(dll, #x); if (! x) return false;
+ GET(Atlas_StartWindow);
+ GET(Atlas_SetMessagePasser);
+ GET(Atlas_GLSetCurrent);
+ GET(Atlas_GLSwapBuffers);
+ GET(Atlas_NotifyEndOfFrame);
+#undef GET
// Pass our message handler to Atlas
Atlas_SetMessagePasser(&msgPasser_Command, &msgPasser_Input);
@@ -66,7 +63,9 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
state.argv = argv;
state.running = true;
state.rendering = false;
- state.currentDC = NULL;
+ state.glContext = NULL;
+
+ double last_activity = get_time();
while (state.running)
{
@@ -82,18 +81,18 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
static double last_time = time;
const float length = (float)(time-last_time);
last_time = time;
- assert(length >= 0.0f);
+ debug_assert(length >= 0.0f);
// TODO: filter out big jumps, e.g. when having done a lot of slow
// processing in the last frame
state.frameLength = length;
}
+ // Process the input that was received in the past
if (g_Input.ProcessInput(&state))
recent_activity = true;
//////////////////////////////////////////////////////////////////////////
- // if (!(in interactive-tool mode))
{
mCommand* msg;
while ((msg = msgPasser_Command.Retrieve()) != NULL)
@@ -164,18 +163,36 @@ bool BeginAtlas(int argc, char* argv[], void* dll)
{
Render_();
glFinish();
-#if OS_WIN
- SwapBuffers((void*)state.currentDC);
-#endif
+ Atlas_GLSwapBuffers((void*)state.glContext);
}
- // Be nice to the processor if we're not doing anything useful, but
- // nice to the user if we are
- if (! recent_activity)
- SDL_Delay(100);
+ Atlas_NotifyEndOfFrame();
+
+ double time = get_time();
+ if (recent_activity)
+ last_activity = time;
+
+ // Be nice to the processor (by sleeping) if we're not doing anything
+ // useful, but nice to the user (by just yielding to other threads) if we are
+
+ if (time - last_activity > 0.5) // if there was no recent activity...
+ {
+ double sleepUntil = time + 0.5; // only redraw at 2fps
+ while (time < sleepUntil)
+ {
+ // To minimise latency when the user starts doing stuff, only
+ // sleep for a short while, then check if anything's happened,
+ // then go back to sleep
+ SDL_Delay(50);
+ if (!msgPasser_Input.IsEmpty() || !msgPasser_Command.IsEmpty())
+ break;
+ time = get_time();
+ }
+ }
else
+ {
SDL_Delay(0);
- // Probable TODO: allow interruption of sleep by incoming messages
+ }
}
// TODO: delete all remaining messages, to avoid memory leak warnings
diff --git a/source/tools/atlas/GameInterface/GameLoop.h b/source/tools/atlas/GameInterface/GameLoop.h
index 43c34bbf17..9e681ea0e7 100644
--- a/source/tools/atlas/GameInterface/GameLoop.h
+++ b/source/tools/atlas/GameInterface/GameLoop.h
@@ -1,13 +1,15 @@
#ifndef GAMELOOP_H__
#define GAMELOOP_H__
+extern void (*Atlas_GLSetCurrent)(void* context);
+
struct GameLoopState
{
int argc;
char** argv;
bool running;
bool rendering;
- const void* currentDC;
+ const void* glContext;
float frameLength; // smoothed to avoid large jumps
struct
diff --git a/source/tools/atlas/GameInterface/Handlers/Elevation.cpp b/source/tools/atlas/GameInterface/Handlers/Elevation.cpp
index d9d05f3a39..2572af4da7 100644
--- a/source/tools/atlas/GameInterface/Handlers/Elevation.cpp
+++ b/source/tools/atlas/GameInterface/Handlers/Elevation.cpp
@@ -9,6 +9,7 @@
namespace AtlasMessage {
+
BEGIN_COMMAND(AlterElevation)
// TODO: much more efficient version of this, and without the memory leaks
@@ -25,7 +26,8 @@ BEGIN_COMMAND(AlterElevation)
delete NewTerrain;
}
- void Do() {
+ void Do()
+ {
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
@@ -33,16 +35,29 @@ BEGIN_COMMAND(AlterElevation)
OldTerrain = new u16[verts];
memcpy(OldTerrain, terrain->GetHeightMap(), verts*sizeof(u16));
+ int amount = (int)d->amount;
+// debug_printf("%d\n", amount);
+
+ // If the thing's being updated very fast, 'amount' is often very
+ // small (even zero) so the integer truncation is significant
+ static float roundingError = 0.0;
+ roundingError += d->amount - (float)amount;
+ if (roundingError >= 1.f)
+ {
+ amount += (int)roundingError;
+ roundingError -= (float)(int)roundingError;
+ }
+
CVector3D vec;
d->pos.GetWorldSpace(vec);
uint32_t x, z;
terrain->CalcFromPosition(vec, x, z);
- terrain->RaiseVertex(x, z, (int)d->amount);
+ terrain->RaiseVertex(x, z, amount);
terrain->MakeDirty(x, z, x, z);
-
}
- void Undo() {
+ void Undo()
+ {
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
if (! NewTerrain)
{
@@ -53,12 +68,14 @@ BEGIN_COMMAND(AlterElevation)
terrain->SetHeightMap(OldTerrain); // CTerrain duplicates the data
}
- void Redo() {
+ void Redo()
+ {
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
terrain->SetHeightMap(NewTerrain); // CTerrain duplicates the data
}
- void MergeWithSelf(cAlterElevation* prev) {
+ void MergeWithSelf(cAlterElevation* prev)
+ {
std::swap(prev->NewTerrain, NewTerrain);
}
diff --git a/source/tools/atlas/GameInterface/Handlers/GraphicsSetup.cpp b/source/tools/atlas/GameInterface/Handlers/GraphicsSetup.cpp
index 835970aec7..8025b4a11e 100644
--- a/source/tools/atlas/GameInterface/Handlers/GraphicsSetup.cpp
+++ b/source/tools/atlas/GameInterface/Handlers/GraphicsSetup.cpp
@@ -82,10 +82,8 @@ REGISTER(CommandString_render_disable);
void fSetContext(IMessage* msg)
{
mSetContext* cmd = static_cast(msg);
-#if OS_WIN
- wglMakeCurrent((HDC)cmd->hdc, (HGLRC)cmd->hglrc);
- g_GameLoop->currentDC = cmd->hdc;
-#endif
+ g_GameLoop->glContext = cmd->context;
+ Atlas_GLSetCurrent((void*)g_GameLoop->glContext);
}
REGISTER(SetContext);
diff --git a/source/tools/atlas/GameInterface/Handlers/MessageHandler.h b/source/tools/atlas/GameInterface/Handlers/MessageHandler.h
index 95a9626bb4..e3fcaddcb8 100644
--- a/source/tools/atlas/GameInterface/Handlers/MessageHandler.h
+++ b/source/tools/atlas/GameInterface/Handlers/MessageHandler.h
@@ -15,6 +15,7 @@ extern msgHandlers& GetMsgHandlers();
#define CAT1(a,b) a##b
#define CAT2(a,b) CAT1(a,b)
+// TODO quite urgently: Fix this, because it's broken and not very helpful anyway
#define REGISTER(t) namespace CAT2(hndlr_, __LINE__) { struct init { init() { \
bool notAlreadyRegisted = GetMsgHandlers().insert(std::pair(#t, &f##t)).second; \
assert(notAlreadyRegisted); \
diff --git a/source/tools/atlas/GameInterface/InputProcessor.cpp b/source/tools/atlas/GameInterface/InputProcessor.cpp
index ad57533242..8e0d1732d4 100644
--- a/source/tools/atlas/GameInterface/InputProcessor.cpp
+++ b/source/tools/atlas/GameInterface/InputProcessor.cpp
@@ -5,8 +5,6 @@
#include "ps/Game.h"
#include "graphics/Camera.h"
-#include
-
bool InputProcessor::ProcessInput(GameLoopState* state)
{
if (! g_Game)
@@ -24,13 +22,6 @@ bool InputProcessor::ProcessInput(GameLoopState* state)
else
forwards.Normalize();
- float l;
- l = forwards.GetLength();
- assert(fabsf(l - 1.f) < 0.0001f);
- l = leftwards.GetLength();
- assert(fabsf(l - 1.f) < 0.0001f);
-
-
bool moved = false;
if (state->input.scrollSpeed[0] != 0.0f)
diff --git a/source/tools/atlas/GameInterface/MessagePasser.h b/source/tools/atlas/GameInterface/MessagePasser.h
index 0b3e436fc3..71dfc7324a 100644
--- a/source/tools/atlas/GameInterface/MessagePasser.h
+++ b/source/tools/atlas/GameInterface/MessagePasser.h
@@ -9,9 +9,6 @@ template class MessagePasser
public:
virtual void Add(T*)=0;
virtual T* Retrieve()=0;
-
- virtual void Query(T&)=0;
- virtual void QueryDone()=0;
};
struct mCommand;
@@ -24,13 +21,4 @@ extern MessagePasser* g_MessagePasser_Input;
}
-
-/*
-
-atlas->game command ("initialise now", "render now")
-atlas->game->atlas query ("what is at position (x,y)?")
-game->atlas notification ("game ended") ??
-
-*/
-
#endif // MESSAGEPASSER_H__
diff --git a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp
index e9e9453c6f..0f51327857 100644
--- a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp
+++ b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp
@@ -49,12 +49,12 @@ template T* MessagePasserImpl::Retrieve()
return msg;
}
-template void MessagePasserImpl::Query(T&)
-{
-}
-
-template void MessagePasserImpl::QueryDone()
+template bool MessagePasserImpl::IsEmpty()
{
+ m_Mutex.Lock();
+ bool empty = m_Queue.empty();
+ m_Mutex.Unlock();
+ return empty;
}
MessagePasser* g_MessagePasser_Command = NULL;
diff --git a/source/tools/atlas/GameInterface/MessagePasserImpl.h b/source/tools/atlas/GameInterface/MessagePasserImpl.h
index 407ac7f8ec..70496838a2 100644
--- a/source/tools/atlas/GameInterface/MessagePasserImpl.h
+++ b/source/tools/atlas/GameInterface/MessagePasserImpl.h
@@ -8,9 +8,7 @@ template class MessagePasserImpl : public AtlasMessage::MessagePass
public:
virtual void Add(T* msg);
virtual T* Retrieve();
-
- virtual void Query(T&);
- virtual void QueryDone();
+ virtual bool IsEmpty();
private:
CMutex m_Mutex;
diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h
index 2fd4ef2d33..4dd55c9dad 100644
--- a/source/tools/atlas/GameInterface/Messages.h
+++ b/source/tools/atlas/GameInterface/Messages.h
@@ -90,9 +90,8 @@ COMMAND(CommandString)
//////////////////////////////////////////////////////////////////////////
COMMAND(SetContext)
- mSetContext(void* /* HDC */ hdc_, void* /* HGLRC */ hglrc_) : hdc(hdc_), hglrc(hglrc_) {};
- const void* hdc;
- const void* hglrc;
+ mSetContext(void* /* wxGLContext */ context_) : context(context_) {};
+ const void* context;
};
COMMAND(ResizeScreen)