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);
|
||||
|
||||
g_SelectedTexture = _T("grass1_spring");
|
||||
g_SelectedTexture.NotifyObservers();
|
||||
|
||||
SetOpenFilename(_T(""));
|
||||
|
||||
#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.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -45,7 +45,6 @@ private:
|
||||
TextureNotebook* m_Textures;
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
ID_Passability = 1,
|
||||
@ -60,6 +59,118 @@ static wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
|
||||
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) :
|
||||
Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
|
||||
{
|
||||
@ -84,7 +195,7 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
|
||||
wxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Texture tools"));
|
||||
wxSizer* gridSizer = new wxGridSizer(3);
|
||||
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")),
|
||||
_("Replace all of a terrain texture with a new one")), wxSizerFlags().Expand());
|
||||
gridSizer->Add(Tooltipped(new ToolButton(scenarioEditor.GetToolManager(), this, _("Fill"), _T("FillTerrain")),
|
||||
@ -97,6 +208,10 @@ TerrainSidebar::TerrainSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebar
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Brush settings
|
||||
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);
|
||||
m_MainSizer->Add(sizer, wxSizerFlags().Expand().Border(wxTOP, 10));
|
||||
}
|
||||
@ -145,6 +260,7 @@ void TerrainSidebar::OnFirstDisplay()
|
||||
m_PassabilityChoice->Append(passClasses[i].c_str());
|
||||
|
||||
static_cast<TerrainBottomBar*>(m_BottomBar)->LoadTerrain();
|
||||
m_TexturePreview->LoadPreview();
|
||||
}
|
||||
|
||||
void TerrainSidebar::OnPassabilityChoice(wxCommandEvent& evt)
|
||||
@ -245,7 +361,7 @@ public:
|
||||
AtlasMessage::qGetTerrainGroupPreviews qry((std::wstring)m_Name.wc_str(), imageWidth, imageHeight);
|
||||
qry.Post();
|
||||
|
||||
std::vector<AtlasMessage::sTerrainGroupPreview> previews = *qry.previews;
|
||||
std::vector<AtlasMessage::sTerrainTexturePreview> previews = *qry.previews;
|
||||
|
||||
bool allLoaded = true;
|
||||
|
||||
@ -254,15 +370,10 @@ public:
|
||||
if (!previews[i].loaded)
|
||||
allLoaded = false;
|
||||
|
||||
// Construct the wrapped-text label
|
||||
wxString name = previews[i].name.c_str();
|
||||
|
||||
// Add spaces into the displayed name so there are more wrapping opportunities
|
||||
wxString labelText = name;
|
||||
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);
|
||||
// Construct the wrapped-text label
|
||||
wxStaticText* label = new wxStaticText(m_ScrolledPanel, wxID_ANY, FormatTextureName(name), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
label->Wrap(imageWidth);
|
||||
|
||||
unsigned char* buf = (unsigned char*)(malloc(previews[i].imageData.GetSize()));
|
||||
@ -303,6 +414,7 @@ public:
|
||||
wxButton* button = wxDynamicCast(evt.GetEventObject(), wxButton);
|
||||
wxString name = static_cast<wxStringClientData*>(button->GetClientObject())->GetData();
|
||||
g_SelectedTexture = name;
|
||||
g_SelectedTexture.NotifyObservers();
|
||||
|
||||
if (m_LastTerrainSelection)
|
||||
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.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -17,6 +17,8 @@
|
||||
|
||||
#include "../Common/Sidebar.h"
|
||||
|
||||
class TexturePreviewPanel;
|
||||
|
||||
class TerrainSidebar : public Sidebar
|
||||
{
|
||||
public:
|
||||
@ -31,6 +33,8 @@ private:
|
||||
void OnResizeMap(wxCommandEvent& evt);
|
||||
|
||||
wxChoice* m_PassabilityChoice;
|
||||
TexturePreviewPanel* m_TexturePreview;
|
||||
|
||||
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.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -19,6 +19,6 @@
|
||||
|
||||
#include "MiscState.h"
|
||||
|
||||
wxString g_SelectedTexture = _T("grass1_spring");
|
||||
Observable<wxString> g_SelectedTexture;
|
||||
|
||||
Observable<std::vector<AtlasMessage::ObjectID> > g_SelectedObjects;
|
||||
|
@ -25,7 +25,7 @@ namespace AtlasMessage
|
||||
typedef unsigned int ObjectID;
|
||||
}
|
||||
|
||||
extern wxString g_SelectedTexture;
|
||||
extern Observable<wxString> g_SelectedTexture;
|
||||
|
||||
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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
// 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:
|
||||
PaintTerrain()
|
||||
{
|
||||
SetState(&Waiting);
|
||||
|
||||
m_EyedropperBrush.SetSquare(2);
|
||||
}
|
||||
|
||||
|
||||
@ -49,9 +57,21 @@ public:
|
||||
POST_MESSAGE(BrushPreview, (false, Position()));
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (evt.LeftDown())
|
||||
@ -135,6 +155,56 @@ public:
|
||||
int GetPriority() { return AtlasMessage::ePaintTerrainPriority::LOW; }
|
||||
}
|
||||
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>);
|
||||
|
@ -51,74 +51,81 @@ QUERYHANDLER(GetTerrainGroups)
|
||||
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);
|
||||
}
|
||||
|
||||
static sTerrainTexturePreview GetPreview(CTerrainTextureEntry* tex, int width, int height)
|
||||
{
|
||||
sTerrainTexturePreview preview;
|
||||
preview.name = tex->GetTag().FromUTF8();
|
||||
|
||||
std::vector<unsigned char> buf (width*height*3);
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// It's not good to shrink the entire texture to fit the small preview
|
||||
// window, since it's the fine details in the texture that are
|
||||
// interesting; so just go down one mipmap level, then crop a chunk
|
||||
// out of the middle.
|
||||
|
||||
// Read the size of the texture. (Usually loads the texture from
|
||||
// disk, which is slow.)
|
||||
tex->GetTexture()->Bind();
|
||||
int level = 1; // level 0 is the original size
|
||||
int w = std::max(1, (int)tex->GetTexture()->GetWidth() >> level);
|
||||
int h = std::max(1, (int)tex->GetTexture()->GetHeight() >> level);
|
||||
|
||||
if (w >= width && h >= height)
|
||||
{
|
||||
// Read the whole texture into a new buffer
|
||||
unsigned char* texdata = new unsigned char[w*h*3];
|
||||
glGetTexImage(GL_TEXTURE_2D, level, GL_RGB, GL_UNSIGNED_BYTE, texdata);
|
||||
|
||||
// Extract the middle section (as a representative preview),
|
||||
// and copy into buf
|
||||
unsigned char* texdata_ptr = texdata + (w*(h - height)/2 + (w - width)/2) * 3;
|
||||
unsigned char* buf_ptr = &buf[0];
|
||||
for (ssize_t y = 0; y < height; ++y)
|
||||
{
|
||||
memcpy(buf_ptr, texdata_ptr, width*3);
|
||||
buf_ptr += width*3;
|
||||
texdata_ptr += w*3;
|
||||
}
|
||||
|
||||
delete[] texdata;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Too small to preview, or glGetTexImage not supported (on GLES)
|
||||
// Just use a flat color instead
|
||||
u32 c = tex->GetBaseColor();
|
||||
for (ssize_t i = 0; i < width*height; ++i)
|
||||
{
|
||||
buf[i*3+0] = (c>>16) & 0xff;
|
||||
buf[i*3+1] = (c>>8) & 0xff;
|
||||
buf[i*3+2] = (c>>0) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
preview.loaded = tex->GetTexture()->IsLoaded();
|
||||
preview.imageWidth = width;
|
||||
preview.imageHeight = height;
|
||||
preview.imageData = buf;
|
||||
|
||||
return preview;
|
||||
}
|
||||
|
||||
QUERYHANDLER(GetTerrainGroupPreviews)
|
||||
{
|
||||
std::vector<sTerrainGroupPreview> previews;
|
||||
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(sTerrainGroupPreview());
|
||||
previews.back().name = (*it)->GetTag().FromUTF8();
|
||||
|
||||
std::vector<unsigned char> buf (msg->imageWidth*msg->imageHeight*3);
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
// It's not good to shrink the entire texture to fit the small preview
|
||||
// window, since it's the fine details in the texture that are
|
||||
// interesting; so just go down one mipmap level, then crop a chunk
|
||||
// out of the middle.
|
||||
|
||||
// Read the size of the texture. (Usually loads the texture from
|
||||
// disk, which is slow.)
|
||||
(*it)->GetTexture()->Bind();
|
||||
int level = 1; // level 0 is the original size
|
||||
int w = std::max(1, (int)(*it)->GetTexture()->GetWidth() >> level);
|
||||
int h = std::max(1, (int)(*it)->GetTexture()->GetHeight() >> level);
|
||||
|
||||
if (w >= msg->imageWidth && h >= msg->imageHeight)
|
||||
{
|
||||
// Read the whole texture into a new buffer
|
||||
unsigned char* texdata = new unsigned char[w*h*3];
|
||||
glGetTexImage(GL_TEXTURE_2D, level, GL_RGB, GL_UNSIGNED_BYTE, texdata);
|
||||
|
||||
// Extract the middle section (as a representative preview),
|
||||
// and copy into buf
|
||||
unsigned char* texdata_ptr = texdata + (w*(h - msg->imageHeight)/2 + (w - msg->imageWidth)/2) * 3;
|
||||
unsigned char* buf_ptr = &buf[0];
|
||||
for (ssize_t y = 0; y < msg->imageHeight; ++y)
|
||||
{
|
||||
memcpy(buf_ptr, texdata_ptr, msg->imageWidth*3);
|
||||
buf_ptr += msg->imageWidth*3;
|
||||
texdata_ptr += w*3;
|
||||
}
|
||||
|
||||
delete[] texdata;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Too small to preview, or glGetTexImage not supported (on GLES)
|
||||
// Just use a flat color instead
|
||||
u32 c = (*it)->GetBaseColor();
|
||||
for (ssize_t i = 0; i < msg->imageWidth*msg->imageHeight; ++i)
|
||||
{
|
||||
buf[i*3+0] = (c>>16) & 0xff;
|
||||
buf[i*3+1] = (c>>8) & 0xff;
|
||||
buf[i*3+2] = (c>>0) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
previews.back().loaded = (*it)->GetTexture()->IsLoaded();
|
||||
previews.back().imageWidth = msg->imageWidth;
|
||||
previews.back().imageHeight = msg->imageHeight;
|
||||
previews.back().imageData = buf;
|
||||
}
|
||||
previews.push_back(GetPreview(*it, msg->imageWidth, msg->imageHeight));
|
||||
}
|
||||
|
||||
// Sort the list alphabetically by name
|
||||
std::sort(previews.begin(), previews.end(), CompareTerrain);
|
||||
@ -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 {
|
||||
|
@ -260,7 +260,7 @@ QUERY(GetTerrainGroups,
|
||||
);
|
||||
|
||||
#ifndef MESSAGES_SKIP_STRUCTS
|
||||
struct sTerrainGroupPreview
|
||||
struct sTerrainTexturePreview
|
||||
{
|
||||
Shareable<std::wstring> name;
|
||||
Shareable<bool> loaded;
|
||||
@ -268,7 +268,7 @@ struct sTerrainGroupPreview
|
||||
Shareable<int> imageHeight;
|
||||
Shareable<std::vector<unsigned char> > imageData; // RGB*width*height
|
||||
};
|
||||
SHAREABLE_STRUCT(sTerrainGroupPreview);
|
||||
SHAREABLE_STRUCT(sTerrainTexturePreview);
|
||||
#endif
|
||||
|
||||
QUERY(GetTerrainGroupPreviews,
|
||||
@ -276,7 +276,7 @@ QUERY(GetTerrainGroupPreviews,
|
||||
((int, imageWidth))
|
||||
((int, imageHeight))
|
||||
,
|
||||
((std::vector<sTerrainGroupPreview>, previews))
|
||||
((std::vector<sTerrainTexturePreview>, previews))
|
||||
);
|
||||
|
||||
QUERY(GetTerrainPassabilityClasses,
|
||||
@ -284,6 +284,14 @@ QUERY(GetTerrainPassabilityClasses,
|
||||
((std::vector<std::wstring>, classNames))
|
||||
);
|
||||
|
||||
QUERY(GetTerrainTexturePreview,
|
||||
((std::wstring, name))
|
||||
((int, imageWidth))
|
||||
((int, imageHeight))
|
||||
,
|
||||
((sTerrainTexturePreview, preview))
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef MESSAGES_SKIP_STRUCTS
|
||||
@ -483,6 +491,12 @@ COMMAND(FillTerrain, NOMERGE,
|
||||
((std::wstring, texture))
|
||||
);
|
||||
|
||||
QUERY(GetTerrainTexture,
|
||||
((Position, pos))
|
||||
,
|
||||
((std::wstring, texture))
|
||||
);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
QUERY(PickObject,
|
||||
|
@ -118,7 +118,7 @@ SHAREABLE_PRIMITIVE(void*);
|
||||
// Shareable containers must have shareable contents - but it's easy to forget
|
||||
// to declare them, so make sure the errors are almost readable, like:
|
||||
// "use of undefined type 'REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE<T,__formal>
|
||||
// with [ T=AtlasMessage::sTerrainGroupPreview, __formal=false ]"
|
||||
// with [ T=AtlasMessage::sTerrainTexturePreview, __formal=false ]"
|
||||
//
|
||||
// (Implementation based on boost/static_assert)
|
||||
template <typename T, bool> struct REQUIRE_TYPE_TO_BE_SHAREABLE_FAILURE;
|
||||
|
Loading…
Reference in New Issue
Block a user