1
1
forked from 0ad/0ad

# Improved actor-viewer tool (more viewing controls, support for random actor variations)

Also right-click-and-drag to rotate the camera vertically.
Fixed LookAt code (the algorithm in the gluLookAt man page seems to be
wrong).

This was SVN commit r4394.
This commit is contained in:
Ykkrosh 2006-09-27 16:54:23 +00:00
parent 2f53eea71a
commit b6c1022566
20 changed files with 291 additions and 204 deletions

View File

@ -405,6 +405,23 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once, float speed, CSkeleton
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CopyAnimation
void CModel::CopyAnimationFrom(CModel* source)
{
m_Anim = source->m_Anim;
m_NextAnim = source->m_NextAnim;
m_AnimTime = source->m_AnimTime;
m_AnimSpeed = source->m_AnimSpeed;
m_Flags &= ~MODELFLAG_CASTSHADOWS;
if (source->m_Flags & MODELFLAG_CASTSHADOWS)
m_Flags |= MODELFLAG_CASTSHADOWS;
m_ObjectBounds.SetEmpty();
InvalidateBounds();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AddProp: add a prop to the model on the given point
void CModel::AddProp(SPropPoint* point, CModel* model, CObjectEntry* objectentry)

View File

@ -78,6 +78,10 @@ public:
// get the currently playing animation, if any
CSkeletonAnim* GetAnimation() { return m_Anim; }
// set the animation state to be the same as from another; both models should
// be compatible types (same type of skeleton)
void CopyAnimationFrom(CModel* source);
// set object flags
void SetFlags(u32 flags) { m_Flags=flags; }
// get object flags

View File

@ -172,14 +172,14 @@ void CUnit::ReloadObject()
CObjectEntry* newObject = g_ObjMan.FindObjectVariation(m_Object->m_Base, selections);
if (newObject != m_Object)
{
// Clone the base model (lacking instance-specific data)
// Clone the new object's base (non-instance) model
CModel* newModel = newObject->m_Model->Clone();
// Copy the old instance-specific settings to the new model
// Copy the old instance-specific settings from the old model to the new instance
newModel->SetTransform(m_Model->GetTransform());
if (m_PlayerID != -1)
newModel->SetPlayerID(m_PlayerID);
// TODO: preserve selection of animation, anim offset, etc?
newModel->CopyAnimationFrom(m_Model);
delete m_Model;
m_Model = newModel;

View File

@ -9,6 +9,7 @@
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "ScenarioEditor/Sections/Environment/LightControl.h"
#include "ScenarioEditor/Sections/Object/VariationControl.h"
#include "GameInterface/Messages.h"
@ -28,19 +29,25 @@ wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
return window;
}
//////////////////////////////////////////////////////////////////////////
class ActorCanvas : public Canvas
{
public:
ActorCanvas(wxWindow* parent, int* attribList)
: Canvas(parent, attribList, wxBORDER_SUNKEN),
m_Distance(20.f), m_Angle(0.f), m_LastIsValid(false)
m_Distance(20.f), m_Angle(0.f), m_Elevation(M_PI/6.f), m_LastIsValid(false)
{
}
void PostLookAt()
{
float offset = 0.3f; // slight fudge so we turn nicely when going over the top of the unit
POST_MESSAGE(LookAt, (eRenderView::ACTOR,
Position(m_Distance*sin(m_Angle), m_Distance/2.f, m_Distance*cos(m_Angle)),
Position(
m_Distance*cos(m_Elevation)*sin(m_Angle) + offset*cos(m_Angle),
m_Distance*sin(m_Elevation),
m_Distance*cos(m_Elevation)*cos(m_Angle) - offset*sin(m_Angle)),
Position(0, 0, 0)));
}
@ -58,13 +65,15 @@ protected:
camera_changed = true;
}
if (evt.ButtonDown(wxMOUSE_BTN_LEFT))
if (evt.ButtonDown(wxMOUSE_BTN_LEFT) || evt.ButtonDown(wxMOUSE_BTN_RIGHT))
{
m_LastX = evt.GetX();
m_LastY = evt.GetY();
m_LastIsValid = true;
}
else if (evt.Dragging() && evt.ButtonIsDown(wxMOUSE_BTN_LEFT) && m_LastIsValid)
else if (evt.Dragging()
&& (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
&& m_LastIsValid)
{
int dx = evt.GetX() - m_LastX;
int dy = evt.GetY() - m_LastY;
@ -72,16 +81,23 @@ protected:
m_LastY = evt.GetY();
m_Angle += dx * M_PI/256.f * ScenarioEditor::GetSpeedModifier();
m_Distance += dy / 8.f * ScenarioEditor::GetSpeedModifier();
if (evt.ButtonIsDown(wxMOUSE_BTN_LEFT))
m_Distance += dy / 8.f * ScenarioEditor::GetSpeedModifier();
else // evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
m_Elevation += dy * M_PI/256.f * ScenarioEditor::GetSpeedModifier();
camera_changed = true;
}
else if (evt.ButtonUp(wxMOUSE_BTN_ANY))
else if (evt.ButtonUp(wxMOUSE_BTN_ANY)
&& ! (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
)
{
// In some situations (e.g. double-clicking the title bar to
// maximise the window) we get a dragging event without the matching
// buttondown; so disallow dragging when there was a buttonup since
// buttondown; so disallow dragging when all buttons were released since
// the last buttondown.
// (TODO: does this affect the scenario editor too?)
// (TODO: does this problem affect the scenario editor too?)
m_LastIsValid = false;
}
@ -94,6 +110,7 @@ protected:
private:
float m_Distance;
float m_Angle;
float m_Elevation;
int m_LastX, m_LastY;
bool m_LastIsValid;
};
@ -142,7 +159,8 @@ static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
ActorViewer::ActorViewer(wxWindow* parent)
: wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)),
m_CurrentSpeed(0.f), m_Wireframe(false), m_BackgroundColour(wxColour(255, 255, 255)),
m_Walking(true)
m_Walking(true),
m_ObjectSettings(m_ObjectSelection, AtlasMessage::eRenderView::ACTOR)
{
SetIcon(wxIcon(_T("ICON_ActorEditor")));
@ -239,40 +257,48 @@ ActorViewer::ActorViewer(wxWindow* parent)
m_EnvironmentSettings.suncolour = Colour(255, 255, 255);
m_EnvironmentSettings.terraincolour = Colour(164, 164, 164);
m_EnvironmentSettings.unitcolour = Colour(164, 164, 164);
LightControl* lightControl = new LightControl(sidePanel, wxSize(100, 100), m_EnvironmentSettings);
LightControl* lightControl = new LightControl(sidePanel, wxSize(90, 90), m_EnvironmentSettings);
m_EnvConn = m_EnvironmentSettings.RegisterObserver(0, &SendToGame);
SendToGame(m_EnvironmentSettings);
wxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
wxSizer* bottomSizer = new wxBoxSizer(wxHORIZONTAL);
wxSizer* bottomLeftSizer = new wxBoxSizer(wxVERTICAL);
wxSizer* bottomRightSizer = new wxBoxSizer(wxVERTICAL);
wxSizer* playButtonSizer = new wxBoxSizer(wxHORIZONTAL);
wxSizer* optionButtonSizer = new wxGridSizer(2);
mainSizer->Add(m_TreeCtrl, wxSizerFlags().Expand().Proportion(1));
mainSizer->Add(bottomSizer, wxSizerFlags().Expand());
bottomSizer->Add(lightControl, wxSizerFlags().Border(wxRIGHT, 5));
bottomSizer->Add(bottomRightSizer, wxSizerFlags().Proportion(1));
wxSizer* optionButtonSizer = new wxBoxSizer(wxVERTICAL);
wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, sidePanel, _("Variation"));
playButtonSizer->Add(new wxButton(sidePanel, ID_Play, _("Play")), wxSizerFlags().Proportion(1));
playButtonSizer->Add(new wxButton(sidePanel, ID_Pause, _("Pause")), wxSizerFlags().Proportion(1));
playButtonSizer->Add(new wxButton(sidePanel, ID_Slow, _("Slow")), wxSizerFlags().Proportion(1));
bottomRightSizer->Add(m_AnimationBox, wxSizerFlags().Expand());
bottomRightSizer->Add(playButtonSizer, wxSizerFlags().Expand());
optionButtonSizer->Add(new wxButton(sidePanel, ID_Edit, _("Edit actor")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Wireframe, _("Wireframe")), _("Toggle wireframe / solid rendering")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Background, _("Background")), _("Change the background colour")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_Walking, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand());
bottomRightSizer->Add(optionButtonSizer, wxSizerFlags().Expand().Border(wxTOP, 4));
variationSizer->Add(new VariationControl(sidePanel, m_ObjectSettings), wxSizerFlags().Expand().Proportion(1));
mainSizer->Add(m_TreeCtrl, wxSizerFlags().Expand().Proportion(1));
mainSizer->Add(bottomSizer, wxSizerFlags().Expand());
bottomSizer->Add(bottomLeftSizer, wxSizerFlags().Expand().Border(wxRIGHT, 5));
bottomSizer->Add(bottomRightSizer, wxSizerFlags().Expand().Proportion(1));
bottomLeftSizer->Add(lightControl, wxSizerFlags().Expand());
bottomLeftSizer->Add(optionButtonSizer, wxSizerFlags().Expand().Border(wxTOP, 4));
bottomRightSizer->Add(m_AnimationBox, wxSizerFlags().Expand());
bottomRightSizer->Add(playButtonSizer, wxSizerFlags().Expand());
bottomRightSizer->Add(variationSizer, wxSizerFlags().Expand().Proportion(1));
sidePanel->SetSizer(mainSizer);
//////////////////////////////////////////////////////////////////////////
m_ObjectSelection.push_back(0);
// Start by displaying the default non-existent actor
m_CurrentActor = _T("structures/fndn_1x1.xml");
SetActorView();
@ -294,6 +320,7 @@ void ActorViewer::OnClose(wxCloseEvent& WXUNUSED(event))
void ActorViewer::SetActorView(bool flushCache)
{
POST_MESSAGE(SetActorViewer, (m_CurrentActor.c_str(), m_AnimationBox->GetValue().c_str(), m_CurrentSpeed, flushCache));
m_ObjectSelection.NotifyObservers();
}
void ActorViewer::OnTreeSelection(wxTreeEvent& event)

