# Fix the actor viewer in Atlas.

Delete the old standalone actor viewer.
Import some terrain textures that are useful for tools.
Fixes #483.

This was SVN commit r7428.
This commit is contained in:
Ykkrosh 2010-04-03 11:07:42 +00:00
parent 6fb5c1b307
commit 0d6882dad2
20 changed files with 172 additions and 665 deletions

View File

@ -18,7 +18,7 @@ var actorViewer = {
distance: 20,
angle: 0,
elevation: Math.PI / 6,
actor: "(n) structures/fndn_1x1.xml",
actor: "actor|structures/fndn_1x1.xml",
animation: "idle",
// Animation playback speed
speed: 0,
@ -37,7 +37,7 @@ actorViewer.toggle = function () {
};
actorViewer.postToGame = function () {
Atlas.Message.SetActorViewer(this.actor, this.animation, this.speed, false);
Atlas.Message.SetActorViewer(this.actor, this.animation, this.speed, false);
};
actorViewer.postLookAt = function () {
@ -194,6 +194,40 @@ function init(window, bottomWindow)
window.sizer.add(viewerButton, 0, wxStretch.EXPAND);
// Actor viewer settings:
var displaySettingsBoxBox = new wxStaticBox(bottomWindow, -1, "Display settings");
actorViewer.controls.push(displaySettingsBoxBox);
var displaySettingsBox = new wxStaticBoxSizer(displaySettingsBoxBox, wxOrientation.VERTICAL);
displaySettingsBox.minSize = new wxSize(140, -1);
var displaySettings = [
["Wireframe", "Toggle wireframe / solid rendering", "wireframe", false],
["Move", "Toggle movement along ground when playing walk/run animations", "walk", false],
["Ground", "Toggle the ground plane", "ground", true],
["Shadows", "Toggle shadow rendering", "shadows", true],
["Poly count", "Toggle polygon-count statistics - turn off ground and shadows for more useful data", "stats", false]
];
// NOTE: there's also a background colour setting, which isn't exposed
// by this UI because I don't know if it's worth the effort
for each (var setting in displaySettings) {
var button = new wxButton(bottomWindow, -1, setting[0]);
actorViewer.controls.push(button);
button.toolTip = setting[1];
// Set the default value
Atlas.Message.SetViewParamB(Atlas.RenderView.ACTOR, setting[2], setting[3]);
// Toggle the value on clicks
(function (s) { // local scope for closure
button.onClicked = function () {
s[3] = !s[3];
Atlas.Message.SetViewParamB(Atlas.RenderView.ACTOR, s[2], s[3]);
};
})(setting);
displaySettingsBox.add(button, 0, wxStretch.EXPAND);
}
// TODO: It might be nice to add an "edit this actor" button
// in the actor viewer (when we have working actor hotloading)
var playerSelector = new wxChoice(bottomWindow, -1, wxDefaultPosition, wxDefaultSize,
["Gaia", "Player 1", "Player 2", "Player 3", "Player 4", "Player 5", "Player 6", "Player 7", "Player 8"]
);
@ -236,13 +270,13 @@ function init(window, bottomWindow)
animationBox.add(animationSelector, 0, wxStretch.EXPAND);
animationBox.add(animationSpeedSizer, 0, wxStretch.EXPAND);
var animationSizer = new wxBoxSizer(wxOrientation.VERTICAL);
animationSizer.minSize = new wxSize(160, -1);
animationSizer.add(playerSelector, 0, wxStretch.EXPAND);
animationSizer.add(animationBox, 0, wxStretch.EXPAND);
for each (ctrl in actorViewer.controls)
ctrl.show(false);
@ -297,6 +331,7 @@ function init(window, bottomWindow)
bottomWindow.sizer = new wxBoxSizer(wxOrientation.HORIZONTAL);
bottomWindow.sizer.add(displaySettingsBox);
bottomWindow.sizer.add(animationSizer);
bottomWindow.sizer.add(variationControlBox, 0, wxStretch.EXPAND);

View File

@ -1 +0,0 @@
start pyrogenesis.exe -editor -actorviewer

View File

@ -790,7 +790,6 @@ function setup_atlas_packages()
atlas_src = {
"ActorEditor",
"ActorViewer",
"ColourTester",
"CustomControls/Buttons",
"CustomControls/Canvas",

View File

@ -84,9 +84,7 @@ CGame::CGame():
if (g_UseSimulation2)
{
m_Simulation2->LoadScripts(L"simulation/components/interfaces/");
m_Simulation2->LoadScripts(L"simulation/helpers/");
m_Simulation2->LoadScripts(L"simulation/components/");
m_Simulation2->LoadDefaultScripts();
m_Simulation2->ResetState();
CScriptVal initData; // TODO: ought to get this from the GUI, somehow

View File

@ -266,6 +266,15 @@ bool CSimulation2::LoadScripts(const VfsPath& path)
return m->LoadScripts(path);
}
bool CSimulation2::LoadDefaultScripts()
{
return (
m->LoadScripts(L"simulation/components/interfaces/") &&
m->LoadScripts(L"simulation/helpers/") &&
m->LoadScripts(L"simulation/components/")
);
}
LibError CSimulation2::ReloadChangedFile(const VfsPath& path)
{
return m->ReloadChangedFile(path);

View File

@ -54,9 +54,16 @@ public:
* Load all scripts in the specified directory (non-recursively),
* so they can register new component types and functions. This
* should be called immediately after constructing the CSimulation2 object.
* @return false on failure
*/
bool LoadScripts(const VfsPath& path);
/**
* Call LoadScripts for each of the game's standard simulation script paths.
* @return false on failure
*/
bool LoadDefaultScripts();
/**
* Reload any scripts that were loaded from the given filename.
* (This is used to implement hotloading.)

View File

@ -72,9 +72,7 @@ public:
CTerrain terrain;
CSimulation2 sim2(NULL, &terrain);
sim2.LoadScripts(L"simulation/components/interfaces/");
sim2.LoadScripts(L"simulation/helpers/");
sim2.LoadScripts(L"simulation/components/");
sim2.LoadDefaultScripts();
sim2.ResetState();
CMapReader* mapReader = new CMapReader(); // it'll call "delete this" itself

View File

@ -1,459 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "ActorViewer.h"
#include "wx/treectrl.h"
#include "wx/regex.h"
#include "General/Datafile.h"
#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"
#include "CustomControls/Canvas/Canvas.h"
#include "CustomControls/ColourDialog/ColourDialog.h"
#include "CustomControls/SnapSplitterWindow/SnapSplitterWindow.h"
#include "ActorEditor/ActorEditor.h"
using namespace AtlasMessage;
const float M_PIf = 3.14159265f;
//////////////////////////////////////////////////////////////////////////
wxWindow* Tooltipped(wxWindow* window, const wxString& tip)
{
window->SetToolTip(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_Elevation(M_PIf/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*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)));
}
protected:
virtual void HandleMouseEvent(wxMouseEvent& evt)
{
bool camera_changed = false;
if (evt.GetWheelRotation())
{
float speed = -1.f * ScenarioEditor::GetSpeedModifier();
m_Distance += evt.GetWheelRotation() * speed / evt.GetWheelDelta();
camera_changed = true;
}
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) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
&& m_LastIsValid)
{
int dx = evt.GetX() - m_LastX;
int dy = evt.GetY() - m_LastY;
m_LastX = evt.GetX();
m_LastY = evt.GetY();
m_Angle += dx * M_PIf/256.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_PIf/256.f * ScenarioEditor::GetSpeedModifier();
camera_changed = true;
}
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 all buttons were released since
// the last buttondown.
// (TODO: does this problem affect the scenario editor too?)
m_LastIsValid = false;
}
m_Distance = std::max(m_Distance, 1/64.f); // don't let people fly through the origin
if (camera_changed)
PostLookAt();
}
private:
float m_Distance;
float m_Angle;
float m_Elevation;
int m_LastX, m_LastY;
bool m_LastIsValid;
};
//////////////////////////////////////////////////////////////////////////
class StringTreeItemData : public wxTreeItemData
{
public:
StringTreeItemData(const wxString& string) : m_String(string) {}
wxString m_String;
};
enum
{
ID_Actors,
ID_Animations,
ID_Play,
ID_Pause,
ID_Slow,
ID_Edit,
ID_Background,
ID_ToggleWireframe,
ID_ToggleWalking,
ID_ToggleGround,
ID_ToggleShadows,
ID_ToggleStats,
};
BEGIN_EVENT_TABLE(ActorViewer, wxFrame)
EVT_CLOSE(ActorViewer::OnClose)
EVT_TREE_SEL_CHANGED(ID_Actors, ActorViewer::OnTreeSelection)
EVT_COMBOBOX(ID_Animations, ActorViewer::OnAnimationSelection)
EVT_TEXT_ENTER(ID_Animations, ActorViewer::OnAnimationSelection)
EVT_BUTTON(ID_Play, ActorViewer::OnSpeedButton)
EVT_BUTTON(ID_Pause, ActorViewer::OnSpeedButton)
EVT_BUTTON(ID_Slow, ActorViewer::OnSpeedButton)
EVT_BUTTON(ID_Edit, ActorViewer::OnEditButton)
EVT_BUTTON(ID_Background, ActorViewer::OnBackgroundButton)
EVT_BUTTON(ID_ToggleWireframe, ActorViewer::OnToggleButton)
EVT_BUTTON(ID_ToggleWalking, ActorViewer::OnToggleButton)
EVT_BUTTON(ID_ToggleGround, ActorViewer::OnToggleButton)
EVT_BUTTON(ID_ToggleShadows, ActorViewer::OnToggleButton)
EVT_BUTTON(ID_ToggleStats, ActorViewer::OnToggleButton)
END_EVENT_TABLE()
static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
{
POST_COMMAND(SetEnvironmentSettings, (settings));
}
ActorViewer::ActorViewer(wxWindow* parent, ScriptInterface& scriptInterface)
: wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)),
m_CurrentSpeed(0.f), m_BackgroundColour(wxColour(255, 255, 255)),
m_ToggledWalking(false), m_ToggledWireframe(false), m_ToggledGround(true),
m_ToggledShadows(true), m_ToggledStats(false),
m_ScriptInterface(scriptInterface),
m_ObjectSettings(m_ObjectSelection, m_ScriptInterface)
{
SetIcon(wxIcon(_T("ICON_ActorEditor")));
// XXX: need to init m_ScriptInterface
m_ObjectSettings.Init(AtlasMessage::eRenderView::ACTOR);
SnapSplitterWindow* splitter = new SnapSplitterWindow(this, 0);
splitter->SetDefaultSashPosition(250);
wxPanel* sidePanel = new wxPanel(splitter);
// TODO: don't have this duplicated from ScenarioEditor.cpp
int glAttribList[] = {
WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
WX_GL_DEPTH_SIZE, 24,
WX_GL_BUFFER_SIZE, 24,
WX_GL_MIN_ALPHA, 8,
0
};
ActorCanvas* canvas = new ActorCanvas(splitter, glAttribList);
splitter->SplitVertically(sidePanel, canvas);
#ifdef __WXMSW__
wglMakeCurrent(NULL, NULL);
#elif defined(__WXGTK__)
// Need to make sure the canvas is realized by GTK, so that its context is valid
Show(true);
wxSafeYield();
#endif
POST_MESSAGE(SetCanvas, (static_cast<wxGLCanvas*>(canvas)));
POST_MESSAGE(Init, (false));
canvas->InitSize();
canvas->PostLookAt();
//////////////////////////////////////////////////////////////////////////
// Construct a tree containing all the available actors
qGetObjectsList qry;
qry.Post();
std::vector<sObjectsListItem> objects = *qry.objects;
m_TreeCtrl = new wxTreeCtrl(sidePanel, ID_Actors);
wxTreeItemId root = m_TreeCtrl->AddRoot(_("Actors"));
std::map<std::wstring, wxTreeItemId> treeEntries;
wxRegEx stripDirs (_T("^([^/]+)/"), wxRE_EXTENDED); // the non-empty string up to the first slash
for (std::vector<sObjectsListItem>::iterator it = objects.begin(); it != objects.end(); ++it)
{
if (it->type != 1)
continue;
wxString name = it->name.c_str();
// Loop through the directory components of the name, stripping them
// off and search down the tree hierarchy
wxString path = _T("");
wxTreeItemId treeItem = root;
while (stripDirs.Matches(name))
{
wxString dir = stripDirs.GetMatch(name, 1);
path += dir + _T("/");
// If we've got 'path' in the tree already, use it
std::map<std::wstring, wxTreeItemId>::iterator entry = treeEntries.find(path.c_str());
if (entry != treeEntries.end())
{
treeItem = entry->second;
}
else
{
// Add this new path into the tree
treeItem = m_TreeCtrl->AppendItem(treeItem, dir);
treeEntries.insert(std::make_pair(path, treeItem));
}
// Remove the leading directory name from the full filename
stripDirs.Replace(&name, _T(""));
}
m_TreeCtrl->AppendItem(treeItem, name, -1, -1, new StringTreeItemData(it->name.c_str()));
}
m_TreeCtrl->Expand(root);
wxArrayString animations;
AtObj animationsList (Datafile::ReadList("animations"));
for (AtIter it = animationsList["item"]; it.defined(); ++it)
animations.Add((const wchar_t *)it);
m_AnimationBox = new wxComboBox(sidePanel, ID_Animations, _T("Idle"), wxDefaultPosition, wxDefaultSize, animations);
m_EnvironmentSettings.sunelevation = 45 * M_PIf/180;
m_EnvironmentSettings.sunrotation = 315 * M_PIf/180;
m_EnvironmentSettings.sunoverbrightness = 1.0f;
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(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 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));
optionButtonSizer->Add(new wxButton(sidePanel, ID_Edit, _("Edit actor")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleWireframe, _("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_ToggleWalking, _("Move")), _("Toggle movement along ground when playing walk/run animations")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleGround, _("Ground")), _("Toggle the ground plane")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand());
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleStats, _("Poly count")), _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand());
// 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);
//////////////////////////////////////////////////////////////////////////
// Pretend to have selected a unit, so the variations thing works properly
m_ObjectSelection.push_back(0);
// Start by displaying the default non-existent actor
m_CurrentActor = _T("structures/fndn_1x1.xml");
SetActorView();
POST_MESSAGE(RenderEnable, (eRenderView::ACTOR));
#ifdef __WXGTK__
// HACK: because of how we fiddle with stuff earlier to make sure the canvas
// is displayed, the layout gets messed up, and it only seems to be fixable
// by changing the window's size
SetSize(GetSize() + wxSize(1, 0));
#endif
}
void ActorViewer::OnClose(wxCloseEvent& WXUNUSED(event))
{
POST_MESSAGE(Shutdown, ());
AtlasMessage::qExit().Post();
// blocks until engine has noticed the message, so we won't be
// destroying the GLCanvas while it's still rendering
Destroy();
}
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)
{
wxTreeItemData* data = m_TreeCtrl->GetItemData(event.GetItem());
if (! data)
return;
m_CurrentActor = static_cast<StringTreeItemData*>(data)->m_String;
SetActorView();
}
void ActorViewer::OnAnimationSelection(wxCommandEvent& WXUNUSED(event))
{
SetActorView();
}
void ActorViewer::OnSpeedButton(wxCommandEvent& event)
{
if (event.GetId() == ID_Play)
m_CurrentSpeed = 1.f;
else if (event.GetId() == ID_Pause)
m_CurrentSpeed = 0.f;
else if (event.GetId() == ID_Slow)
m_CurrentSpeed = 0.1f;
else
{
wxLogDebug(_T("Invalid OnSpeedButton (%d)"), event.GetId());
m_CurrentSpeed = 1.f;
}
SetActorView();
}
void ActorViewer::OnActorEdited()
{
SetActorView(true);
}
void ActorViewer::OnEditButton(wxCommandEvent& WXUNUSED(event))
{
wxFileName dir (_T("mods/public/art/actors/") + m_CurrentActor, wxPATH_UNIX);
dir.MakeAbsolute(Datafile::GetDataDirectory());
ActorEditor* ed = new ActorEditor(NULL);
ed->OpenFile(dir.GetFullPath());
ed->Show();
m_ActorConns.Add(ed->sig_FileSaved.connect(
boost::bind(std::mem_fun(&ActorViewer::OnActorEdited), this)
));
}
void ActorViewer::OnBackgroundButton(wxCommandEvent& WXUNUSED(event))
{
ColourDialog dlg (this, _T("Actor Viewer/BackgroundColour"), m_BackgroundColour);
if (dlg.ShowModal() == wxID_OK)
{
wxColour& c = dlg.GetColourData().GetColour();
m_BackgroundColour = c;
POST_MESSAGE(SetViewParamC, (eRenderView::ACTOR, L"background",
AtlasMessage::Colour(c.Red(), c.Green(), c.Blue())));
}
}
void ActorViewer::OnToggleButton(wxCommandEvent& event)
{
#define CASE(name, str) \
case ID_Toggle##name: \
m_Toggled##name = !m_Toggled##name; \
POST_MESSAGE(SetViewParamB, (eRenderView::ACTOR, str, m_Toggled##name)); \
break
switch (event.GetId())
{
CASE(Wireframe, L"wireframe");
CASE(Walking, L"walk");
CASE(Ground, L"ground");
CASE(Shadows, L"shadows");
CASE(Stats, L"stats");
default:
wxFAIL_MSG(_T("Incorrect ID in OnToggleButton"));
}
}

View File

@ -1,64 +0,0 @@
/* Copyright (C) 2009 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Windows/AtlasWindow.h"
#include "GameInterface/Messages.h"
#include "General/Observable.h"
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
#include "wx/treectrl.h"
class wxTreeCtrl;
class wxTreeEvent;
class ScriptInterface;
class ActorViewer : public wxFrame
{
public:
ActorViewer(wxWindow* parent, ScriptInterface& scriptInterface);
private:
void SetActorView(bool flushCache = false);
void OnClose(wxCloseEvent& event);
void OnTreeSelection(wxTreeEvent& event);
void OnAnimationSelection(wxCommandEvent& event);
void OnSpeedButton(wxCommandEvent& event);
void OnEditButton(wxCommandEvent& event);
void OnToggleButton(wxCommandEvent& event);
void OnBackgroundButton(wxCommandEvent& event);
void OnActorEdited();
ObservableScopedConnections m_ActorConns;
wxTreeCtrl* m_TreeCtrl;
wxComboBox* m_AnimationBox;
wxString m_CurrentActor;
float m_CurrentSpeed;
ScriptInterface& m_ScriptInterface;
Observable<std::vector<AtlasMessage::ObjectID> > m_ObjectSelection;
ObjectSettings m_ObjectSettings;
wxColour m_BackgroundColour;
bool m_ToggledWireframe, m_ToggledWalking, m_ToggledGround, m_ToggledShadows, m_ToggledStats;
Observable<AtlasMessage::sEnvironmentSettings> m_EnvironmentSettings;
ObservableScopedConnection m_EnvConn;
DECLARE_EVENT_TABLE();
};

View File

@ -24,7 +24,6 @@
#include "General/Datafile.h"
#include "ActorEditor/ActorEditor.h"
#include "ActorViewer/ActorViewer.h"
#include "ArchiveViewer/ArchiveViewer.h"
#include "ColourTester/ColourTester.h"
#include "FileConverter/FileConverter.h"
@ -217,11 +216,6 @@ public:
m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand);
frame = new ScenarioEditor(NULL, *m_ScriptInterface);
}
else if (g_InitialWindowType == _T("ActorViewer"))
{
m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand);
frame = new ActorViewer(NULL, *m_ScriptInterface);
}
else
{
wxFAIL_MSG(_("Internal error: invalid window type"));

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -25,13 +25,10 @@
#include "graphics/Model.h"
#include "graphics/ObjectManager.h"
#include "graphics/Patch.h"
#include "graphics/SkeletonAnim.h"
#include "graphics/SkeletonAnimDef.h"
#include "graphics/SkeletonAnimManager.h"
#include "graphics/Terrain.h"
#include "graphics/TextureEntry.h"
#include "graphics/TextureManager.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "maths/MathUtil.h"
#include "ps/Font.h"
@ -40,20 +37,22 @@
#include "renderer/Renderer.h"
#include "renderer/Scene.h"
#include "renderer/SkyManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "simulation/EntityTemplate.h"
#include "simulation2/Simulation2.h"
#include "simulation2/components/ICmpPosition.h"
#include "simulation2/components/ICmpVisual.h"
struct ActorViewerImpl : public Scene
{
NONCOPYABLE(ActorViewerImpl);
public:
ActorViewerImpl()
: Unit(NULL), ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
ObjectManager(MeshManager, SkeletonAnimManager)
: Entity(INVALID_ENTITY), Terrain(), ColladaManager(), MeshManager(ColladaManager), SkeletonAnimManager(ColladaManager),
ObjectManager(MeshManager, SkeletonAnimManager), UnitManager(), Simulation2(&UnitManager, &Terrain)
{
UnitManager.SetObjectManager(ObjectManager);
}
CUnit* Unit;
entity_id_t Entity;
CStrW CurrentUnitID;
CStrW CurrentUnitAnim;
float CurrentSpeed;
@ -69,35 +68,27 @@ public:
CMeshManager MeshManager;
CSkeletonAnimManager SkeletonAnimManager;
CObjectManager ObjectManager;
CUnitManager UnitManager;
CSimulation2 Simulation2;
// Simplistic implementation of the Scene interface
void EnumerateObjects(const CFrustum& UNUSED(frustum), SceneCollector* c)
void EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
{
if (GroundEnabled)
c->Submit(Terrain.GetPatch(0, 0));
if (Unit)
c->SubmitRecursive(Unit->GetModel());
Simulation2.RenderSubmit(*c, frustum, false);
}
};
ActorViewer::ActorViewer()
: m(*new ActorViewerImpl())
{
m.Unit = NULL;
m.WalkEnabled = false;
m.GroundEnabled = true;
m.ShadowsEnabled = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
m.Background = SColor4ub(255, 255, 255, 255);
// Set up the renderer
g_TexMan.LoadTerrainTextures();
g_Renderer.LoadAlphaMaps();
g_Renderer.GetSkyManager()->m_RenderSky = false;
// (TODO: should these be unloaded properly some time? and what should
// happen if we want the actor viewer and scenario editor loaded at
// the same time?)
// Create a tiny empty piece of terrain, just so we can put shadows
// on it without having to think too hard
m.Terrain.Initialize(1, NULL);
@ -115,17 +106,29 @@ ActorViewer::ActorViewer()
}
}
}
else
{
debug_warn(L"Failed to load whiteness texture");
}
// Start the simulation
m.Simulation2.LoadDefaultScripts();
m.Simulation2.ResetState();
}
ActorViewer::~ActorViewer()
{
delete m.Unit;
delete &m;
}
CUnit* ActorViewer::GetUnit()
CSimulation2* ActorViewer::GetSimulation2()
{
return m.Unit;
return &m.Simulation2;
}
entity_id_t ActorViewer::GetEntity()
{
return m.Entity;
}
void ActorViewer::UnloadObjects()
@ -133,64 +136,38 @@ void ActorViewer::UnloadObjects()
m.ObjectManager.UnloadObjects();
}
// We want to support selection of both entities and actors in the
// Actor Viewer tool, so work out the actor corresponding to the given
// string
static bool ParseObjectName(const CStrW& obj, CStrW& name)
{
if (obj.substr(0, 4) == L"(e) ")
{
CStrW entname = obj.substr(4);
CEntityTemplate* entity = g_EntityTemplateCollection.GetTemplate(entname);
if (! entity)
return false;
name = entity->m_actorName;
return true;
}
else if (obj.substr(0, 4) == L"(n) ")
{
name = obj.substr(4);
return true;
}
else
{
// By default, assume it's just an actor name. (TODO: This
// case is probably only used by the obsolete standalone
// Actor Viewer and should get removed eventually.)
name = obj;
return true;
}
}
void ActorViewer::SetActor(const CStrW& name, const CStrW& animation)
{
bool needsAnimReload = false;
CStrW id;
if (! ParseObjectName(name, id))
id = L"";
CStrW id = name;
if (! m.Unit || id != m.CurrentUnitID)
// Recreate the entity, if we don't have one or if the new one is different
if (m.Entity == INVALID_ENTITY || id != m.CurrentUnitID)
{
delete m.Unit;
m.Unit = NULL;
// Delete the old entity (if any)
if (m.Entity != INVALID_ENTITY)
{
m.Simulation2.DestroyEntity(m.Entity);
m.Simulation2.FlushDestroyedEntities();
m.Entity = INVALID_ENTITY;
}
// If there's no actor to display, return with nothing loaded
if (id.empty())
return;
m.Unit = CUnit::Create(CStr(id), NULL, std::set<CStr>(), m.ObjectManager);
m.Entity = m.Simulation2.AddEntity(L"preview|" + id);
if (! m.Unit)
if (m.Entity == INVALID_ENTITY)
return;
float angle = (float)M_PI;
CMatrix3D mat;
mat.SetYRotation(angle + (float)M_PI);
mat.Translate(CELL_SIZE * PATCH_SIZE/2, 0.f, CELL_SIZE * PATCH_SIZE/2);
m.Unit->GetModel()->SetTransform(mat);
m.Unit->GetModel()->ValidatePosition();
CmpPtr<ICmpPosition> cmpPosition(m.Simulation2, m.Entity);
if (!cmpPosition.null())
{
cmpPosition->JumpTo(entity_pos_t::FromInt(CELL_SIZE*PATCH_SIZE/2), entity_pos_t::FromInt(CELL_SIZE*PATCH_SIZE/2));
cmpPosition->SetYRotation(entity_angle_t::FromFloat((float)M_PI));
}
needsAnimReload = true;
}
@ -203,8 +180,8 @@ void ActorViewer::SetActor(const CStrW& name, const CStrW& animation)
float speed;
// TODO: this is just copied from template_unit.xml and isn't the
// same for all units. But we don't know anything about entities here,
// so what to do?
// same for all units. We ought to get it from the entity definition
// (if there is one)
if (anim == "walk")
speed = 7.f;
else if (anim == "run")
@ -213,8 +190,12 @@ void ActorViewer::SetActor(const CStrW& name, const CStrW& animation)
speed = 0.f;
m.CurrentSpeed = speed;
m.Unit->SetEntitySelection(anim);
m.Unit->SetRandomAnimation(anim, false, speed);
CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
if (!cmpVisual.null())
{
// TODO: SetEntitySelection(anim)
cmpVisual->SelectAnimation(anim, false, speed);
}
}
m.CurrentUnitID = id;
@ -249,13 +230,17 @@ void ActorViewer::Render()
bool oldShadows = g_Renderer.GetOptionBool(CRenderer::OPT_SHADOWS);
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, m.ShadowsEnabled);
bool oldSky = g_Renderer.GetSkyManager()->m_RenderSky;
g_Renderer.GetSkyManager()->m_RenderSky = false;
g_Renderer.BeginFrame();
// Find the centre of the interesting region, in the middle of the patch
// and half way up the model (assuming there is one)
CVector3D centre;
if (m.Unit)
m.Unit->GetModel()->GetBounds().GetCentre(centre);
CmpPtr<ICmpVisual> cmpVisual(m.Simulation2, m.Entity);
if (!cmpVisual.null())
cmpVisual->GetBounds().GetCentre(centre);
else
centre.Y = 0.f;
centre.X = centre.Z = CELL_SIZE * PATCH_SIZE/2;
@ -301,45 +286,30 @@ void ActorViewer::Render()
g_Renderer.EndFrame();
// Restore the old renderer state
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWS, oldShadows);
g_Renderer.GetSkyManager()->m_RenderSky = oldSky;
ogl_WarnIfError();
}
void ActorViewer::Update(float dt)
{
if (m.Unit)
m.Simulation2.Update(dt);
m.Simulation2.Interpolate(dt);
if (m.WalkEnabled && m.CurrentSpeed)
{
m.Unit->GetModel()->Update(dt);
CMatrix3D mat = m.Unit->GetModel()->GetTransform();
if (m.WalkEnabled && m.CurrentSpeed)
CmpPtr<ICmpPosition> cmpPosition(m.Simulation2, m.Entity);
if (!cmpPosition.null())
{
// Move the model by speed*dt forwards
float z = mat.GetTranslation().Z;
float z = cmpPosition->GetPosition().Z.ToFloat();
z -= m.CurrentSpeed*dt;
// Wrap at the edges, so it doesn't run off into the horizon
if (z < CELL_SIZE*PATCH_SIZE * 0.4f)
z = CELL_SIZE*PATCH_SIZE * 0.6f;
mat.Translate(0.f, 0.f, z - mat.GetTranslation().Z);
cmpPosition->JumpTo(cmpPosition->GetPosition().X, entity_pos_t::FromFloat(z));
}
m.Unit->GetModel()->SetTransform(mat);
m.Unit->GetModel()->ValidatePosition();
}
}
bool ActorViewer::HasAnimation() const
{
if (m.Unit &&
m.Unit->GetModel()->GetAnimation() &&
m.Unit->GetModel()->GetAnimation()->m_AnimDef &&
m.Unit->GetModel()->GetAnimation()->m_AnimDef->GetNumFrames() > 1)
return true;
if (m.Unit && m.WalkEnabled && m.CurrentSpeed)
return true;
return false;
}

View File

@ -18,9 +18,11 @@
#ifndef INCLUDED_ACTORVIEWER
#define INCLUDED_ACTORVIEWER
#include "simulation2/system/Entity.h"
struct ActorViewerImpl;
struct SColor4ub;
class CUnit;
class CSimulation2;
class CStrW;
class ActorViewer
@ -30,9 +32,10 @@ public:
ActorViewer();
~ActorViewer();
CSimulation2* GetSimulation2();
entity_id_t GetEntity();
void SetActor(const CStrW& id, const CStrW& animation);
void UnloadObjects();
CUnit* GetUnit();
void SetBackgroundColour(const SColor4ub& colour);
void SetWalkEnabled(bool enabled);
void SetGroundEnabled(bool enabled);
@ -40,10 +43,6 @@ public:
void SetStatsEnabled(bool enabled);
void Render();
void Update(float dt);
// Returns whether there is a selected actor which has more than one
// frame of animation
bool HasAnimation() const;
private:
ActorViewerImpl& m;

View File

@ -80,12 +80,10 @@ static void* LaunchWindow(void* data)
}
// Work out which Atlas window to launch, given the command-line arguments
static const wchar_t* FindWindowName(const CmdLineArgs& args)
static const wchar_t* FindWindowName(const CmdLineArgs& UNUSED(args))
{
if (args.Has("actorviewer"))
return L"ActorViewer";
else
return L"ScenarioEditor";
return L"ScenarioEditor";
// (This is a bit pointless - there's no choice since we've deleted the ActorViewer)
}
static ErrorReaction AtlasDisplayError(const wchar_t* text, size_t flags)

View File

@ -190,12 +190,14 @@ MESSAGEHANDLER(SetSelectionPreview)
QUERYHANDLER(GetObjectSettings)
{
if (g_UseSimulation2)
View* view = View::GetView(msg->view);
CSimulation2* simulation = view->GetSimulation2();
if (simulation)
{
sObjectSettings settings;
settings.player = 0;
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), msg->id);
CmpPtr<ICmpOwnership> cmpOwner (*simulation, view->GetEntityId(msg->id));
if (!cmpOwner.null())
{
int32_t player = cmpOwner->GetOwner();
@ -210,7 +212,7 @@ QUERYHANDLER(GetObjectSettings)
return;
}
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
CUnit* unit = view->GetUnit(msg->id);
if (! unit) return;
sObjectSettings settings;
@ -265,9 +267,11 @@ BEGIN_COMMAND(SetObjectSettings)
{
sObjectSettings settings = msg->settings;
if (g_UseSimulation2)
View* view = View::GetView(msg->view);
CSimulation2* simulation = view->GetSimulation2();
if (simulation)
{
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), msg->id);
CmpPtr<ICmpOwnership> cmpOwner (*simulation, view->GetEntityId(msg->id));
m_PlayerOld = 0;
if (!cmpOwner.null())
{
@ -280,7 +284,7 @@ BEGIN_COMMAND(SetObjectSettings)
}
else
{
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
CUnit* unit = view->GetUnit(msg->id);
if (! unit) return;
m_PlayerOld = unit->GetPlayerID();
m_SelectionsOld = unit->GetActorSelections();
@ -310,9 +314,11 @@ BEGIN_COMMAND(SetObjectSettings)
private:
void Set(size_t player, const std::set<CStr>& selections)
{
if (g_UseSimulation2)
View* view = View::GetView(msg->view);
CSimulation2* simulation = view->GetSimulation2();
if (simulation)
{
CmpPtr<ICmpOwnership> cmpOwner (*g_Game->GetSimulation2(), msg->id);
CmpPtr<ICmpOwnership> cmpOwner (*simulation, view->GetEntityId(msg->id));
if (!cmpOwner.null())
cmpOwner->SetOwner(player);
// TODO: selections
@ -320,7 +326,7 @@ private:
return;
}
CUnit* unit = View::GetView(msg->view)->GetUnit(msg->id);
CUnit* unit = view->GetUnit(msg->id);
if (! unit) return;
unit->SetPlayerID(player);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -85,14 +85,19 @@ CCamera& ViewActor::GetCamera()
return m_Camera;
}
CUnit* ViewActor::GetUnit(AtlasMessage::ObjectID UNUSED(id))
CSimulation2* ViewActor::GetSimulation2()
{
return m_ActorViewer->GetUnit();
return m_ActorViewer->GetSimulation2();
}
entity_id_t ViewActor::GetEntityId(AtlasMessage::ObjectID UNUSED(obj))
{
return m_ActorViewer->GetEntity();
}
bool ViewActor::WantsHighFramerate()
{
if (m_SpeedMultiplier != 0.f && m_ActorViewer->HasAnimation())
if (m_SpeedMultiplier != 0.f)
return true;
return false;
@ -155,6 +160,13 @@ ViewGame::~ViewGame()
std::for_each(m_SavedStates.begin(), m_SavedStates.end(), delete_pair_2nd<std::wstring, SimState*>);
}
CSimulation2* ViewGame::GetSimulation2()
{
if (g_UseSimulation2)
return g_Game->GetSimulation2();
return NULL;
}
void ViewGame::Update(float frameLength)
{
float actualFrameLength = frameLength * m_SpeedMultiplier;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2009 Wildfire Games.
/* Copyright (C) 2010 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -23,8 +23,10 @@
#include "graphics/Camera.h"
#include "Messages.h"
#include "simulation2/system/Entity.h"
class CUnit;
class CSimulation2;
class ViewGame;
class ViewActor;
@ -36,6 +38,8 @@ public:
virtual void Update(float UNUSED(frameLength)) { };
virtual void Render() { };
virtual CCamera& GetCamera() = 0;
virtual CSimulation2* GetSimulation2() { return NULL; }
virtual entity_id_t GetEntityId(AtlasMessage::ObjectID obj) { return (entity_id_t)obj; }
virtual CUnit* GetUnit(AtlasMessage::ObjectID UNUSED(id)) { return NULL; }
virtual bool WantsHighFramerate() { return false; }
@ -73,6 +77,7 @@ public:
virtual void Render();
virtual CCamera& GetCamera();
virtual CUnit* GetUnit(AtlasMessage::ObjectID id);
virtual CSimulation2* GetSimulation2();
virtual bool WantsHighFramerate();
void SetSpeedMultiplier(float speed);
@ -96,7 +101,8 @@ public:
virtual void Update(float frameLength);
virtual void Render();
virtual CCamera& GetCamera();
virtual CUnit* GetUnit(AtlasMessage::ObjectID id);
virtual CSimulation2* GetSimulation2();
virtual entity_id_t GetEntityId(AtlasMessage::ObjectID obj);
virtual bool WantsHighFramerate();
virtual void SetParam(const std::wstring& name, bool value);