diff --git a/binaries/data/mods/official/art/actors/structures/celts/house.xml b/binaries/data/mods/official/art/actors/structures/celts/house.xml index 43731f9642..18325286fe 100644 --- a/binaries/data/mods/official/art/actors/structures/celts/house.xml +++ b/binaries/data/mods/official/art/actors/structures/celts/house.xml @@ -5,21 +5,21 @@ structural/celt_ho_1.pmd - + structural/celt_struct_1.dds structural/celt_ho_2.pmd - + structural/celt_struct_1.dds structural/celt_ho_3.pmd - + structural/celt_struct_1.dds diff --git a/binaries/data/mods/official/art/actors/structures/persians/house.xml b/binaries/data/mods/official/art/actors/structures/persians/house.xml index 7030544176..216b94d7d6 100644 --- a/binaries/data/mods/official/art/actors/structures/persians/house.xml +++ b/binaries/data/mods/official/art/actors/structures/persians/house.xml @@ -5,28 +5,28 @@ structural/pers_ho_a.pmd - + structural/pers_struct_a.dds structural/pers_ho_b.pmd - + structural/pers_struct_a.dds structural/pers_ho_c.pmd - + structural/pers_struct_a.dds structural/pers_ho_d.pmd - + structural/pers_struct_a.dds diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index 7209d0df94..12e4a89f27 100755 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -555,7 +555,7 @@ void CGameView::SetCameraTarget( const CVector3D& target ) { // Maintain the same orientation and level of zoom, if we can // (do this by working out the point the camera is looking at, saving - // the difference beteen that position and the camera point, and restoring + // the difference between that position and the camera point, and restoring // that difference to our new target) CVector3D CurrentTarget = m_Camera.GetFocus(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp index c9995d3e14..7a6869b18a 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp @@ -27,7 +27,8 @@ public: Canvas(wxWindow* parent, int* attribList) : wxGLCanvas(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS, _T("GLCanvas"), attribList), m_SuppressResize(true), - m_MouseState(NONE), m_LastMouseState(NONE), m_MouseCaptured(false) + m_MouseState(NONE), m_LastMouseState(NONE), m_MouseCaptured(false), + m_LastMousePos(-1, -1) { } @@ -132,9 +133,29 @@ public: ReleaseMouse(); } + // Set focus when clicking if (evt.ButtonDown()) SetFocus(); + // TODO or at least to think about: When using other controls in the + // editor, it's annoying that keyboard/scrollwheel no longer navigate + // around the world until you click on it. + // Setting focus back whenever the mouse moves over the GL window + // feels like a fairly natural solution to me, since I can use + // e.g. brush-editing controls normally, and then move the mouse to + // see the brush outline and magically get given back full control + // of the camera. + if (evt.Moving()) + SetFocus(); + + // Reject motion events if the mouse has not actually moved + if (evt.Moving() || evt.Dragging()) + { + if (m_LastMousePos == evt.GetPosition()) + return; + m_LastMousePos = evt.GetPosition(); + } + g_CurrentTool->OnMouse(evt); // TODO: if the tool responded to the mouse action, should we avoid moving @@ -197,6 +218,8 @@ private: int m_MouseState, m_LastMouseState; bool m_MouseCaptured; + wxPoint m_LastMousePos; + DECLARE_EVENT_TABLE(); }; BEGIN_EVENT_TABLE(Canvas, wxGLCanvas) @@ -249,6 +272,7 @@ enum // ID_SaveAs, ID_Wireframe, + ID_MessageTrace, }; BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame) @@ -260,6 +284,7 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame) EVT_MENU(wxID_REDO, ScenarioEditor::OnRedo) EVT_MENU(ID_Wireframe, ScenarioEditor::OnWireframe) + EVT_MENU(ID_MessageTrace, ScenarioEditor::OnMessageTrace) EVT_IDLE(ScenarioEditor::OnIdle) END_EVENT_TABLE() @@ -312,6 +337,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent) menuBar->Append(menuMisc, _("&Misc hacks")); { menuMisc->AppendCheckItem(ID_Wireframe, _("&Wireframe")); + menuMisc->AppendCheckItem(ID_MessageTrace, _("Message debug trace")); } ////////////////////////////////////////////////////////////////////////// @@ -436,6 +462,11 @@ void ScenarioEditor::OnWireframe(wxCommandEvent& event) POST_COMMAND(RenderStyle(event.IsChecked())); } +void ScenarioEditor::OnMessageTrace(wxCommandEvent& event) +{ + POST_COMMAND(MessageTrace(event.IsChecked())); +} + ////////////////////////////////////////////////////////////////////////// AtlasMessage::Position::Position(const wxPoint& pt) diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h index 57436c9cad..ac3fb0b08a 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.h @@ -16,6 +16,7 @@ public: void OnRedo(wxCommandEvent& event); void OnWireframe(wxCommandEvent& event); + void OnMessageTrace(wxCommandEvent& event); static AtlasWindowCommandProc& GetCommandProc(); diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp index ecf57993f4..e9162bdd93 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/AlterElevation.cpp @@ -50,8 +50,12 @@ public: else if (evt.Moving()) { POST_COMMAND(BrushPreview(true, Position(evt.GetPosition()))); + return true; + } + else + { + return false; } - return false; } } Waiting; @@ -59,6 +63,11 @@ public: struct sAltering_common : public State { + void OnEnter(AlterElevation* obj) + { + POST_COMMAND(BrushPreview(true, obj->m_Pos)); + } + void OnLeave(AlterElevation*) { ScenarioEditor::GetCommandProc().FinaliseLastCommand(); @@ -73,7 +82,8 @@ public: } else if (evt.Dragging()) { - obj->m_Pos = Position(evt.GetPosition()); + wxPoint pos = evt.GetPosition(); + obj->m_Pos = Position(pos); POST_COMMAND(BrushPreview(true, obj->m_Pos)); return true; } @@ -85,7 +95,8 @@ public: void OnTick(AlterElevation* obj, float dt) { - ADD_WORLDCOMMAND(AlterElevation, (obj->m_Pos, dt*4096.f*GetDirection())); + ADD_WORLDCOMMAND(AlterElevation, (obj->m_Pos, dt*4096.f*GetDirection()*g_Brush_Elevation.GetStrength())); + obj->m_Pos = Position::Unchanged(); } virtual bool IsMouseUp(wxMouseEvent& evt) = 0; diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.cpp index b542527bdb..0c56fe3cc0 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.cpp @@ -5,7 +5,7 @@ #include "GameInterface/Messages.h" Brush::Brush() -: m_BrushShape(SQUARE), m_BrushSize(4), m_IsActive(false) +: m_Shape(SQUARE), m_Size(4), m_Strength(1.f), m_IsActive(false) { } @@ -13,55 +13,58 @@ Brush::~Brush() { } -int Brush::GetWidth() +int Brush::GetWidth() const { - switch (m_BrushShape) + switch (m_Shape) { case CIRCLE: - return m_BrushSize*2 + 1; + return m_Size; case SQUARE: - return m_BrushSize; + return m_Size; default: wxFAIL; return -1; } } -int Brush::GetHeight() +int Brush::GetHeight() const { - switch (m_BrushShape) +/* + switch (m_Shape) { - case CIRCLE: - return m_BrushSize*2 + 1; - case SQUARE: - return m_BrushSize; + case RECTANGLE or something: default: - wxFAIL; - return -1; + return GetWidth(); } +*/ + return GetWidth(); } -float* Brush::GetNewedData() +float* Brush::GetNewedData() const { int width = GetWidth(); int height = GetHeight(); float* data = new float[width*height]; - switch (m_BrushShape) + switch (m_Shape) { case CIRCLE: { int i = 0; - for (int y = -m_BrushSize; y <= m_BrushSize; ++y) + // All calculations are done in units of half-tiles, since that + // is the required precision + int mid_x = m_Size-1; + int mid_y = m_Size-1; + for (int y = 0; y < m_Size; ++y) { - for (int x = -m_BrushSize; x <= m_BrushSize; ++x) + for (int x = 0; x < m_Size; ++x) { - // TODO: proper circle rasterization, with variable smoothness etc - if (x*x + y*y <= m_BrushSize*m_BrushSize - 4) - data[i++] = 1.f; - else if (x*x + y*y <= m_BrushSize*m_BrushSize) - data[i++] = 0.5f; + float dist_sq = // scaled to 0 in centre, 1 on edge + ((2*x - mid_x)*(2*x - mid_x) + + (2*y - mid_y)*(2*y - mid_y)) / (float)(m_Size*m_Size); + if (dist_sq <= 1.f) + data[i++] = (sqrtf(2.f - dist_sq) - 1.f) / (sqrt(2.f) - 1.f); else data[i++] = 0.f; } @@ -82,6 +85,11 @@ float* Brush::GetNewedData() return data; } +float Brush::GetStrength() const +{ + return m_Strength; +} + ////////////////////////////////////////////////////////////////////////// class BrushShapeCtrl : public wxRadioBox @@ -91,7 +99,7 @@ public: : wxRadioBox(parent, wxID_ANY, _("Shape"), wxDefaultPosition, wxDefaultSize, shapes, 0, wxRA_SPECIFY_ROWS), m_Brush(brush) { - SetSelection(m_Brush.m_BrushShape); + SetSelection(m_Brush.m_Shape); } private: @@ -99,7 +107,7 @@ private: void OnChange(wxCommandEvent& WXUNUSED(evt)) { - m_Brush.m_BrushShape = (Brush::BrushShape)GetSelection(); + m_Brush.m_Shape = (Brush::BrushShape)GetSelection(); m_Brush.Send(); } @@ -114,7 +122,7 @@ class BrushSizeCtrl: public wxSpinCtrl { public: BrushSizeCtrl(wxWindow* parent, Brush& brush) - : wxSpinCtrl(parent, wxID_ANY, wxString::Format(_T("%d"), brush.m_BrushSize), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 50, brush.m_BrushSize), + : wxSpinCtrl(parent, wxID_ANY, wxString::Format(_T("%d"), brush.m_Size), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100, brush.m_Size), m_Brush(brush) { } @@ -124,7 +132,7 @@ private: void OnChange(wxSpinEvent& WXUNUSED(evt)) { - m_Brush.m_BrushSize = GetValue(); + m_Brush.m_Size = GetValue(); m_Brush.Send(); } @@ -135,6 +143,31 @@ BEGIN_EVENT_TABLE(BrushSizeCtrl, wxSpinCtrl) END_EVENT_TABLE() +class BrushStrengthCtrl : public wxSpinCtrl +{ +public: + BrushStrengthCtrl(wxWindow* parent, Brush& brush) + : wxSpinCtrl(parent, wxID_ANY, wxString::Format(_T("%d"), (int)(10.f*brush.m_Strength)), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 100, (int)(10.f*brush.m_Strength)), + m_Brush(brush) + { + } + +private: + Brush& m_Brush; + + void OnChange(wxSpinEvent& WXUNUSED(evt)) + { + m_Brush.m_Strength = GetValue()/10.f; + m_Brush.Send(); + } + + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(BrushStrengthCtrl, wxSpinCtrl) + EVT_SPINCTRL(wxID_ANY, BrushStrengthCtrl::OnChange) +END_EVENT_TABLE() + + void Brush::CreateUI(wxWindow* parent, wxSizer* sizer) { @@ -144,9 +177,12 @@ void Brush::CreateUI(wxWindow* parent, wxSizer* sizer) // TODO (maybe): get rid of the extra static box, by not using wxRadioBox sizer->Add(new BrushShapeCtrl(parent, shapes, *this)); - wxSizer* spinnerSizer = new wxBoxSizer(wxHORIZONTAL); + // TODO: These are yucky + wxSizer* spinnerSizer = new wxFlexGridSizer(2); spinnerSizer->Add(new wxStaticText(parent, wxID_ANY, _("Size"))); spinnerSizer->Add(new BrushSizeCtrl(parent, *this)); + spinnerSizer->Add(new wxStaticText(parent, wxID_ANY, _("Strength"))); + spinnerSizer->Add(new BrushStrengthCtrl(parent, *this)); sizer->Add(spinnerSizer); } @@ -164,7 +200,7 @@ void Brush::MakeActive() void Brush::Send() { if (m_IsActive) - POST_COMMAND(SetBrush(GetWidth(), GetHeight(), GetNewedData())); + POST_COMMAND(Brush(GetWidth(), GetHeight(), GetNewedData())); } diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.h index e964e03094..2d8e792934 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Tools/Common/Brushes.h @@ -3,18 +3,22 @@ class BrushShapeCtrl; class BrushSizeCtrl; +class BrushStrengthCtrl; class Brush { friend class BrushShapeCtrl; friend class BrushSizeCtrl; + friend class BrushStrengthCtrl; public: Brush(); ~Brush(); - int GetWidth(); - int GetHeight(); - float* GetNewedData(); // freshly allocated via new[] + int GetWidth() const; + int GetHeight() const; + float* GetNewedData() const; // freshly allocated via new[] + + float GetStrength() const; void CreateUI(wxWindow* parent, wxSizer* sizer); @@ -27,8 +31,9 @@ private: void Send(); enum BrushShape { SQUARE = 0, CIRCLE }; - BrushShape m_BrushShape; - int m_BrushSize; + BrushShape m_Shape; + int m_Size; + float m_Strength; bool m_IsActive; }; diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp index 9eda9c8cda..8ab420c1e6 100644 --- a/source/tools/atlas/GameInterface/GameLoop.cpp +++ b/source/tools/atlas/GameInterface/GameLoop.cpp @@ -37,6 +37,10 @@ void (*Atlas_NotifyEndOfFrame)(); static MessagePasserImpl msgPasser_Command; static MessagePasserImpl msgPasser_Input; +MessagePasser* AtlasMessage::g_MessagePasser_Command = &msgPasser_Command; +MessagePasser* AtlasMessage::g_MessagePasser_Input = &msgPasser_Input; + + static InputProcessor g_Input; static GameLoopState state; diff --git a/source/tools/atlas/GameInterface/Handlers/Brush.cpp b/source/tools/atlas/GameInterface/Handlers/Brush.cpp index 2667f3eda0..aa6826425d 100644 --- a/source/tools/atlas/GameInterface/Handlers/Brush.cpp +++ b/source/tools/atlas/GameInterface/Handlers/Brush.cpp @@ -6,7 +6,7 @@ namespace AtlasMessage { -MESSAGEHANDLER(SetBrush) +MESSAGEHANDLER(Brush) { g_CurrentBrush.SetData(msg->width, msg->height, msg->data); } diff --git a/source/tools/atlas/GameInterface/Handlers/Elevation.cpp b/source/tools/atlas/GameInterface/Handlers/Elevation.cpp index f7983218eb..a6efe3ed62 100644 --- a/source/tools/atlas/GameInterface/Handlers/Elevation.cpp +++ b/source/tools/atlas/GameInterface/Handlers/Elevation.cpp @@ -49,9 +49,13 @@ BEGIN_COMMAND(AlterElevation) roundingError -= (float)(int)roundingError; } + static CVector3D previousPosition; + d->pos.GetWorldSpace(g_CurrentBrush.m_Centre, previousPosition); + previousPosition = g_CurrentBrush.m_Centre; + int x0, y0; - d->pos.GetWorldSpace(g_CurrentBrush.m_Centre); 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) { diff --git a/source/tools/atlas/GameInterface/Handlers/Map.cpp b/source/tools/atlas/GameInterface/Handlers/Map.cpp index 82e325470b..daf733c79e 100644 --- a/source/tools/atlas/GameInterface/Handlers/Map.cpp +++ b/source/tools/atlas/GameInterface/Handlers/Map.cpp @@ -47,7 +47,7 @@ MESSAGEHANDLER(GenerateMap) for (int z = 0; z < vertices; ++z) for (int x = 0; x < vertices; ++x) // heightmap[x + z*vertices] = 32768 +(int)(2048.f*(rand()/(float)RAND_MAX-0.5f)); - heightmap[x + z*vertices] = 32768; + heightmap[x + z*vertices] = 16384; // Initialise terrain using the heightmap CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); diff --git a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp index 0f51327857..e24ef373f8 100644 --- a/source/tools/atlas/GameInterface/MessagePasserImpl.cpp +++ b/source/tools/atlas/GameInterface/MessagePasserImpl.cpp @@ -1,23 +1,25 @@ #include "precompiled.h" #include "MessagePasserImpl.h" +#include "Messages.h" -#define MESSAGE_TRACE 0 - -#if MESSAGE_TRACE -#include "Messages.h" // for mCommand implementation -#endif +#include "lib/timer.h" using namespace AtlasMessage; +template MessagePasserImpl::MessagePasserImpl() +: m_Trace(false) +{ +} + template void MessagePasserImpl::Add(T* msg) { debug_assert(msg); -#if MESSAGE_TRACE - debug_printf("Add %s\n", msg->GetType()); -#endif + if (m_Trace) + debug_printf("%8.3f add message: %s\n", get_time(), msg->GetType()); + m_Mutex.Lock(); m_Queue.push(msg); @@ -42,9 +44,7 @@ template T* MessagePasserImpl::Retrieve() m_Mutex.Unlock(); -#if MESSAGE_TRACE - if (msg) debug_printf("Retrieved %s\n", msg->GetType()); -#endif +// if (m_Trace && msg) debug_printf("%8.3f retrieved message: %s\n", get_time(), msg->GetType()); return msg; } @@ -57,8 +57,10 @@ template bool MessagePasserImpl::IsEmpty() return empty; } -MessagePasser* g_MessagePasser_Command = NULL; -MessagePasser* g_MessagePasser_Input = NULL; +template void MessagePasserImpl::SetTrace(bool t) +{ + m_Trace = t; +} // Explicit instantiation: template MessagePasserImpl; diff --git a/source/tools/atlas/GameInterface/MessagePasserImpl.h b/source/tools/atlas/GameInterface/MessagePasserImpl.h index 70496838a2..0c991f44fd 100644 --- a/source/tools/atlas/GameInterface/MessagePasserImpl.h +++ b/source/tools/atlas/GameInterface/MessagePasserImpl.h @@ -6,11 +6,15 @@ template class MessagePasserImpl : public AtlasMessage::MessagePasser { public: + MessagePasserImpl(); virtual void Add(T* msg); virtual T* Retrieve(); virtual bool IsEmpty(); + void SetTrace(bool t); + private: CMutex m_Mutex; std::queue m_Queue; + bool m_Trace; }; diff --git a/source/tools/atlas/GameInterface/Messages.h b/source/tools/atlas/GameInterface/Messages.h index 3973a13c55..fe3e22b200 100644 --- a/source/tools/atlas/GameInterface/Messages.h +++ b/source/tools/atlas/GameInterface/Messages.h @@ -36,9 +36,13 @@ COMMAND(RenderStyle, ((bool, wireframe)) ); +COMMAND(MessageTrace, + ((bool, enable)) + ); + ////////////////////////////////////////////////////////////////////////// -COMMAND(SetBrush, +COMMAND(Brush, ((int, width)) // number of vertices ((int, height)) ((float*, data)) // width*height array, allocated with new[] diff --git a/source/tools/atlas/GameInterface/MessagesSetup.h b/source/tools/atlas/GameInterface/MessagesSetup.h index 18f3872b52..591dbad257 100644 --- a/source/tools/atlas/GameInterface/MessagesSetup.h +++ b/source/tools/atlas/GameInterface/MessagesSetup.h @@ -26,11 +26,18 @@ struct Position 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. - void GetWorldSpace(CVector3D& vec) const; // (implementation in Misc.cpp) - void GetScreenSpace(float& x, float& y) const; // (implementation in Misc.cpp) + // Implementations in Misc.cpp. + void GetWorldSpace(CVector3D& vec) const; + void GetWorldSpace(CVector3D& vec, const CVector3D& prev) const; + void GetScreenSpace(float& x, float& y) const; }; ////////////////////////////////////////////////////////////////////////// diff --git a/source/tools/atlas/GameInterface/Misc.cpp b/source/tools/atlas/GameInterface/Misc.cpp index 992f202dc5..8e1c4e8bb6 100644 --- a/source/tools/atlas/GameInterface/Misc.cpp +++ b/source/tools/atlas/GameInterface/Misc.cpp @@ -19,12 +19,29 @@ void AtlasMessage::Position::GetWorldSpace(CVector3D& vec) const vec = g_Game->GetView()->GetCamera()->GetWorldCoordinates(type1.x, type1.y); break; + case 2: + debug_warn("Invalid Position acquisition (unchanged without previous)"); + vec.Set(0.f, 0.f, 0.f); + break; + default: debug_warn("Invalid Position type"); vec.Set(0.f, 0.f, 0.f); } } +void AtlasMessage::Position::GetWorldSpace(CVector3D& vec, const CVector3D& prev) const +{ + switch (type) + { + case 2: + vec = prev; + break; + default: + GetWorldSpace(vec); + } +} + void AtlasMessage::Position::GetScreenSpace(float& x, float& y) const { switch (type)