Adds eyedropper tool to Atlas terrain brush (Shift+Click to activate). Fixes #1122.
Adds preview box showing currently selected terrain. This was SVN commit r11528.
This commit is contained in:
parent
772b38e6be
commit
5cfeccea09
@ -373,6 +373,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
|
|||||||
|
|
||||||
// wxLog::SetTraceMask(wxTraceMessages);
|
// wxLog::SetTraceMask(wxTraceMessages);
|
||||||
|
|
||||||
|
g_SelectedTexture = _T("grass1_spring");
|
||||||
|
g_SelectedTexture.NotifyObservers();
|
||||||
|
|
||||||
SetOpenFilename(_T(""));
|
SetOpenFilename(_T(""));
|
||||||
|
|
||||||
#if defined(__WXMSW__)
|
#if defined(__WXMSW__)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2011 Wildfire Games.
|
/* Copyright (C) 2012 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@ -45,7 +45,6 @@ private:
|
|||||||
TextureNotebook* m_Textures;
|
TextureNotebook* m_Textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ID_Passability = 1,
|
ID_Passability = 1,
|
||||||
@ -60,6 +59,118 @@ static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
|
|||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add spaces into the displayed name so there are more wrapping opportunities
|
||||||
|
static wxString FormatTextureName(wxString name)
|
||||||
|
{
|
||||||
|
if (name.Len())
|
||||||
|
name[0] = wxToupper(name[0]);
|
||||||
|
name.Replace(_T("_"), _T(" "));
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class TexturePreviewPanel : public wxPanel
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const int imageWidth = 120;
|
||||||
|
static const int imageHeight = 40;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TexturePreviewPanel(wxWindow* parent)
|
||||||
|
: wxPanel(parent, wxID_ANY), m_Timer(this)
|
||||||
|
{
|
||||||
|
m_Conn = g_SelectedTexture.RegisterObserver(0, &TexturePreviewPanel::OnTerrainChange, this);
|
||||||
|
m_Sizer = new wxStaticBoxSizer(wxVERTICAL, this, _T("Texture"));
|
||||||
|
SetSizer(m_Sizer);
|
||||||
|
|
||||||
|
// Use placeholder bitmap for now
|
||||||
|
m_Sizer->Add(new wxStaticBitmap(this, wxID_ANY, wxNullBitmap), wxSizerFlags(1).Expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadPreview()
|
||||||
|
{
|
||||||
|
if (m_TextureName.IsEmpty())
|
||||||
|
{
|
||||||
|
// If we haven't got a texture yet, copy the global
|
||||||
|
m_TextureName = g_SelectedTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
Freeze();
|
||||||
|
|
||||||
|
m_Sizer->Clear(true);
|
||||||
|
|
||||||
|
AtlasMessage::qGetTerrainTexturePreview qry(m_TextureName.wc_str(), imageWidth, imageHeight);
|
||||||
|
qry.Post();
|
||||||
|
|
||||||
|
AtlasMessage::sTerrainTexturePreview preview = qry.preview;
|
||||||
|
|
||||||
|
// Check for invalid/missing texture - shouldn't happen
|
||||||
|
if (!wxString(qry.preview->name.c_str()).IsEmpty())
|
||||||
|
{
|
||||||
|
// Construct the wrapped-text label
|
||||||
|
wxStaticText* label = new wxStaticText(this, wxID_ANY, FormatTextureName(*qry.preview->name), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||||
|
label->Wrap(m_Sizer->GetSize().GetX());
|
||||||
|
|
||||||
|
unsigned char* buf = (unsigned char*)(malloc(preview.imageData.GetSize()));
|
||||||
|
// imagedata.GetBuffer() gives a Shareable<unsigned char>*, which
|
||||||
|
// is stored the same as a unsigned char*, so we can just copy it.
|
||||||
|
memcpy(buf, preview.imageData.GetBuffer(), preview.imageData.GetSize());
|
||||||
|
wxImage img(qry.preview->imageWidth, qry.preview->imageHeight, buf);
|
||||||
|
|
||||||
|
wxStaticBitmap* bitmap = new wxStaticBitmap(this, wxID_ANY, wxBitmap(img), wxDefaultPosition, wxSize(qry.preview->imageWidth, qry.preview->imageHeight), wxBORDER_SIMPLE);
|
||||||
|
m_Sizer->Add(bitmap, wxSizerFlags(1).Align(wxALIGN_CENTRE));
|
||||||
|
m_Sizer->Add(label, wxSizerFlags().Expand());
|
||||||
|
|
||||||
|
// We have to force the sidebar to layout manually
|
||||||
|
GetParent()->Layout();
|
||||||
|
|
||||||
|
if (preview.loaded && m_Timer.IsRunning())
|
||||||
|
{
|
||||||
|
m_Timer.Stop();
|
||||||
|
}
|
||||||
|
else if (!preview.loaded && !m_Timer.IsRunning())
|
||||||
|
{
|
||||||
|
m_Timer.Start(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Thaw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTerrainChange(const wxString& texture)
|
||||||
|
{
|
||||||
|
// Check if texture really changed, to avoid doing this too often
|
||||||
|
if (texture != m_TextureName)
|
||||||
|
{
|
||||||
|
// Load new texture preview
|
||||||
|
m_TextureName = texture;
|
||||||
|
LoadPreview();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTimer(wxTimerEvent& WXUNUSED(evt))
|
||||||
|
{
|
||||||
|
LoadPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ObservableScopedConnection m_Conn;
|
||||||
|
wxSizer* m_Sizer;
|
||||||
|
wxTimer m_Timer;
|
||||||
|
wxString m_TextureName;
|
||||||
|
|
||||||
|
DECLARE_EVENT_TABLE();
|
||||||
|
};
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(TexturePreviewPanel, wxPanel)
|
||||||
|
EVT_TIMER(wxID_ANY, TexturePreviewPanel::OnTimer)
|
||||||
|
END_EVENT_TABLE();
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) :
|
TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) :
|
||||||
Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
|
Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
|
||||||
{
|
{
|
||||||
@ -84,7 +195,7 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
|
|||||||
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Texture tools"));
|
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Texture tools"));
|
||||||
wxSizer* gridSizer = new wxGridSizer(3);
|
wxSizer* gridSizer = new wxGridSizer(3);
|
||||||
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Paint"), _T("PaintTerrain")),
|
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Paint"), _T("PaintTerrain")),
|
||||||
_("Brush with left mouse button to paint texture dominantly,\nright mouse button to paint submissively")), wxSizerFlags().Expand());
|
_("Brush with left mouse button to paint texture dominantly,\nright mouse button to paint submissively.\nShift-left-click for eyedropper tool")), wxSizerFlags().Expand());
|
||||||
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Replace"), _T("ReplaceTerrain")),
|
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Replace"), _T("ReplaceTerrain")),
|
||||||
_("Replace all of a terrain texture with a new one")), wxSizerFlags().Expand());
|
_("Replace all of a terrain texture with a new one")), wxSizerFlags().Expand());
|
||||||
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Fill"), _T("FillTerrain")),
|
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Fill"), _T("FillTerrain")),
|
||||||
@ -97,6 +208,10 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
|
|||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
// Brush settings
|
// Brush settings
|
||||||
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Brush"));
|
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Brush"));
|
||||||
|
|
||||||
|
m_TexturePreview = new TexturePreviewPanel(this);
|
||||||
|
sizer->Add(m_TexturePreview, wxSizerFlags(1).Expand());
|
||||||
|
|
||||||
g_Brush_Elevation.CreateUI(this, sizer);
|
g_Brush_Elevation.CreateUI(this, sizer);
|
||||||
m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 10));
|
m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 10));
|
||||||
}
|
}
|
||||||
@ -145,6 +260,7 @@ void TerrainSidebar::OnFirstDisplay()
|
|||||||
m_PassabilityChoice->Append(passClasses[i].c_str());
|
m_PassabilityChoice->Append(passClasses[i].c_str());
|
||||||
|
|
||||||
static_cast<TerrainBottomBar*>(m_BottomBar)->LoadTerrain();
|
static_cast<TerrainBottomBar*>(m_BottomBar)->LoadTerrain();
|
||||||
|
m_TexturePreview->LoadPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerrainSidebar::OnPassabilityChoice(wxCommandEvent& evt)
|
void TerrainSidebar::OnPassabilityChoice(wxCommandEvent& evt)
|
||||||
@ -245,7 +361,7 @@ public:
|
|||||||
AtlasMessage::qGetTerrainGroupPreviews qry((std::wstring)m_Name.wc_str(), imageWidth, imageHeight);
|
AtlasMessage::qGetTerrainGroupPreviews qry((std::wstring)m_Name.wc_str(), imageWidth, imageHeight);
|
||||||
qry.Post();
|
qry.Post();
|
||||||
|
|
||||||
std::vector<AtlasMessage::sTerrainGroupPreview> previews = *qry.previews;
|
std::vector<AtlasMessage::sTerrainTexturePreview> previews = *qry.previews;
|
||||||
|
|
||||||
bool allLoaded = true;
|
bool allLoaded = true;
|
||||||
|
|
||||||
@ -254,15 +370,10 @@ public:
|
|||||||
if (!previews[i].loaded)
|
if (!previews[i].loaded)
|
||||||
allLoaded = false;
|
allLoaded = false;
|
||||||
|
|
||||||
// Construct the wrapped-text label
|
|
||||||
wxString name = previews[i].name.c_str();
|
wxString name = previews[i].name.c_str();
|
||||||
|
|
||||||
// Add spaces into the displayed name so there are more wrapping opportunities
|
// Construct the wrapped-text label
|
||||||
wxString labelText = name;
|
wxStaticText* label = new wxStaticText(m_ScrolledPanel, wxID_ANY, FormatTextureName(name), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||||
if (labelText.Len())
|
|
||||||
labelText[0] = wxToupper(labelText[0]);
|
|
||||||
labelText.Replace(_T("_"), _T(" "));
|
|
||||||
wxStaticText* label = new wxStaticText(m_ScrolledPanel, wxID_ANY, labelText, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
|
||||||
label->Wrap(imageWidth);
|
label->Wrap(imageWidth);
|
||||||
|
|
||||||
unsigned char* buf = (unsigned char*)(malloc(previews[i].imageData.GetSize()));
|
unsigned char* buf = (unsigned char*)(malloc(previews[i].imageData.GetSize()));
|
||||||
@ -303,6 +414,7 @@ public:
|
|||||||
wxButton* button = wxDynamicCast(evt.GetEventObject(), wxButton);
|
wxButton* button = wxDynamicCast(evt.GetEventObject(), wxButton);
|
||||||
wxString name = static_cast<wxStringClientData*>(button->GetClientObject())->GetData();
|
wxString name = static_cast<wxStringClientData*>(button->GetClientObject())->GetData();
|
||||||
g_SelectedTexture = name;
|
g_SelectedTexture = name;
|
||||||
|
g_SelectedTexture.NotifyObservers();
|
||||||
|
|
||||||
if (m_LastTerrainSelection)
|
if (m_LastTerrainSelection)
|
||||||
m_LastTerrainSelection->SetBackgroundColour(wxNullColour);
|
m_LastTerrainSelection->SetBackgroundColour(wxNullColour);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2011 Wildfire Games.
|
/* Copyright (C) 2012 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include "../Common/Sidebar.h"
|
#include "../Common/Sidebar.h"
|
||||||
|
|
||||||
|
class TexturePreviewPanel;
|
||||||
|
|
||||||
class TerrainSidebar : public Sidebar
|
class TerrainSidebar : public Sidebar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -31,6 +33,8 @@ private:
|
|||||||
void OnResizeMap(wxCommandEvent& evt);
|
void OnResizeMap(wxCommandEvent& evt);
|
||||||
|
|
||||||
wxChoice* m_PassabilityChoice;
|
wxChoice* m_PassabilityChoice;
|
||||||
|
TexturePreviewPanel* m_TexturePreview;
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE();
|
DECLARE_EVENT_TABLE();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2012 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@ -19,6 +19,6 @@
|
|||||||
|
|
||||||
#include "MiscState.h"
|
#include "MiscState.h"
|
||||||
|
|
||||||
wxString g_SelectedTexture = _T("grass1_spring");
|
Observable<wxString> g_SelectedTexture;
|
||||||
|
|
||||||
Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
|
Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
|
||||||
|
@ -25,7 +25,7 @@ namespace AtlasMessage
|
|||||||
typedef unsigned int ObjectID;
|
typedef unsigned int ObjectID;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern wxString g_SelectedTexture;
|
extern Observable<wxString> g_SelectedTexture;
|
||||||
|
|
||||||
extern Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
|
extern Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
/* Copyright (C) 2012 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@ -31,10 +31,18 @@ class PaintTerrain : public StateDrivenTool<PaintTerrain>
|
|||||||
|
|
||||||
Position m_Pos;
|
Position m_Pos;
|
||||||
|
|
||||||
|
// Brush for eyedropper preview
|
||||||
|
// (it's confusing if we use the arbitrarily sized paint brush)
|
||||||
|
Brush m_EyedropperBrush;
|
||||||
|
|
||||||
|
static const wxKeyCode EYEDROPPER_HOTKEY = WXK_SHIFT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PaintTerrain()
|
PaintTerrain()
|
||||||
{
|
{
|
||||||
SetState(&Waiting);
|
SetState(&Waiting);
|
||||||
|
|
||||||
|
m_EyedropperBrush.SetSquare(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -49,9 +57,21 @@ public:
|
|||||||
POST_MESSAGE(BrushPreview, (false, Position()));
|
POST_MESSAGE(BrushPreview, (false, Position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct sWaiting : public State
|
struct sWaiting : public State
|
||||||
{
|
{
|
||||||
|
bool OnKey(PaintTerrain* obj, wxKeyEvent& evt, KeyEventType type)
|
||||||
|
{
|
||||||
|
if (type == KEY_DOWN && evt.GetKeyCode() == EYEDROPPER_HOTKEY)
|
||||||
|
{
|
||||||
|
SET_STATE(Eyedropper);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool OnMouse(PaintTerrain* obj, wxMouseEvent& evt)
|
bool OnMouse(PaintTerrain* obj, wxMouseEvent& evt)
|
||||||
{
|
{
|
||||||
if (evt.LeftDown())
|
if (evt.LeftDown())
|
||||||
@ -135,6 +155,56 @@ public:
|
|||||||
int GetPriority() { return AtlasMessage::ePaintTerrainPriority::LOW; }
|
int GetPriority() { return AtlasMessage::ePaintTerrainPriority::LOW; }
|
||||||
}
|
}
|
||||||
PaintingLow;
|
PaintingLow;
|
||||||
|
|
||||||
|
struct sEyedropper : public State
|
||||||
|
{
|
||||||
|
void OnEnter(PaintTerrain* obj)
|
||||||
|
{
|
||||||
|
obj->m_EyedropperBrush.MakeActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnLeave(PaintTerrain* WXUNUSED(obj))
|
||||||
|
{
|
||||||
|
g_Brush_Elevation.MakeActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnKey(PaintTerrain* obj, wxKeyEvent& evt, KeyEventType type)
|
||||||
|
{
|
||||||
|
if (type == KEY_UP && evt.GetKeyCode() == EYEDROPPER_HOTKEY)
|
||||||
|
{
|
||||||
|
SET_STATE(Waiting);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnMouse(PaintTerrain* WXUNUSED(obj), wxMouseEvent& evt)
|
||||||
|
{
|
||||||
|
if (evt.ButtonDown() || evt.Dragging())
|
||||||
|
{
|
||||||
|
POST_MESSAGE(BrushPreview, (true, evt.GetPosition()));
|
||||||
|
AtlasMessage::qGetTerrainTexture qry(evt.GetPosition());
|
||||||
|
qry.Post();
|
||||||
|
|
||||||
|
g_SelectedTexture = wxString(qry.texture.c_str());
|
||||||
|
g_SelectedTexture.NotifyObservers();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (evt.Moving())
|
||||||
|
{
|
||||||
|
POST_MESSAGE(BrushPreview, (true, Position(evt.GetPosition())));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Eyedropper;
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(PaintTerrain, StateDrivenTool<PaintTerrain>);
|
IMPLEMENT_DYNAMIC_CLASS(PaintTerrain, StateDrivenTool<PaintTerrain>);
|
||||||
|
@ -51,22 +51,17 @@ QUERYHANDLER(GetTerrainGroups)
|
|||||||
msg->groupNames = groupNames;
|
msg->groupNames = groupNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CompareTerrain(const sTerrainGroupPreview& a, const sTerrainGroupPreview& b)
|
static bool CompareTerrain(const sTerrainTexturePreview& a, const sTerrainTexturePreview& b)
|
||||||
{
|
{
|
||||||
return (wcscmp(a.name.c_str(), b.name.c_str()) < 0);
|
return (wcscmp(a.name.c_str(), b.name.c_str()) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUERYHANDLER(GetTerrainGroupPreviews)
|
static sTerrainTexturePreview GetPreview(CTerrainTextureEntry* tex, int width, int height)
|
||||||
{
|
{
|
||||||
std::vector<sTerrainGroupPreview> previews;
|
sTerrainTexturePreview preview;
|
||||||
|
preview.name = tex->GetTag().FromUTF8();
|
||||||
|
|
||||||
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupName).ToUTF8());
|
std::vector<unsigned char> buf (width*height*3);
|
||||||
for (std::vector<CTerrainTextureEntry*>::const_iterator it = group->GetTerrains().begin(); it != group->GetTerrains().end(); ++it)
|
|
||||||
{
|
|
||||||
previews.push_back(sTerrainGroupPreview());
|
|
||||||
previews.back().name = (*it)->GetTag().FromUTF8();
|
|
||||||
|
|
||||||
std::vector<unsigned char> buf (msg->imageWidth*msg->imageHeight*3);
|
|
||||||
|
|
||||||
#if !CONFIG2_GLES
|
#if !CONFIG2_GLES
|
||||||
// It's not good to shrink the entire texture to fit the small preview
|
// It's not good to shrink the entire texture to fit the small preview
|
||||||
@ -76,12 +71,12 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
|||||||
|
|
||||||
// Read the size of the texture. (Usually loads the texture from
|
// Read the size of the texture. (Usually loads the texture from
|
||||||
// disk, which is slow.)
|
// disk, which is slow.)
|
||||||
(*it)->GetTexture()->Bind();
|
tex->GetTexture()->Bind();
|
||||||
int level = 1; // level 0 is the original size
|
int level = 1; // level 0 is the original size
|
||||||
int w = std::max(1, (int)(*it)->GetTexture()->GetWidth() >> level);
|
int w = std::max(1, (int)tex->GetTexture()->GetWidth() >> level);
|
||||||
int h = std::max(1, (int)(*it)->GetTexture()->GetHeight() >> level);
|
int h = std::max(1, (int)tex->GetTexture()->GetHeight() >> level);
|
||||||
|
|
||||||
if (w >= msg->imageWidth && h >= msg->imageHeight)
|
if (w >= width && h >= height)
|
||||||
{
|
{
|
||||||
// Read the whole texture into a new buffer
|
// Read the whole texture into a new buffer
|
||||||
unsigned char* texdata = new unsigned char[w*h*3];
|
unsigned char* texdata = new unsigned char[w*h*3];
|
||||||
@ -89,12 +84,12 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
|||||||
|
|
||||||
// Extract the middle section (as a representative preview),
|
// Extract the middle section (as a representative preview),
|
||||||
// and copy into buf
|
// and copy into buf
|
||||||
unsigned char* texdata_ptr = texdata + (w*(h - msg->imageHeight)/2 + (w - msg->imageWidth)/2) * 3;
|
unsigned char* texdata_ptr = texdata + (w*(h - height)/2 + (w - width)/2) * 3;
|
||||||
unsigned char* buf_ptr = &buf[0];
|
unsigned char* buf_ptr = &buf[0];
|
||||||
for (ssize_t y = 0; y < msg->imageHeight; ++y)
|
for (ssize_t y = 0; y < height; ++y)
|
||||||
{
|
{
|
||||||
memcpy(buf_ptr, texdata_ptr, msg->imageWidth*3);
|
memcpy(buf_ptr, texdata_ptr, width*3);
|
||||||
buf_ptr += msg->imageWidth*3;
|
buf_ptr += width*3;
|
||||||
texdata_ptr += w*3;
|
texdata_ptr += w*3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +100,8 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
|||||||
{
|
{
|
||||||
// Too small to preview, or glGetTexImage not supported (on GLES)
|
// Too small to preview, or glGetTexImage not supported (on GLES)
|
||||||
// Just use a flat color instead
|
// Just use a flat color instead
|
||||||
u32 c = (*it)->GetBaseColor();
|
u32 c = tex->GetBaseColor();
|
||||||
for (ssize_t i = 0; i < msg->imageWidth*msg->imageHeight; ++i)
|
for (ssize_t i = 0; i < width*height; ++i)
|
||||||
{
|
{
|
||||||
buf[i*3+0] = (c>>16) & 0xff;
|
buf[i*3+0] = (c>>16) & 0xff;
|
||||||
buf[i*3+1] = (c>>8) & 0xff;
|
buf[i*3+1] = (c>>8) & 0xff;
|
||||||
@ -114,10 +109,22 @@ QUERYHANDLER(GetTerrainGroupPreviews)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
previews.back().loaded = (*it)->GetTexture()->IsLoaded();
|
preview.loaded = tex->GetTexture()->IsLoaded();
|
||||||
previews.back().imageWidth = msg->imageWidth;
|
preview.imageWidth = width;
|
||||||
previews.back().imageHeight = msg->imageHeight;
|
preview.imageHeight = height;
|
||||||
previews.back().imageData = buf;
|
preview.imageData = buf;
|
||||||
|
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUERYHANDLER(GetTerrainGroupPreviews)
|
||||||
|
{
|
||||||
|
std::vector<sTerrainTexturePreview> previews;
|
||||||
|
|
||||||
|
CTerrainGroup* group = g_TexMan.FindGroup(CStrW(*msg->groupName).ToUTF8());
|
||||||
|
for (std::vector<CTerrainTextureEntry*>::const_iterator it = group->GetTerrains().begin(); it != group->GetTerrains().end(); ++it)
|
||||||
|
{
|
||||||
|
previews.push_back(GetPreview(*it, msg->imageWidth, msg->imageHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort the list alphabetically by name
|
// Sort the list alphabetically by name
|
||||||
@ -139,6 +146,42 @@ QUERYHANDLER(GetTerrainPassabilityClasses)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUERYHANDLER(GetTerrainTexture)
|
||||||
|
{
|
||||||
|
ssize_t x, y;
|
||||||
|
g_CurrentBrush.m_Centre = msg->pos->GetWorldSpace();
|
||||||
|
g_CurrentBrush.GetCentre(x, y);
|
||||||
|
|
||||||
|
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||||
|
CMiniPatch* tile = terrain->GetTile(x, y);
|
||||||
|
if (tile)
|
||||||
|
{
|
||||||
|
CTerrainTextureEntry* tex = tile->GetTextureEntry();
|
||||||
|
msg->texture = tex->GetTag().FromUTF8();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg->texture = std::wstring();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QUERYHANDLER(GetTerrainTexturePreview)
|
||||||
|
{
|
||||||
|
CTerrainTextureEntry* tex = g_TexMan.FindTexture(CStrW(*msg->name).ToUTF8());
|
||||||
|
if (tex)
|
||||||
|
{
|
||||||
|
msg->preview = GetPreview(tex, msg->imageWidth, msg->imageHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sTerrainTexturePreview noPreview;
|
||||||
|
noPreview.name = std::wstring();
|
||||||
|
noPreview.imageHeight = 0;
|
||||||
|
noPreview.imageWidth = 0;
|
||||||
|
msg->preview = noPreview;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -260,7 +260,7 @@ QUERY(GetTerrainGroups,
|
|||||||
);
|
);
|
||||||
|
|
||||||
#ifndef MESSAGES_SKIP_STRUCTS
|
#ifndef MESSAGES_SKIP_STRUCTS
|
||||||
struct sTerrainGroupPreview
|
struct sTerrainTexturePreview
|
||||||
{
|
{
|
||||||
Shareable<std::wstring> name;
|
Shareable<std::wstring> name;
|
||||||
Shareable<bool> loaded;
|
Shareable<bool> loaded;
|
||||||
@ -268,7 +268,7 @@ struct sTerrainGroupPreview
|
|||||||
Shareable<int> imageHeight;
|
Shareable<int> imageHeight;
|
||||||
Shareable<std::vector<unsigned char> > imageData; // RGB*width*height
|
Shareable<std::vector<unsigned char> > imageData; // RGB*width*height
|
||||||
};
|
};
|
||||||
SHAREABLE_STRUCT(sTerrainGroupPreview);
|
SHAREABLE_STRUCT(sTerrainTexturePreview);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QUERY(GetTerrainGroupPreviews,
|
QUERY(GetTerrainGroupPreviews,
|
||||||
@ -276,7 +276,7 @@ QUERY(GetTerrainGroupPreviews,
|
|||||||
((int, imageWidth))
|
((int, imageWidth))
|
||||||
((int, imageHeight))
|
((int, imageHeight))
|
||||||
,
|
,
|
||||||
((std::vector<sTerrainGroupPreview>, previews))
|
((std::vector<sTerrainTexturePreview>, previews))
|
||||||
);
|
);
|
||||||
|
|
||||||
QUERY(GetTerrainPassabilityClasses,
|
QUERY(GetTerrainPassabilityClasses,
|
||||||
@ -284,6 +284,14 @@ QUERY(GetTerrainPassabilityClasses,
|
|||||||
((std::vector<std::wstring>, classNames))
|
((std::vector<std::wstring>, classNames))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QUERY(GetTerrainTexturePreview,
|
||||||
|
((std::wstring, name))
|
||||||
|
((int, imageWidth))
|
||||||
|
((int, imageHeight))
|
||||||
|
,
|
||||||
|
((sTerrainTexturePreview, preview))
|
||||||
|
);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef MESSAGES_SKIP_STRUCTS
|
#ifndef MESSAGES_SKIP_STRUCTS
|
||||||
@ -483,6 +491,12 @@ COMMAND(FillTerrain, NOMERGE,
|
|||||||
((std::wstring, texture))
|
((std::wstring, texture))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QUERY(GetTerrainTexture,
|
||||||
|
((Position, pos))
|
||||||
|
,
|
||||||
|
((std::wstring, texture))
|
||||||
|
);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
QUERY(PickObject,
|
QUERY(PickObject,
|
||||||
|
@ -118,7 +118,7 @@ SHAREABLE_PRIMITIVE(void*);
|
|||||||
// Shareable containers must have shareable contents - but it's easy to forget
|
// Shareable containers must have shareable contents - but it's easy to forget
|
||||||
// to declare them, so make sure the errors are almost readable, like:
|
// to declare them, so make sure the errors are almost readable, like:
|
||||||
// "use of undefined type 'REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE<T,__formal>
|
// "use of undefined type 'REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE<T,__formal>
|
||||||
// with [ T=AtlasMessage::sTerrainGroupPreview, __formal=false ]"
|
// with [ T=AtlasMessage::sTerrainTexturePreview, __formal=false ]"
|
||||||
//
|
//
|
||||||
// (Implementation based on boost/static_assert)
|
// (Implementation based on boost/static_assert)
|
||||||
template <typename T, bool> struct REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE;
|
template <typename T, bool> struct REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE;
|
||||||
|
Loading…
Reference in New Issue
Block a user