View File

@ -2,6 +2,7 @@
#include "GameInterface/Messages.h"
#include "General/Observable.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
class wxTreeCtrl;
@ -29,6 +30,8 @@ private:
wxString m_CurrentActor;
float m_CurrentSpeed;
Observable<std::vector<AtlasMessage::ObjectID> > m_ObjectSelection;
Observable<ObjectSettings> m_ObjectSettings;
bool m_Wireframe;
wxColour m_BackgroundColour;
bool m_Walking;

View File

@ -31,6 +31,13 @@ typedef boost::signals::scoped_connection ObservableScopedConnection;
template <typename T> class Observable : public T
{
public:
Observable() {}
template <typename T1>
explicit Observable(const T1& a1) : T(a1) {}
template <typename T1, typename T2>
explicit Observable(T1& a1, T2 a2) : T(a1, a2) {}
template<typename C> ObservableConnection RegisterObserver(int order, void (C::*callback) (const T&), C* obj)
{
return m_Signal.connect(order, boost::bind(std::mem_fun(callback), obj, _1));

View File

@ -135,11 +135,6 @@ LightControl::LightControl(wxWindow* parent, const wxSize& size, Observable<Atla
m_Conn = environment.RegisterObserver(0, &LightControl::OnSettingsChange, this);
}
LightControl::~LightControl()
{
m_Conn.disconnect();
}
void LightControl::OnSettingsChange(const AtlasMessage::sEnvironmentSettings& settings)
{
m_Sphere->theta = settings.sunrotation;

View File

@ -11,7 +11,6 @@ class LightControl : public wxPanel
{
public:
LightControl(wxWindow* parent, const wxSize& size, Observable<AtlasMessage::sEnvironmentSettings>& environment);
~LightControl();
void OnSettingsChange(const AtlasMessage::sEnvironmentSettings& settings);
@ -19,7 +18,7 @@ public:
private:
Observable<AtlasMessage::sEnvironmentSettings>& m_Environment;
ObservableConnection m_Conn;
ObservableScopedConnection m_Conn;
LightSphere* m_Sphere;
};

View File

@ -6,6 +6,7 @@
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
#include "ScenarioEditor/Tools/Common/MiscState.h"
#include "VariationControl.h"
#include "GameInterface/Messages.h"
@ -160,152 +161,6 @@ BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
EVT_COMBOBOX(wxID_ANY, OnSelect)
END_EVENT_TABLE();
class VariationDisplay : public wxScrolledWindow
{
public:
VariationDisplay(wxWindow* parent)
: wxScrolledWindow(parent, -1)
{
m_Conn = g_ObjectSettings.RegisterObserver(1, &VariationDisplay::OnObjectSettingsChange, this);
SetMinSize(wxSize(160, wxDefaultCoord));
SetScrollRate(0, 5);
m_Sizer = new wxBoxSizer(wxVERTICAL);
SetSizer(m_Sizer);
}
~VariationDisplay()
{
g_ObjectSettings.RemoveObserver(m_Conn);
}
private:
ObservableConnection m_Conn;
std::vector<wxWindow*> m_ComboBoxes;
wxSizer* m_Sizer;
// Event handler shared by all the combo boxes created by this window
void OnSelect(wxCommandEvent& evt)
{
std::set<wxString> selections;
// It's possible for a variant name to appear in multiple groups.
// If so, assume that all the names in each group are the same, so
// we don't have to worry about some impossible combinations (e.g.
// one group "a,b", a second "b,c", and a third "c,a", where's there's
// no set of selections that matches one (and only one) of each group).
//
// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
// selections and make sure any other combo boxes containing both 'a' and
// 'b' no longer contain 'a'.
wxComboBox* thisComboBox = wxDynamicCast(evt.GetEventObject(), wxComboBox);
wxString newValue = thisComboBox->GetValue();
selections.insert(newValue);
for (size_t i = 0; i < m_ComboBoxes.size(); ++i)
{
wxComboBox* comboBox = wxDynamicCast(m_ComboBoxes[i], wxComboBox);
wxCHECK(comboBox != NULL, );
// If our newly selected value is used in another combobox, we want
// that combobox to use the new value, so don't add its old value
// to the list of selections
if (comboBox->FindString(newValue) == wxNOT_FOUND)
selections.insert(comboBox->GetValue());
}
g_ObjectSettings.SetActorSelections(selections);
g_ObjectSettings.NotifyObserversExcept(m_Conn);
RefreshObjectSettings();
}
void OnObjectSettingsChange(const ObjectSettings& settings)
{
Freeze();
const std::vector<ObjectSettings::Group>& variation = settings.GetActorVariation();
// Creating combo boxes seems to be pretty expensive - so we create as
// few as possible, by never deleting any.
size_t oldCount = m_ComboBoxes.size();
size_t newCount = variation.size();
// If we have too many combo boxes, hide the excess ones
for (size_t i = newCount; i < oldCount; ++i)
{
m_ComboBoxes[i]->Show(false);
}
for (size_t i = 0; i < variation.size(); ++i)
{
const ObjectSettings::Group& group = variation[i];
if (i < oldCount)
{
// Already got enough boxes available, so use an old one
wxComboBox* comboBox = wxDynamicCast(m_ComboBoxes[i], wxComboBox);
wxCHECK(comboBox != NULL, );
// Replace the contents of the old combobox with the new data
comboBox->Freeze();
comboBox->Clear();
comboBox->Append(group.variants);
comboBox->SetValue(group.chosen);
comboBox->Show(true);
comboBox->Thaw();
}
else
{
// Create an initially empty combobox, because we can fill it
// quicker than the default constructor can
wxComboBox* combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition,
wxSize(130, wxDefaultCoord), wxArrayString(), wxCB_READONLY);
// Freeze it before adding all the values
combo->Freeze();
combo->Append(group.variants);
combo->SetValue(group.chosen);
combo->Thaw();
// Add the on-select event handler
combo->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(VariationDisplay::OnSelect), NULL, this);
// Add box to sizer and list
m_Sizer->Add(combo);
m_ComboBoxes.push_back(combo);
}
}
Layout();
// Make the scrollbars appear when appropriate
FitInside();
Thaw();
}
void RefreshObjectSettings()
{
const std::vector<ObjectSettings::Group>& variation = g_ObjectSettings.GetActorVariation();
// For each group, set the corresponding combobox's value to the chosen one
size_t i = 0;
for (std::vector<ObjectSettings::Group>::const_iterator group = variation.begin();
group != variation.end() && i < m_ComboBoxes.size();
++group, ++i)
{
wxComboBox* comboBox = wxDynamicCast(m_ComboBoxes[i], wxComboBox);
wxCHECK(comboBox != NULL, );
comboBox->SetValue(group->chosen);
}
}
};
//////////////////////////////////////////////////////////////////////////
ObjectBottomBar::ObjectBottomBar(wxWindow* parent)
@ -327,7 +182,8 @@ ObjectBottomBar::ObjectBottomBar(wxWindow* parent)
wxComboBox* playerSelect = new PlayerComboBox(this, players);
sizer->Add(playerSelect);
wxWindow* variationSelect = new VariationDisplay(this);
wxWindow* variationSelect = new VariationControl(this, g_ObjectSettings);
variationSelect->SetMinSize(wxSize(160, -1));
wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Variation"));
variationSizer->Add(variationSelect, wxSizerFlags().Proportion(1).Expand());
sizer->Add(variationSizer, wxSizerFlags().Proportion(1));

View File

@ -0,0 +1,129 @@
#include "stdafx.h"
#include "VariationControl.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
VariationControl::VariationControl(wxWindow* parent, Observable<ObjectSettings>& objectSettings)
: wxScrolledWindow(parent, -1),
m_ObjectSettings(objectSettings)
{
m_Conn = m_ObjectSettings.RegisterObserver(1, &VariationControl::OnObjectSettingsChange, this);
SetScrollRate(0, 5);
m_Sizer = new wxBoxSizer(wxVERTICAL);
SetSizer(m_Sizer);
}
// Event handler shared by all the combo boxes created by this window
void VariationControl::OnSelect(wxCommandEvent& evt)
{
std::set<wxString> selections;
// It's possible for a variant name to appear in multiple groups.
// If so, assume that all the names in each group are the same, so
// we don't have to worry about some impossible combinations (e.g.
// one group "a,b", a second "b,c", and a third "c,a", where's there's
// no set of selections that matches one (and only one) of each group).
//
// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
// selections and make sure any other combo boxes containing both 'a' and
// 'b' no longer contain 'a'.
wxComboBox* thisComboBox = wxDynamicCast(evt.GetEventObject(), wxComboBox);
wxCHECK(thisComboBox != NULL, );
wxString newValue = thisComboBox->GetValue();
selections.insert(newValue);
for (size_t i = 0; i < m_ComboBoxes.size(); ++i)
{
wxComboBox* comboBox = m_ComboBoxes[i];
// If our newly selected value is used in another combobox, we want
// that combobox to use the new value, so don't add its old value
// to the list of selections
if (comboBox->FindString(newValue) == wxNOT_FOUND)
selections.insert(comboBox->GetValue());
}
m_ObjectSettings.SetActorSelections(selections);
m_ObjectSettings.NotifyObserversExcept(m_Conn);
RefreshObjectSettings();
}
void VariationControl::OnObjectSettingsChange(const ObjectSettings& settings)
{
Freeze();
const std::vector<ObjectSettings::Group>& variation = settings.GetActorVariation();
// Creating combo boxes seems to be pretty expensive - so we create as
// few as possible, by never deleting any.
size_t oldCount = m_ComboBoxes.size();
size_t newCount = variation.size();
// If we have too many combo boxes, hide the excess ones
for (size_t i = newCount; i < oldCount; ++i)
{
m_ComboBoxes[i]->Show(false);
}
for (size_t i = 0; i < variation.size(); ++i)
{
const ObjectSettings::Group& group = variation[i];
if (i < oldCount)
{
// Already got enough boxes available, so use an old one
wxComboBox* comboBox = m_ComboBoxes[i];
// Replace the contents of the old combobox with the new data
comboBox->Freeze();
comboBox->Clear();
comboBox->Append(group.variants);
comboBox->SetValue(group.chosen);
comboBox->Show(true);
comboBox->Thaw();
}
else
{
// Create an initially empty combobox, because we can fill it
// quicker than the default constructor can
wxComboBox* combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition,
wxSize(80, wxDefaultCoord), wxArrayString(), wxCB_READONLY);
// Freeze it before adding all the values
combo->Freeze();
combo->Append(group.variants);
combo->SetValue(group.chosen);
combo->Thaw();
// Add the on-select event handler
combo->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED,
wxCommandEventHandler(VariationControl::OnSelect), NULL, this);
// Add box to sizer and list
m_Sizer->Add(combo, wxSizerFlags().Expand());
m_ComboBoxes.push_back(combo);
}
}
Layout();
Thaw();
// Make the scrollbars appear when appropriate
FitInside();
}
void VariationControl::RefreshObjectSettings()
{
const std::vector<ObjectSettings::Group>& variation = m_ObjectSettings.GetActorVariation();
// For each group, set the corresponding combobox's value to the chosen one
size_t i = 0;
for (std::vector<ObjectSettings::Group>::const_iterator group = variation.begin();
group != variation.end() && i < m_ComboBoxes.size();
++group, ++i)
{
m_ComboBoxes[i]->SetValue(group->chosen);
}
}

