1
0
forked from 0ad/0ad

Atlas: improved brushes

This was SVN commit r2875.
This commit is contained in:
Ykkrosh 2005-10-09 03:26:16 +00:00
parent 7fc8713794
commit 7ebdefec4b
17 changed files with 190 additions and 64 deletions

View File

@ -5,21 +5,21 @@
<variant frequency="10" name="House A">
<mesh>structural/celt_ho_1.pmd</mesh>
<props>
<item actor="props/celts/celt_house1_prop.xml" attachpoint="PropCandyA"/>
<prop actor="props/celts/celt_house1_prop.xml" attachpoint="PropCandyA"/>
</props>
<texture>structural/celt_struct_1.dds</texture>
</variant>
<variant frequency="10" name="House B">
<mesh>structural/celt_ho_2.pmd</mesh>
<props>
<item actor="props/celts/celt_house2_prop.xml" attachpoint="PropCandyA"/>
<prop actor="props/celts/celt_house2_prop.xml" attachpoint="PropCandyA"/>
</props>
<texture>structural/celt_struct_1.dds</texture>
</variant>
<variant frequency="10" name="House C">
<mesh>structural/celt_ho_3.pmd</mesh>
<props>
<item actor="props/celts/celt_house3_prop.xml" attachpoint="PropCandyA"/>
<prop actor="props/celts/celt_house3_prop.xml" attachpoint="PropCandyA"/>
</props>
<texture>structural/celt_struct_1.dds</texture>
</variant>

View File

@ -5,28 +5,28 @@
<variant frequency="10" name="House A">
<mesh>structural/pers_ho_a.pmd</mesh>
<props>
<item actor="props/persians/pers_ho_a.xml" attachpoint="props_main"/>
<prop actor="props/persians/pers_ho_a.xml" attachpoint="props_main"/>
</props>
<texture>structural/pers_struct_a.dds</texture>
</variant>
<variant frequency="10" name="House B">
<mesh>structural/pers_ho_b.pmd</mesh>
<props>
<item actor="props/persians/pers_ho_b.xml" attachpoint="props_main"/>
<prop actor="props/persians/pers_ho_b.xml" attachpoint="props_main"/>
</props>
<texture>structural/pers_struct_a.dds</texture>
</variant>
<variant frequency="10" name="House C">
<mesh>structural/pers_ho_c.pmd</mesh>
<props>
<item actor="props/persians/pers_ho_c.xml" attachpoint="props_main"/>
<prop actor="props/persians/pers_ho_c.xml" attachpoint="props_main"/>
</props>
<texture>structural/pers_struct_a.dds</texture>
</variant>
<variant frequency="10" name="House D">
<mesh>structural/pers_ho_d.pmd</mesh>
<props>
<item actor="props/persians/pers_ho_d.xml" attachpoint="props_main"/>
<prop actor="props/persians/pers_ho_d.xml" attachpoint="props_main"/>
</props>
<texture>structural/pers_struct_a.dds</texture>
</variant>

View File

@ -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();

View File

@ -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)

View File

@ -16,6 +16,7 @@ public:
void OnRedo(wxCommandEvent& event);
void OnWireframe(wxCommandEvent& event);
void OnMessageTrace(wxCommandEvent& event);
static AtlasWindowCommandProc& GetCommandProc();

View File

@ -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;

View File

@ -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()));
}

View File

@ -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;
};

View File

@ -37,6 +37,10 @@ void (*Atlas_NotifyEndOfFrame)();
static MessagePasserImpl<mCommand> msgPasser_Command;
static MessagePasserImpl<mInput> msgPasser_Input;
MessagePasser<mCommand>* AtlasMessage::g_MessagePasser_Command = &msgPasser_Command;
MessagePasser<mInput>* AtlasMessage::g_MessagePasser_Input = &msgPasser_Input;
static InputProcessor g_Input;
static GameLoopState state;

View File

@ -6,7 +6,7 @@
namespace AtlasMessage {
MESSAGEHANDLER(SetBrush)
MESSAGEHANDLER(Brush)
{
g_CurrentBrush.SetData(msg->width, msg->height, msg->data);
}

View File

@ -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)
{

View File

@ -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();

View File

@ -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<typename T> MessagePasserImpl<T>::MessagePasserImpl()
: m_Trace(false)
{
}
template<typename T> void MessagePasserImpl<T>::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 <typename T> T* MessagePasserImpl<T>::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 <typename T> bool MessagePasserImpl<T>::IsEmpty()
return empty;
}
MessagePasser<mCommand>* g_MessagePasser_Command = NULL;
MessagePasser<mInput>* g_MessagePasser_Input = NULL;
template <typename T> void MessagePasserImpl<T>::SetTrace(bool t)
{
m_Trace = t;
}
// Explicit instantiation:
template MessagePasserImpl<mCommand>;

View File

@ -6,11 +6,15 @@
template <typename T> class MessagePasserImpl : public AtlasMessage::MessagePasser<T>
{
public:
MessagePasserImpl();
virtual void Add(T* msg);
virtual T* Retrieve();
virtual bool IsEmpty();
void SetTrace(bool t);
private:
CMutex m_Mutex;
std::queue<T*> m_Queue;
bool m_Trace;
};

View File

@ -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[]

View File

@ -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;
};
//////////////////////////////////////////////////////////////////////////

View File

@ -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)