Allow map to recenter during resize in Atlas. Fixes #1109.
Patch By: Clockwork-Muse Tested By: Stan Differential Revision: https://code.wildfiregames.com/D825 This was SVN commit r23859.
This commit is contained in:
parent
25e8b38ba8
commit
3ed9df0d6c
@ -1136,6 +1136,7 @@ function setup_atlas_projects()
|
||||
"CustomControls/FileHistory",
|
||||
"CustomControls/HighResTimer",
|
||||
"CustomControls/MapDialog",
|
||||
"CustomControls/MapResizeDialog",
|
||||
"CustomControls/SnapSplitterWindow",
|
||||
"CustomControls/VirtualDirTreeCtrl",
|
||||
"CustomControls/Windows",
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include "simulation2/helpers/Los.h"
|
||||
#include "simulation2/system/ParamNode.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
extern bool g_GameRestarted;
|
||||
|
||||
@ -79,14 +79,7 @@ CMiniMap::CMiniMap(CGUI& pGUI) :
|
||||
// Register Relax NG validator
|
||||
CXeromyces::AddValidator(g_VFS, "pathfinder", "simulation/data/pathfinder.rng");
|
||||
|
||||
// Get the maximum height for unit passage in water.
|
||||
CParamNode externalParamNode;
|
||||
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
|
||||
const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses");
|
||||
if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk())
|
||||
m_ShallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat();
|
||||
else
|
||||
m_ShallowPassageHeight = 0.0f;
|
||||
m_ShallowPassageHeight = GetShallowPassageHeight();
|
||||
|
||||
m_AttributePos.type = GL_FLOAT;
|
||||
m_AttributePos.elems = 2;
|
||||
@ -719,3 +712,15 @@ void CMiniMap::Destroy()
|
||||
|
||||
SAFE_ARRAY_DELETE(m_TerrainData);
|
||||
}
|
||||
|
||||
// static
|
||||
float CMiniMap::GetShallowPassageHeight()
|
||||
{
|
||||
float shallowPassageHeight = 0.0f;
|
||||
CParamNode externalParamNode;
|
||||
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml", "pathfinder");
|
||||
const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses");
|
||||
if (pathingSettings.GetChild("default").IsOk() && pathingSettings.GetChild("default").GetChild("MaxWaterDepth").IsOk())
|
||||
shallowPassageHeight = pathingSettings.GetChild("default").GetChild("MaxWaterDepth").ToFloat();
|
||||
return shallowPassageHeight;
|
||||
}
|
||||
|
@ -32,6 +32,12 @@ class CMiniMap : public IGUIObject
|
||||
public:
|
||||
CMiniMap(CGUI& pGUI);
|
||||
virtual ~CMiniMap();
|
||||
|
||||
/**
|
||||
* @return The maximum height for unit passage in water.
|
||||
*/
|
||||
static float GetShallowPassageHeight();
|
||||
|
||||
protected:
|
||||
virtual void Draw();
|
||||
|
||||
|
@ -0,0 +1,119 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "MapResizeDialog.h"
|
||||
#include "GameInterface/MessagePasser.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
|
||||
#include <wx/statline.h>
|
||||
|
||||
MapResizeDialog::MapResizeDialog(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxRESIZE_BORDER)
|
||||
{
|
||||
Freeze();
|
||||
|
||||
AtlasMessage::qGetCurrentMapSize qrySize;
|
||||
qrySize.Post();
|
||||
m_NewSize = qrySize.size;
|
||||
|
||||
SetTitle(_("Resize/Recenter map"));
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxStaticText* label = new wxStaticText(this, wxID_ANY, _("Select new map size and center."), wxDefaultPosition, wxDefaultSize);
|
||||
sizer->Add(label, wxSizerFlags().Align(wxALIGN_CENTER_HORIZONTAL).Border(wxALL, 10));
|
||||
|
||||
wxBoxSizer* listAndMap = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
wxListBox* listBox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SINGLE | wxLB_HSCROLL);
|
||||
// Load the map sizes list
|
||||
AtlasMessage::qGetMapSizes qrySizes;
|
||||
qrySizes.Post();
|
||||
AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes);
|
||||
for (AtIter s = sizes["Data"]["item"]; s.defined(); ++s)
|
||||
{
|
||||
wxString size = wxString::FromUTF8(s["Tiles"]);
|
||||
listBox->Append(wxString::FromUTF8(s["Name"]), new wxStringClientData(size));
|
||||
if (m_NewSize == static_cast<ssize_t>(wxAtoi(size)))
|
||||
listBox->SetSelection(listBox->GetCount() - 1);
|
||||
}
|
||||
listAndMap->Add(listBox, wxSizerFlags().Align(wxALIGN_LEFT).Proportion(1).Expand());
|
||||
listAndMap->AddSpacer(10);
|
||||
|
||||
m_MiniMap = new PseudoMiniMapPanel(this, m_NewSize);
|
||||
listBox->Bind(wxEVT_LISTBOX, &PseudoMiniMapPanel::OnNewSize, m_MiniMap);
|
||||
|
||||
listAndMap->Add(m_MiniMap, wxSizerFlags());
|
||||
sizer->Add(listAndMap, wxSizerFlags().Proportion(1).Expand().Border(wxLEFT | wxRIGHT, 10));
|
||||
|
||||
sizer->AddSpacer(5);
|
||||
sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL), wxSizerFlags().Expand().Border(wxRIGHT | wxLEFT, 7));
|
||||
sizer->AddSpacer(5);
|
||||
|
||||
wxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttonSizer->Add(new wxButton(this, wxID_OK, _("OK")));
|
||||
buttonSizer->AddSpacer(5);
|
||||
buttonSizer->Add(new wxButton(this, wxID_CANCEL, _("Cancel")));
|
||||
|
||||
sizer->Add(buttonSizer, wxSizerFlags().Align(wxALIGN_RIGHT).Border(wxRIGHT | wxBOTTOM, 10));
|
||||
|
||||
SetSizerAndFit(sizer);
|
||||
Layout();
|
||||
Thaw();
|
||||
}
|
||||
|
||||
ssize_t MapResizeDialog::GetNewSize() const
|
||||
{
|
||||
return m_NewSize;
|
||||
}
|
||||
|
||||
wxPoint MapResizeDialog::GetOffset() const
|
||||
{
|
||||
return m_MiniMap->GetOffset();
|
||||
}
|
||||
|
||||
void MapResizeDialog::OnListBox(wxCommandEvent& evt)
|
||||
{
|
||||
if (!evt.IsSelection())
|
||||
return;
|
||||
|
||||
const wxString str = static_cast<wxStringClientData*>(evt.GetClientObject())->GetData();
|
||||
long value = 0;
|
||||
if (str.ToLong(&value))
|
||||
m_NewSize = static_cast<ssize_t>(value);
|
||||
|
||||
if (evt.GetEventType() == wxEVT_COMMAND_LISTBOX_DOUBLECLICKED)
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void MapResizeDialog::OnCancel(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
|
||||
void MapResizeDialog::OnOK(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(MapResizeDialog, wxDialog)
|
||||
EVT_BUTTON(wxID_CANCEL, MapResizeDialog::OnCancel)
|
||||
EVT_BUTTON(wxID_OK, MapResizeDialog::OnOK)
|
||||
EVT_LISTBOX(wxID_ANY, MapResizeDialog::OnListBox)
|
||||
EVT_LISTBOX_DCLICK(wxID_ANY, MapResizeDialog::OnListBox)
|
||||
END_EVENT_TABLE()
|
@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_MAPRESIZEDIALOG
|
||||
#define INCLUDED_MAPRESIZEDIALOG
|
||||
|
||||
#include "PseudoMiniMapPanel.h"
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
class MapResizeDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
MapResizeDialog(wxWindow* parent);
|
||||
|
||||
/**
|
||||
* Returns selected new size.
|
||||
*/
|
||||
ssize_t GetNewSize() const;
|
||||
|
||||
/**
|
||||
* Returns the offset from center.
|
||||
*/
|
||||
wxPoint GetOffset() const;
|
||||
|
||||
private:
|
||||
void OnCancel(wxCommandEvent& evt);
|
||||
void OnOK(wxCommandEvent& evt);
|
||||
void OnListBox(wxCommandEvent& evt);
|
||||
|
||||
ssize_t m_NewSize;
|
||||
PseudoMiniMapPanel* m_MiniMap;
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
#endif // INCLUDED_MAPRESIZEDIALOG
|
@ -0,0 +1,232 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "PseudoMiniMapPanel.h"
|
||||
|
||||
#include "GameInterface/MessagePasser.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
#include "ScenarioEditor/Tools/Common/Tools.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <wx/dcgraph.h>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/event.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const int PanelRadius = 64 + 1;
|
||||
const wxPoint PanelCenter = wxPoint(PanelRadius + 1, PanelRadius + 1);
|
||||
const wxPoint ScreenToneOffset(-2 * PanelRadius, -2 * PanelRadius);
|
||||
const wxPen Rim(*wxBLACK, 3);
|
||||
const wxPen BackgroundMask(*wxBLACK, 2 * PanelRadius);
|
||||
|
||||
bool Within(const wxPoint& test, const wxPoint& center, int radius)
|
||||
{
|
||||
int dx = abs(test.x - center.x);
|
||||
if (dx > radius)
|
||||
return false;
|
||||
int dy = abs(test.y - center.y);
|
||||
if (dy > radius)
|
||||
return false;
|
||||
if (dx + dy <= radius)
|
||||
return true;
|
||||
return dx * dx + dy * dy <= radius * radius;
|
||||
}
|
||||
}
|
||||
|
||||
PseudoMiniMapPanel::PseudoMiniMapPanel(wxWindow* parent, int currentSize)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(PanelRadius * 2 + 1, PanelRadius * 2 + 1)),
|
||||
m_CurrentSize(currentSize), m_ScreenTones(),
|
||||
m_LastMousePos(-1, -1), m_Dragging(false),
|
||||
m_SelectionRadius(PanelRadius), m_SelectionCenter(PanelCenter), m_SameOrGrowing(true), m_NewSize(currentSize)
|
||||
{
|
||||
AtlasMessage::qRasterizeMinimap qryBackground;
|
||||
qryBackground.Post();
|
||||
int dim = qryBackground.dimension;
|
||||
std::vector<uint8_t> imageBytes = *qryBackground.imageBytes;
|
||||
|
||||
// Data is destined for a wxImage, which uses free.
|
||||
uint8_t* data = new uint8_t[imageBytes.size()];
|
||||
std::copy(imageBytes.cbegin(), imageBytes.cend(), data);
|
||||
m_Background = wxImage(dim, dim, data);
|
||||
m_Background.Rescale(PanelRadius * 2, PanelRadius * 2, wxIMAGE_QUALITY_BOX_AVERAGE);
|
||||
m_Backgrounds[PanelRadius] = wxBitmap(m_Background);
|
||||
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
}
|
||||
|
||||
wxPoint PseudoMiniMapPanel::GetOffset() const
|
||||
{
|
||||
// Since offset is from center, amplitude is (at most) half the largest size.
|
||||
int size = std::max(m_CurrentSize, m_NewSize) / 2;
|
||||
// If the map is growing, the display is opposite what the actual offset is.
|
||||
float scalar = (m_SameOrGrowing ? 1.0 : -1.0) / PanelRadius * size;
|
||||
// Rebase offsets to center.
|
||||
int hOffset = m_SelectionCenter.x - PanelCenter.x;
|
||||
int vOffset = m_SelectionCenter.y - PanelCenter.y;
|
||||
return wxPoint(scalar * hOffset, scalar * vOffset);
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::OnNewSize(wxCommandEvent& evt)
|
||||
{
|
||||
if (!evt.IsSelection())
|
||||
return;
|
||||
|
||||
evt.Skip();
|
||||
|
||||
m_NewSize = wxAtoi(static_cast<wxStringClientData*>(evt.GetClientObject())->GetData());
|
||||
|
||||
m_SameOrGrowing = m_NewSize >= m_CurrentSize;
|
||||
m_SelectionRadius = std::min(m_NewSize, m_CurrentSize) * PanelRadius / std::max(m_NewSize, m_CurrentSize);
|
||||
if (!m_SameOrGrowing && m_ScreenTones.find(m_SelectionRadius) == m_ScreenTones.cend())
|
||||
{
|
||||
wxImage overlay = wxImage(PanelRadius * 4, PanelRadius * 4);
|
||||
overlay.InitAlpha();
|
||||
wxGraphicsContext* gc = wxGraphicsContext::Create(overlay);
|
||||
gc->SetBrush(*wxGREY_BRUSH);
|
||||
gc->DrawRectangle(0, 0, PanelRadius * 4, PanelRadius * 4);
|
||||
gc->SetBrush(*wxBLACK_BRUSH);
|
||||
gc->DrawEllipse(PanelRadius * 2 - m_SelectionRadius, PanelRadius * 2 - m_SelectionRadius, m_SelectionRadius * 2, m_SelectionRadius * 2);
|
||||
gc->SetPen(*wxWHITE_PEN);
|
||||
gc->DrawEllipse(PanelRadius * 2 - m_SelectionRadius, PanelRadius * 2 - m_SelectionRadius, m_SelectionRadius * 2, m_SelectionRadius * 2);
|
||||
delete gc;
|
||||
// Black -> Converted to transparent.
|
||||
// White -> converted to black.
|
||||
overlay.ConvertColourToAlpha(0, 0, 0);
|
||||
|
||||
m_ScreenTones[m_SelectionRadius] = wxBitmap(overlay);
|
||||
}
|
||||
else if (m_SameOrGrowing && m_Backgrounds.find(m_SelectionRadius) == m_Backgrounds.cend())
|
||||
{
|
||||
wxImage rescaled = wxImage(m_Background);
|
||||
rescaled.Rescale(2 * m_SelectionRadius, 2 * m_SelectionRadius, wxIMAGE_QUALITY_BOX_AVERAGE);
|
||||
m_Backgrounds[m_SelectionRadius] = wxBitmap(rescaled);
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::OnMouseDown(wxMouseEvent& evt)
|
||||
{
|
||||
// Capture on button-down, so we can respond even when the mouse
|
||||
// moves off the window
|
||||
if (!m_Dragging && evt.ButtonDown() &&
|
||||
Within(evt.GetPosition(), PanelCenter, PanelRadius) &&
|
||||
Within(evt.GetPosition(), m_SelectionCenter, m_SelectionRadius))
|
||||
{
|
||||
m_LastMousePos = evt.GetPosition();
|
||||
m_Dragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::OnMouseUp(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_Dragging &&
|
||||
!(evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_MIDDLE) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
|
||||
)
|
||||
{
|
||||
m_Dragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::OnMouseMove(wxMouseEvent& evt)
|
||||
{
|
||||
if (m_Dragging && evt.Dragging())
|
||||
{
|
||||
if (m_LastMousePos == evt.GetPosition())
|
||||
return;
|
||||
|
||||
wxPoint delta = evt.GetPosition() - m_LastMousePos;
|
||||
wxPoint moved = m_SelectionCenter + delta;
|
||||
|
||||
if (!Within(moved, PanelCenter, PanelRadius))
|
||||
return;
|
||||
|
||||
m_SelectionCenter = moved;
|
||||
m_LastMousePos = evt.GetPosition();
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
|
||||
{
|
||||
m_Dragging = false;
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::PaintEvent(wxPaintEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxAutoBufferedPaintDC dca(this);
|
||||
// Background must be grabbed from paint dc, not gc, or color may be transparent.
|
||||
wxColor background = dca.GetBackground().GetColour();
|
||||
wxGCDC dc(dca);
|
||||
if (m_SameOrGrowing)
|
||||
{
|
||||
dc.DrawBitmap(m_Backgrounds[m_SelectionRadius], m_SelectionCenter - wxSize(m_SelectionRadius, m_SelectionRadius));
|
||||
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen(BackgroundMask);
|
||||
dc.DrawCircle(m_SelectionCenter, PanelRadius + m_SelectionRadius);
|
||||
|
||||
const wxPen BorderPen(*wxWHITE, 2);
|
||||
dc.SetPen(BorderPen);
|
||||
dc.DrawCircle(m_SelectionCenter, m_SelectionRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawBitmap(m_Backgrounds[PanelRadius], 0, 0);
|
||||
// "fade out" trimmed areas by drawing a screentone ring ring.
|
||||
dc.DrawBitmap(m_ScreenTones[m_SelectionRadius], ScreenToneOffset + m_SelectionCenter);
|
||||
}
|
||||
|
||||
// Centering markers.
|
||||
dc.SetBrush(*wxBLACK_BRUSH);
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.DrawCircle(m_SelectionCenter, 2);
|
||||
dc.SetPen(*wxWHITE_PEN);
|
||||
dc.DrawLine(PanelRadius - 10, PanelRadius, PanelRadius + 10, PanelRadius);
|
||||
dc.DrawLine(PanelRadius, PanelRadius + 10, PanelRadius, PanelRadius - 10);
|
||||
|
||||
// Round border.
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.SetPen(Rim);
|
||||
dc.DrawCircle(PanelCenter, PanelRadius - 1);
|
||||
wxPen mask(background, PanelRadius);
|
||||
dc.SetPen(mask);
|
||||
dc.DrawCircle(PanelCenter, PanelRadius + PanelRadius / 2 - 1);
|
||||
}
|
||||
|
||||
void PseudoMiniMapPanel::EraseBackground(wxEraseEvent& WXUNUSED(evt))
|
||||
{
|
||||
// Do nothing - don't erase to remove flicker.
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(PseudoMiniMapPanel, wxPanel)
|
||||
EVT_LEAVE_WINDOW(PseudoMiniMapPanel::OnMouseUp)
|
||||
EVT_LEFT_DOWN(PseudoMiniMapPanel::OnMouseDown)
|
||||
EVT_LEFT_UP(PseudoMiniMapPanel::OnMouseUp)
|
||||
EVT_RIGHT_DOWN(PseudoMiniMapPanel::OnMouseDown)
|
||||
EVT_RIGHT_UP(PseudoMiniMapPanel::OnMouseUp)
|
||||
EVT_MIDDLE_DOWN(PseudoMiniMapPanel::OnMouseDown)
|
||||
EVT_MIDDLE_UP(PseudoMiniMapPanel::OnMouseUp)
|
||||
EVT_MOTION(PseudoMiniMapPanel::OnMouseMove)
|
||||
EVT_LEAVE_WINDOW(PseudoMiniMapPanel::OnMouseLeave)
|
||||
EVT_PAINT(PseudoMiniMapPanel::PaintEvent)
|
||||
END_EVENT_TABLE()
|
@ -0,0 +1,57 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_PSEUDOMINIMAPPANEL
|
||||
#define INCLUDED_PSEUDOMINIMAPPANEL
|
||||
|
||||
#include <map>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class PseudoMiniMapPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
PseudoMiniMapPanel(wxWindow* parent, int currentSize);
|
||||
|
||||
void PaintEvent(wxPaintEvent& evt);
|
||||
void EraseBackground(wxEraseEvent& evt);
|
||||
|
||||
void OnNewSize(wxCommandEvent& evt);
|
||||
|
||||
wxPoint GetOffset() const;
|
||||
private:
|
||||
void OnMouseDown(wxMouseEvent& evt);
|
||||
void OnMouseUp(wxMouseEvent& evt);
|
||||
void OnMouseMove(wxMouseEvent& evt);
|
||||
void OnMouseLeave(wxMouseEvent& evt);
|
||||
|
||||
const ssize_t m_CurrentSize;
|
||||
wxImage m_Background;
|
||||
std::map<int, wxBitmap> m_ScreenTones;
|
||||
std::map<int, wxBitmap> m_Backgrounds;
|
||||
|
||||
wxPoint m_LastMousePos;
|
||||
bool m_Dragging;
|
||||
wxPoint m_SelectionCenter;
|
||||
int m_SelectionRadius;
|
||||
bool m_SameOrGrowing;
|
||||
ssize_t m_NewSize;
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
#endif // INCLUDED_PSEUDOMINIMAPPANEL
|
@ -22,6 +22,7 @@
|
||||
#include "AtlasObject/AtlasObject.h"
|
||||
#include "AtlasObject/JSONSpiritInclude.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
#include "MapResizeDialog/MapResizeDialog.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "ScenarioEditor/Tools/Common/Tools.h"
|
||||
|
||||
@ -50,6 +51,7 @@ enum
|
||||
ID_RandomSeed,
|
||||
ID_RandomReseed,
|
||||
ID_RandomGenerate,
|
||||
ID_ResizeMap,
|
||||
ID_SimPlay,
|
||||
ID_SimFast,
|
||||
ID_SimSlow,
|
||||
@ -461,6 +463,14 @@ MapSidebar::MapSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContaine
|
||||
_("Run selected random map script")), wxSizerFlags().Expand());
|
||||
}
|
||||
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc tools
|
||||
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _("Misc tools"));
|
||||
sizer->Add(new wxButton(scrolledWindow, ID_ResizeMap, _("Resize/Recenter map")), wxSizerFlags().Expand());
|
||||
scrollSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 10));
|
||||
}
|
||||
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Simulation buttons
|
||||
@ -696,6 +706,16 @@ void MapSidebar::OnOpenPlayerPanel(wxCommandEvent& WXUNUSED(evt))
|
||||
m_ScenarioEditor.SelectPage(_T("PlayerSidebar"));
|
||||
}
|
||||
|
||||
void MapSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
MapResizeDialog dlg(this);
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
wxPoint offset = dlg.GetOffset();
|
||||
POST_COMMAND(ResizeMap, (dlg.GetNewSize(), offset.x, offset.y));
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(MapSidebar, Sidebar)
|
||||
EVT_COLLAPSIBLEPANE_CHANGED(wxID_ANY, MapSidebar::OnCollapse)
|
||||
EVT_BUTTON(ID_SimPlay, MapSidebar::OnSimPlay)
|
||||
@ -705,5 +725,6 @@ BEGIN_EVENT_TABLE(MapSidebar, Sidebar)
|
||||
EVT_BUTTON(ID_SimReset, MapSidebar::OnSimReset)
|
||||
EVT_BUTTON(ID_RandomReseed, MapSidebar::OnRandomReseed)
|
||||
EVT_BUTTON(ID_RandomGenerate, MapSidebar::OnRandomGenerate)
|
||||
EVT_BUTTON(ID_ResizeMap, MapSidebar::OnResizeMap)
|
||||
EVT_BUTTON(ID_OpenPlayerPanel, MapSidebar::OnOpenPlayerPanel)
|
||||
END_EVENT_TABLE();
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
#include "../Common/Sidebar.h"
|
||||
|
||||
#include "wx/collpane.h"
|
||||
#include <wx/collpane.h>
|
||||
|
||||
class MapSettingsControl;
|
||||
|
||||
@ -35,12 +35,13 @@ private:
|
||||
MapSettingsControl* m_MapSettingsCtrl;
|
||||
|
||||
void OnCollapse(wxCollapsiblePaneEvent& evt);
|
||||
void OnOpenPlayerPanel(wxCommandEvent& evt);
|
||||
void OnRandomReseed(wxCommandEvent& evt);
|
||||
void OnRandomGenerate(wxCommandEvent& evt);
|
||||
void OnResizeMap(wxCommandEvent& evt);
|
||||
void OnSimPlay(wxCommandEvent& evt);
|
||||
void OnSimPause(wxCommandEvent& evt);
|
||||
void OnSimReset(wxCommandEvent& evt);
|
||||
void OnRandomReseed(wxCommandEvent& evt);
|
||||
void OnRandomGenerate(wxCommandEvent& evt);
|
||||
void OnOpenPlayerPanel(wxCommandEvent& evt);
|
||||
void UpdateSimButtons();
|
||||
|
||||
int m_SimState;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -26,12 +26,12 @@
|
||||
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
#include "wx/spinctrl.h"
|
||||
#include "wx/listctrl.h"
|
||||
#include "wx/image.h"
|
||||
#include "wx/imaglist.h"
|
||||
#include "wx/busyinfo.h"
|
||||
#include "wx/notebook.h"
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/imaglist.h>
|
||||
#include <wx/busyinfo.h>
|
||||
#include <wx/notebook.h>
|
||||
|
||||
class TextureNotebook;
|
||||
|
||||
@ -47,8 +47,7 @@ private:
|
||||
enum
|
||||
{
|
||||
ID_Passability = 1,
|
||||
ID_ShowPriorities,
|
||||
ID_ResizeMap
|
||||
ID_ShowPriorities
|
||||
};
|
||||
|
||||
// Helper function for adding tooltips
|
||||
@ -247,14 +246,6 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
|
||||
_("Show terrain texture priorities")));
|
||||
}
|
||||
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Misc tools
|
||||
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, scrolledWindow, _("Misc tools"));
|
||||
sizer->Add(new wxButton(scrolledWindow, ID_ResizeMap, _("Resize map")), wxSizerFlags().Expand());
|
||||
scrollSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 10));
|
||||
}
|
||||
|
||||
m_BottomBar = new TerrainBottomBar(scenarioEditor, bottomBarContainer);
|
||||
}
|
||||
|
||||
@ -283,37 +274,9 @@ void TerrainSidebar::OnShowPriorities(wxCommandEvent& evt)
|
||||
POST_MESSAGE(SetViewParamB, (AtlasMessage::eRenderView::GAME, L"priorities", evt.IsChecked()));
|
||||
}
|
||||
|
||||
void TerrainSidebar::OnResizeMap(wxCommandEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxArrayString sizeNames;
|
||||
std::vector<size_t> sizeTiles;
|
||||
|
||||
// Load the map sizes list
|
||||
AtlasMessage::qGetMapSizes qrySizes;
|
||||
qrySizes.Post();
|
||||
AtObj sizes = AtlasObject::LoadFromJSON(*qrySizes.sizes);
|
||||
for (AtIter s = sizes["Data"]["item"]; s.defined(); ++s)
|
||||
{
|
||||
sizeNames.Add(wxString::FromUTF8(s["Name"]));
|
||||
sizeTiles.push_back((*s["Tiles"]).getLong());
|
||||
}
|
||||
|
||||
// TODO: set default based on current map size
|
||||
|
||||
wxSingleChoiceDialog dlg(this, _("Select new map size. WARNING: This probably only works reliably on blank maps."),
|
||||
_("Resize map"), sizeNames);
|
||||
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
size_t tiles = sizeTiles.at(dlg.GetSelection());
|
||||
POST_COMMAND(ResizeMap, (tiles));
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(TerrainSidebar, Sidebar)
|
||||
EVT_CHOICE(ID_Passability, TerrainSidebar::OnPassabilityChoice)
|
||||
EVT_CHECKBOX(ID_ShowPriorities, TerrainSidebar::OnShowPriorities)
|
||||
EVT_BUTTON(ID_ResizeMap, TerrainSidebar::OnResizeMap)
|
||||
END_EVENT_TABLE();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -30,11 +30,9 @@ protected:
|
||||
private:
|
||||
void OnPassabilityChoice(wxCommandEvent& evt);
|
||||
void OnShowPriorities(wxCommandEvent& evt);
|
||||
void OnResizeMap(wxCommandEvent& evt);
|
||||
|
||||
wxChoice* m_PassabilityChoice;
|
||||
TexturePreviewPanel* m_TexturePreview;
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
|
||||
|
@ -18,8 +18,9 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "MessageHandler.h"
|
||||
#include "../GameLoop.h"
|
||||
#include "../CommandProc.h"
|
||||
#include "../GameLoop.h"
|
||||
#include "../MessagePasser.h"
|
||||
|
||||
#include "graphics/GameView.h"
|
||||
#include "graphics/LOSTexture.h"
|
||||
@ -29,6 +30,7 @@
|
||||
#include "graphics/Terrain.h"
|
||||
#include "graphics/TerrainTextureEntry.h"
|
||||
#include "graphics/TerrainTextureManager.h"
|
||||
#include "gui/ObjectTypes/CMiniMap.h"
|
||||
#include "lib/bits.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "lib/status.h"
|
||||
@ -36,16 +38,22 @@
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/GameSetup/GameSetup.h"
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/World.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/WaterManager.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpOwnership.h"
|
||||
#include "simulation2/components/ICmpPlayer.h"
|
||||
#include "simulation2/components/ICmpPlayerManager.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
#include "simulation2/components/ICmpTerrain.h"
|
||||
#include "simulation2/components/ICmpVisual.h"
|
||||
#include "simulation2/system/ParamNode.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -271,17 +279,128 @@ QUERYHANDLER(GetMapSizes)
|
||||
msg->sizes = g_Game->GetSimulation2()->GetMapSizes();
|
||||
}
|
||||
|
||||
QUERYHANDLER(RasterizeMinimap)
|
||||
{
|
||||
// TODO: remove the code duplication of the rasterization algorithm, using
|
||||
// CMinimap version.
|
||||
const CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
const ssize_t dimension = terrain->GetVerticesPerSide() - 1;
|
||||
const ssize_t bpp = 24;
|
||||
const ssize_t imageDataSize = dimension * dimension * (bpp / 8);
|
||||
|
||||
std::vector<u8> imageBytes(imageDataSize);
|
||||
|
||||
float shallowPassageHeight = CMiniMap::GetShallowPassageHeight();
|
||||
|
||||
ssize_t w = dimension;
|
||||
ssize_t h = dimension;
|
||||
float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight;
|
||||
|
||||
for (ssize_t j = 0; j < h; ++j)
|
||||
{
|
||||
// Work backwards to vertically flip the image.
|
||||
ssize_t position = 3 * (h - j - 1) * dimension;
|
||||
for (ssize_t i = 0; i < w; ++i)
|
||||
{
|
||||
float avgHeight = (terrain->GetVertexGroundLevel(i, j)
|
||||
+ terrain->GetVertexGroundLevel(i + 1, j)
|
||||
+ terrain->GetVertexGroundLevel(i, j + 1)
|
||||
+ terrain->GetVertexGroundLevel(i + 1, j + 1)
|
||||
) / 4.0f;
|
||||
|
||||
if (avgHeight < waterHeight && avgHeight > waterHeight - shallowPassageHeight)
|
||||
{
|
||||
// shallow water
|
||||
imageBytes[position++] = 0x70;
|
||||
imageBytes[position++] = 0x98;
|
||||
imageBytes[position++] = 0xc0;
|
||||
}
|
||||
else if (avgHeight < waterHeight)
|
||||
{
|
||||
// Set water as constant color for consistency on different maps
|
||||
imageBytes[position++] = 0x50;
|
||||
imageBytes[position++] = 0x78;
|
||||
imageBytes[position++] = 0xa0;
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 color = std::numeric_limits<u32>::max();
|
||||
u32 hmap = static_cast<u32>(terrain->GetHeightMap()[j * dimension + i]) >> 8;
|
||||
float scale = hmap / 3.0f + 170.0f / 255.0f;
|
||||
|
||||
CMiniPatch* mp = terrain->GetTile(i, j);
|
||||
if (mp)
|
||||
{
|
||||
CTerrainTextureEntry* tex = mp->GetTextureEntry();
|
||||
if (tex)
|
||||
color = tex->GetBaseColor();
|
||||
}
|
||||
|
||||
// Convert
|
||||
imageBytes[position++] = static_cast<u8>(static_cast<float>(color & 0xff) * scale);
|
||||
imageBytes[position++] = static_cast<u8>(static_cast<float>((color >> 8) & 0xff) * scale);
|
||||
imageBytes[position++] = static_cast<u8>(static_cast<float>((color >> 16) & 0xff) * scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg->imageBytes = std::move(imageBytes);
|
||||
msg->dimension = dimension;
|
||||
}
|
||||
|
||||
QUERYHANDLER(GetRMSData)
|
||||
{
|
||||
msg->data = g_Game->GetSimulation2()->GetRMSData();
|
||||
}
|
||||
|
||||
QUERYHANDLER(GetCurrentMapSize)
|
||||
{
|
||||
msg->size = g_Game->GetWorld()->GetTerrain()->GetTilesPerSide();
|
||||
}
|
||||
|
||||
BEGIN_COMMAND(ResizeMap)
|
||||
{
|
||||
int m_OldTiles, m_NewTiles;
|
||||
|
||||
cResizeMap()
|
||||
bool Within(const CFixedVector3D& pos, const int centerX, const int centerZ, const int radius)
|
||||
{
|
||||
int dx = abs(pos.X.ToInt_RoundToZero() - centerX);
|
||||
if (dx > radius)
|
||||
return false;
|
||||
int dz = abs(pos.Z.ToInt_RoundToZero() - centerZ);
|
||||
if (dz > radius)
|
||||
return false;
|
||||
if (dx + dz <= radius)
|
||||
return true;
|
||||
return dx * dx + dz * dz <= radius * radius;
|
||||
}
|
||||
|
||||
struct DeletedObject
|
||||
{
|
||||
entity_id_t entityId;
|
||||
CStr templateName;
|
||||
player_id_t owner;
|
||||
CFixedVector3D pos;
|
||||
CFixedVector3D rot;
|
||||
u32 actorSeed;
|
||||
};
|
||||
|
||||
ssize_t m_OldPatches, m_NewPatches;
|
||||
int m_OffsetX, m_OffsetY;
|
||||
|
||||
u16* m_Heightmap;
|
||||
CPatch* m_Patches;
|
||||
|
||||
std::vector<DeletedObject> m_DeletedObjects;
|
||||
std::vector<std::pair<entity_id_t, CFixedVector3D>> m_OldPositions;
|
||||
std::vector<std::pair<entity_id_t, CFixedVector3D>> m_NewPositions;
|
||||
|
||||
cResizeMap() : m_Heightmap(nullptr), m_Patches(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
~cResizeMap()
|
||||
{
|
||||
delete[] m_Heightmap;
|
||||
delete[] m_Patches;
|
||||
}
|
||||
|
||||
void MakeDirty()
|
||||
@ -295,41 +414,185 @@ BEGIN_COMMAND(ResizeMap)
|
||||
g_Game->GetView()->GetLOSTexture().MakeDirty();
|
||||
}
|
||||
|
||||
void ResizeTerrain(int tiles)
|
||||
void ResizeTerrain(ssize_t patches, int offsetX, int offsetY)
|
||||
{
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
terrain->ResizeAndOffset(patches, -offsetX, -offsetY);
|
||||
}
|
||||
|
||||
const ssize_t newSize = tiles / PATCH_SIZE;
|
||||
const ssize_t offset = (newSize - terrain->GetPatchesPerSide()) / 2;
|
||||
terrain->ResizeAndOffset(newSize, offset, offset);
|
||||
void DeleteObjects(const std::vector<DeletedObject>& deletedObjects)
|
||||
{
|
||||
for (const DeletedObject& deleted : deletedObjects)
|
||||
g_Game->GetSimulation2()->DestroyEntity(deleted.entityId);
|
||||
|
||||
MakeDirty();
|
||||
g_Game->GetSimulation2()->FlushDestroyedEntities();
|
||||
}
|
||||
|
||||
void RestoreObjects(const std::vector<DeletedObject>& deletedObjects)
|
||||
{
|
||||
CSimulation2& sim = *g_Game->GetSimulation2();
|
||||
|
||||
for (const DeletedObject& deleted : deletedObjects)
|
||||
{
|
||||
entity_id_t ent = sim.AddEntity(deleted.templateName.FromUTF8(), deleted.entityId);
|
||||
if (ent == INVALID_ENTITY)
|
||||
{
|
||||
LOGERROR("Failed to load entity template '%s'", deleted.templateName.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
CmpPtr<ICmpPosition> cmpPosition(sim, deleted.entityId);
|
||||
if (cmpPosition)
|
||||
{
|
||||
cmpPosition->JumpTo(deleted.pos.X, deleted.pos.Z);
|
||||
cmpPosition->SetXZRotation(deleted.rot.X, deleted.rot.Z);
|
||||
cmpPosition->SetYRotation(deleted.rot.Y);
|
||||
}
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(sim, deleted.entityId);
|
||||
if (cmpOwnership)
|
||||
cmpOwnership->SetOwner(deleted.owner);
|
||||
|
||||
CmpPtr<ICmpVisual> cmpVisual(sim, deleted.entityId);
|
||||
if (cmpVisual)
|
||||
cmpVisual->SetActorSeed(deleted.actorSeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetMovedEntitiesPosition(const std::vector<std::pair<entity_id_t, CFixedVector3D>>& movedObjects)
|
||||
{
|
||||
for (const std::pair<entity_id_t, CFixedVector3D>& obj : movedObjects)
|
||||
{
|
||||
const entity_id_t id = obj.first;
|
||||
const CFixedVector3D position = obj.second;
|
||||
CmpPtr<ICmpPosition> cmpPosition(*g_Game->GetSimulation2(), id);
|
||||
ENSURE(cmpPosition);
|
||||
cmpPosition->JumpTo(position.X, position.Z);
|
||||
}
|
||||
}
|
||||
|
||||
void Do()
|
||||
{
|
||||
CmpPtr<ICmpTerrain> cmpTerrain(*g_Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||
CSimulation2& sim = *g_Game->GetSimulation2();
|
||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(sim, SYSTEM_ENTITY);
|
||||
ENSURE(cmpTemplateManager);
|
||||
|
||||
CmpPtr<ICmpTerrain> cmpTerrain(sim, SYSTEM_ENTITY);
|
||||
if (!cmpTerrain)
|
||||
{
|
||||
m_OldTiles = m_NewTiles = 0;
|
||||
m_OldPatches = m_NewPatches = 0;
|
||||
m_OffsetX = m_OffsetY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OldTiles = (int)cmpTerrain->GetTilesPerSide();
|
||||
m_NewTiles = msg->tiles;
|
||||
m_OldPatches = static_cast<ssize_t>(cmpTerrain->GetTilesPerSide() / PATCH_SIZE);
|
||||
m_NewPatches = msg->tiles / PATCH_SIZE;
|
||||
m_OffsetX = msg->offsetX / PATCH_SIZE;
|
||||
// Need to flip direction of vertical offset, due to screen mapping order.
|
||||
m_OffsetY = -(msg->offsetY / PATCH_SIZE);
|
||||
|
||||
CTerrain* terrain = cmpTerrain->GetCTerrain();
|
||||
m_Heightmap = new u16[(m_OldPatches * PATCH_SIZE + 1) * (m_OldPatches * PATCH_SIZE + 1)];
|
||||
std::copy_n(terrain->GetHeightMap(), (m_OldPatches * PATCH_SIZE + 1) * (m_OldPatches * PATCH_SIZE + 1), m_Heightmap);
|
||||
m_Patches = new CPatch[m_OldPatches * m_OldPatches];
|
||||
for (ssize_t j = 0; j < m_OldPatches; ++j)
|
||||
for (ssize_t i = 0; i < m_OldPatches; ++i)
|
||||
{
|
||||
CPatch& src = *(terrain->GetPatch(i, j));
|
||||
CPatch& dst = m_Patches[j * m_OldPatches + i];
|
||||
std::copy_n(&src.m_MiniPatches[0][0], PATCH_SIZE * PATCH_SIZE, &dst.m_MiniPatches[0][0]);
|
||||
}
|
||||
}
|
||||
|
||||
ResizeTerrain(m_NewTiles);
|
||||
const int radiusInTerrainUnits = m_NewPatches * PATCH_SIZE * TERRAIN_TILE_SIZE / 2 * (1.f - 1e-6f);
|
||||
// Opposite direction offset, as we move the destination onto the source, not the source into the destination.
|
||||
const int mapCenterX = (m_OldPatches / 2 - m_OffsetX) * PATCH_SIZE * TERRAIN_TILE_SIZE;
|
||||
const int mapCenterZ = (m_OldPatches / 2 - m_OffsetY) * PATCH_SIZE * TERRAIN_TILE_SIZE;
|
||||
// The offset to move units by is opposite the direction the map is moved, and from the corner.
|
||||
const int offsetX = ((m_NewPatches - m_OldPatches) / 2 + m_OffsetX) * PATCH_SIZE * TERRAIN_TILE_SIZE;
|
||||
const int offsetZ = ((m_NewPatches - m_OldPatches) / 2 + m_OffsetY) * PATCH_SIZE * TERRAIN_TILE_SIZE;
|
||||
const CFixedVector3D offset = CFixedVector3D(fixed::FromInt(offsetX), fixed::FromInt(0), fixed::FromInt(offsetZ));
|
||||
|
||||
const CSimulation2::InterfaceListUnordered& ents = sim.GetEntitiesWithInterfaceUnordered(IID_Selectable);
|
||||
for (const std::pair<entity_id_t, IComponent*>& ent : ents)
|
||||
{
|
||||
const entity_id_t entityId = ent.first;
|
||||
|
||||
CmpPtr<ICmpPosition> cmpPosition(sim, entityId);
|
||||
|
||||
if (cmpPosition && cmpPosition->IsInWorld() && Within(cmpPosition->GetPosition(), mapCenterX, mapCenterZ, radiusInTerrainUnits))
|
||||
{
|
||||
CFixedVector3D position = cmpPosition->GetPosition();
|
||||
|
||||
m_NewPositions.emplace_back(entityId, position + offset);
|
||||
m_OldPositions.emplace_back(entityId, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeletedObject deleted;
|
||||
deleted.entityId = entityId;
|
||||
deleted.templateName = cmpTemplateManager->GetCurrentTemplateName(entityId);
|
||||
|
||||
// If the entity has a position, but the ending position is not valid;
|
||||
if (cmpPosition)
|
||||
{
|
||||
deleted.pos = cmpPosition->GetPosition();
|
||||
deleted.rot = cmpPosition->GetRotation();
|
||||
}
|
||||
|
||||
CmpPtr<ICmpOwnership> cmpOwnership(sim, entityId);
|
||||
if (cmpOwnership)
|
||||
deleted.owner = cmpOwnership->GetOwner();
|
||||
|
||||
CmpPtr<ICmpVisual> cmpVisual(sim, deleted.entityId);
|
||||
if (cmpVisual)
|
||||
deleted.actorSeed = cmpVisual->GetActorSeed();
|
||||
|
||||
m_DeletedObjects.push_back(deleted);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteObjects(m_DeletedObjects);
|
||||
ResizeTerrain(m_NewPatches, m_OffsetX, m_OffsetY);
|
||||
SetMovedEntitiesPosition(m_NewPositions);
|
||||
MakeDirty();
|
||||
}
|
||||
|
||||
void Undo()
|
||||
{
|
||||
ResizeTerrain(m_OldTiles);
|
||||
if (m_Heightmap == nullptr || m_Patches == nullptr)
|
||||
{
|
||||
// If there previously was no data, just resize to old (probably not originally valid).
|
||||
ResizeTerrain(m_OldPatches, -m_OffsetX, -m_OffsetY);
|
||||
}
|
||||
else
|
||||
{
|
||||
CSimulation2& sim = *g_Game->GetSimulation2();
|
||||
CmpPtr<ICmpTerrain> cmpTerrain(sim, SYSTEM_ENTITY);
|
||||
CTerrain* terrain = cmpTerrain->GetCTerrain();
|
||||
|
||||
terrain->Initialize(m_OldPatches, m_Heightmap);
|
||||
// Copy terrain data back.
|
||||
for (ssize_t j = 0; j < m_OldPatches; ++j)
|
||||
for (ssize_t i = 0; i < m_OldPatches; ++i)
|
||||
{
|
||||
CPatch& src = m_Patches[j * m_OldPatches + i];
|
||||
CPatch& dst = *(terrain->GetPatch(i, j));
|
||||
std::copy_n(&src.m_MiniPatches[0][0], PATCH_SIZE * PATCH_SIZE, &dst.m_MiniPatches[0][0]);
|
||||
}
|
||||
}
|
||||
RestoreObjects(m_DeletedObjects);
|
||||
SetMovedEntitiesPosition(m_OldPositions);
|
||||
MakeDirty();
|
||||
}
|
||||
|
||||
void Redo()
|
||||
{
|
||||
ResizeTerrain(m_NewTiles);
|
||||
DeleteObjects(m_DeletedObjects);
|
||||
ResizeTerrain(m_NewPatches, m_OffsetX, m_OffsetY);
|
||||
SetMovedEntitiesPosition(m_NewPositions);
|
||||
MakeDirty();
|
||||
}
|
||||
};
|
||||
END_COMMAND(ResizeMap)
|
||||
|
@ -195,6 +195,17 @@ QUERY(GetMapSizes,
|
||||
((std::string, sizes))
|
||||
);
|
||||
|
||||
QUERY(GetCurrentMapSize,
|
||||
,
|
||||
((int, size))
|
||||
);
|
||||
|
||||
QUERY(RasterizeMinimap,
|
||||
,
|
||||
((int, dimension))
|
||||
((std::vector<uint8_t>, imageBytes))
|
||||
);
|
||||
|
||||
QUERY(GetRMSData,
|
||||
,
|
||||
((std::vector<std::string>, data))
|
||||
@ -202,6 +213,8 @@ QUERY(GetRMSData,
|
||||
|
||||
COMMAND(ResizeMap, NOMERGE,
|
||||
((int, tiles))
|
||||
((int, offsetX))
|
||||
((int, offsetY))
|
||||
);
|
||||
|
||||
QUERY(VFSFileExists,
|
||||
|
Loading…
Reference in New Issue
Block a user