View File

@ -0,0 +1,25 @@
#ifndef VARIATIONCONTROL_H__
#define VARIATIONCONTROL_H__
#include "General/Observable.h"
class ObjectSettings;
class VariationControl : public wxScrolledWindow
{
public:
VariationControl(wxWindow* parent, Observable<ObjectSettings>& objectSettings);
private:
void OnSelect(wxCommandEvent& evt);
void OnObjectSettingsChange(const ObjectSettings& settings);
void RefreshObjectSettings();
ObservableScopedConnection m_Conn;
Observable<ObjectSettings>& m_ObjectSettings;
std::vector<wxComboBox*> m_ComboBoxes;
wxSizer* m_Sizer;
};
#endif // VARIATIONCONTROL_H__

View File

@ -5,17 +5,12 @@
#include "GameInterface/Messages.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
Observable<ObjectSettings> g_ObjectSettings;
Observable<ObjectSettings> g_ObjectSettings(g_SelectedObjects, AtlasMessage::eRenderView::GAME);
ObjectSettings::ObjectSettings()
: m_PlayerID(0)
ObjectSettings::ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, int view)
: m_PlayerID(0), m_SelectedObjects(selectedObjects), m_View(view)
{
m_Conn = g_SelectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this);
}
ObjectSettings::~ObjectSettings()
{
m_Conn.disconnect();
m_Conn = m_SelectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this);
}
int ObjectSettings::GetPlayerID() const
@ -98,7 +93,7 @@ void ObjectSettings::OnSelectionChange(const std::vector<AtlasMessage::ObjectID>
if (selection.empty())
return;
AtlasMessage::qGetObjectSettings qry (selection[0]);
AtlasMessage::qGetObjectSettings qry (m_View, selection[0]);
qry.Post();
m_PlayerID = qry.settings->player;
@ -136,8 +131,8 @@ void ObjectSettings::OnSelectionChange(const std::vector<AtlasMessage::ObjectID>
void ObjectSettings::PostToGame()
{
if (g_SelectedObjects.empty())
if (m_SelectedObjects.empty())
return;
POST_COMMAND(SetObjectSettings, (g_SelectedObjects[0], GetSettings()));
POST_COMMAND(SetObjectSettings, (m_View, m_SelectedObjects[0], GetSettings()));
}

View File

@ -16,8 +16,7 @@ namespace AtlasMessage
class ObjectSettings
{
public:
ObjectSettings();
~ObjectSettings();
ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, int view);
int GetPlayerID() const;
void SetPlayerID(int playerID);
@ -37,6 +36,10 @@ public:
AtlasMessage::sObjectSettings GetSettings() const;
private:
Observable<std::vector<AtlasMessage::ObjectID> >& m_SelectedObjects;
int m_View;
// 0 = gaia, 1..inf = normal players
int m_PlayerID;
@ -49,7 +52,7 @@ private:
std::vector<wxArrayString> m_VariantGroups;
// Observe changes to unit selection
ObservableConnection m_Conn;
ObservableScopedConnection m_Conn;
void OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection);
// Transfer current settings to the currently selected unit (if any)

View File

@ -82,6 +82,11 @@ ActorViewer::~ActorViewer()
delete &m;
}
CUnit* ActorViewer::GetUnit()
{
return m.Unit;
}
void ActorViewer::SetActor(const CStrW& id, const CStrW& animation)
{
bool needsAnimReload = false;

View File

@ -3,6 +3,7 @@
struct ActorViewerImpl;
struct SColor4ub;
class CUnit;
class ActorViewer
{
@ -11,6 +12,7 @@ public:
~ActorViewer();
void SetActor(const CStrW& id, const CStrW& animation);
CUnit* GetUnit();
void SetWalkEnabled(bool enabled);
void SetBackgroundColour(const SColor4ub& colour);
void Render();

View File

@ -151,14 +151,16 @@ MESSAGEHANDLER(LookAt)
CVector3D tgt = msg->target->GetWorldSpace();
CVector3D eye = msg->pos->GetWorldSpace();
tgt.Y = -tgt.Y; // ??? why is this needed?
eye.Y = -eye.Y; // ???
tgt.Y = -tgt.Y; // ??? why is this needed?
eye.Y = -eye.Y; // ???
// Based on http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
CVector3D f = tgt - eye;
f.Normalize();
CVector3D s = f.Cross(CVector3D(0, 1, 0));
CVector3D u = s.Cross(f);
s.Normalize(); // (not in that man page, but necessary for correctness, and done by Mesa)
u.Normalize();
CMatrix3D M (
s[0], s[1], s[2], 0,
u[0], u[1], u[2], 0,

View File

@ -4,6 +4,7 @@
#include "MessageHandler.h"
#include "../CommandProc.h"
#include "../View.h"
#include "graphics/GameView.h"
#include "graphics/Model.h"
@ -112,7 +113,7 @@ MESSAGEHANDLER(SetSelectionPreview)
QUERYHANDLER(GetObjectSettings)
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
if (! unit) return;
sObjectSettings settings;
@ -165,7 +166,7 @@ BEGIN_COMMAND(SetObjectSettings)
void Do()
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
if (! unit) return;
sObjectSettings settings = msg->settings;
@ -197,7 +198,7 @@ BEGIN_COMMAND(SetObjectSettings)
private:
void Set(int player, const std::set<CStr>& selections)
{
CUnit* unit = g_UnitMan.FindByID(msg->id);
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
if (! unit) return;
unit->SetPlayerID(player);

View File

@ -302,12 +302,14 @@ MESSAGE(SetSelectionPreview,
);
QUERY(GetObjectSettings,
((int, view)) // eRenderView
((ObjectID, id))
,
((sObjectSettings, settings))
);
COMMAND(SetObjectSettings, NOMERGE,
((int, view)) // eRenderView
((ObjectID, id))
((sObjectSettings, settings))
);

View File

@ -7,6 +7,7 @@
#include "Messages.h"
#include "graphics/SColor.h"
#include "graphics/UnitManager.h"
#include "renderer/Renderer.h"
#include "ps/Game.h"
#include "ps/GameSetup/GameSetup.h"
@ -61,6 +62,11 @@ CCamera& ViewActor::GetCamera()
return m_Camera;
}
CUnit* ViewActor::GetUnit(AtlasMessage::ObjectID UNUSED(id))
{
return m_ActorViewer->GetUnit();
}
bool ViewActor::WantsHighFramerate()
{
if (m_SpeedMultiplier != 0.f && m_ActorViewer->HasAnimation())
@ -139,6 +145,11 @@ CCamera& ViewGame::GetCamera()
return *g_Game->GetView()->GetCamera();
}
CUnit* ViewGame::GetUnit(AtlasMessage::ObjectID id)
{
return g_UnitMan.FindByID(id);
}
bool ViewGame::WantsHighFramerate()
{
if (g_Game->GetView()->GetCinema()->IsPlaying())

View File

@ -1,6 +1,8 @@
#ifndef VIEW_H__
#define VIEW_H__
class CUnit;
class ViewGame;
class ViewActor;
@ -8,10 +10,12 @@ class View
{
public:
virtual ~View();
virtual void Update(float frameLength) = 0;
virtual void Render() = 0;
virtual void Update(float UNUSED(frameLength)) { };
virtual void Render() { };
virtual CCamera& GetCamera() = 0;
virtual bool WantsHighFramerate() = 0;
virtual CUnit* GetUnit(AtlasMessage::ObjectID UNUSED(id)) { return NULL; }
virtual bool WantsHighFramerate() { return false; }
virtual void SetParam(const std::wstring& name, bool value);
virtual void SetParam(const std::wstring& name, const AtlasMessage::Colour& value);
@ -30,10 +34,7 @@ public:
class ViewNone : public View
{
public:
virtual void Update(float) { }
virtual void Render() { }
virtual CCamera& GetCamera() { return dummyCamera; }
virtual bool WantsHighFramerate() { return false; }
private:
CCamera dummyCamera;
};
@ -45,6 +46,7 @@ public:
virtual void Update(float frameLength);
virtual void Render();
virtual CCamera& GetCamera();
virtual CUnit* GetUnit(AtlasMessage::ObjectID id);
virtual bool WantsHighFramerate();
private:
@ -61,7 +63,9 @@ public:
virtual void Update(float frameLength);
virtual void Render();
virtual CCamera& GetCamera();
virtual CUnit* GetUnit(AtlasMessage::ObjectID id);
virtual bool WantsHighFramerate();
virtual void SetParam(const std::wstring& name, bool value);
virtual void SetParam(const std::wstring& name, const AtlasMessage::Colour& value);