/* Copyright (C) 2011 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 .
*/
#include "precompiled.h"
#include "ScenarioEditor/ScenarioEditor.h"
#include "Common/Tools.h"
#include "Common/Brushes.h"
#include "Common/MiscState.h"
#include "Common/ObjectSettings.h"
#include "GameInterface/Messages.h"
using AtlasMessage::Position;
// ObjectSidebar handles the display and animation etc of the actor;
// this tool mainly handles the user input and toggling the rendering.
// (There isn't a hugely clear separation of responsibilities.)
class ActorViewerTool : public StateDrivenTool
{
DECLARE_DYNAMIC_CLASS(ActorViewerTool);
// Camera settings
float m_Distance;
float m_Angle;
float m_Elevation;
// Mouse input state
int m_LastX, m_LastY;
bool m_LastIsValid;
public:
ActorViewerTool() :
m_Distance(20.f), m_Angle(0.f), m_Elevation((float)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, (AtlasMessage::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)));
}
virtual void Init(void* initData, ScenarioEditor* scenarioEditor)
{
StateDrivenTool::Init(initData, scenarioEditor);
SetState(&Viewing);
}
void OnEnable()
{
GetScenarioEditor().GetObjectSettings().SetView(AtlasMessage::eRenderView::ACTOR);
std::vector selected;
selected.push_back(0);
g_SelectedObjects = selected;
PostLookAt();
POST_MESSAGE(RenderEnable, (AtlasMessage::eRenderView::ACTOR));
}
void OnDisable()
{
GetScenarioEditor().GetObjectSettings().SetView(AtlasMessage::eRenderView::GAME);
std::vector selected;
g_SelectedObjects = selected;
POST_MESSAGE(RenderEnable, (AtlasMessage::eRenderView::GAME));
}
struct sViewing : public State
{
bool OnMouse(ActorViewerTool* obj, wxMouseEvent& evt)
{
bool camera_changed = false;
if (evt.GetWheelRotation())
{
float speed = -1.f * ScenarioEditor::GetSpeedModifier();
obj->m_Distance += evt.GetWheelRotation() * speed / evt.GetWheelDelta();
camera_changed = true;
}
if (evt.ButtonDown(wxMOUSE_BTN_LEFT) || evt.ButtonDown(wxMOUSE_BTN_RIGHT))
{
obj->m_LastX = evt.GetX();
obj->m_LastY = evt.GetY();
obj->m_LastIsValid = true;
}
else if (evt.Dragging()
&& (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
&& obj->m_LastIsValid)
{
int dx = evt.GetX() - obj->m_LastX;
int dy = evt.GetY() - obj->m_LastY;
obj->m_LastX = evt.GetX();
obj->m_LastY = evt.GetY();
obj->m_Angle += dx * M_PI/256.f * ScenarioEditor::GetSpeedModifier();
if (evt.ButtonIsDown(wxMOUSE_BTN_LEFT))
obj->m_Distance += dy / 8.f * ScenarioEditor::GetSpeedModifier();
else // evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
obj->m_Elevation += dy * M_PI/256.f * ScenarioEditor::GetSpeedModifier();
camera_changed = true;
}
else if ((evt.ButtonUp(wxMOUSE_BTN_LEFT) || evt.ButtonUp(wxMOUSE_BTN_RIGHT))
&& !(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?)
obj->m_LastIsValid = false;
}
obj->m_Distance = std::max(obj->m_Distance, 1/64.f); // don't let people fly through the origin
if (camera_changed)
obj->PostLookAt();
return true;
}
bool OnKey(ActorViewerTool* obj, wxKeyEvent& evt, KeyEventType type)
{
if (type == KEY_DOWN && (evt.GetKeyCode() >= '0' && evt.GetKeyCode() <= '9'))
{
// (TODO: this should probably be 'char' not 'down'; but we don't get
// 'char' unless we return false from this function, in which case the
// scenario editor intercepts some other keys for itself)
int playerID = evt.GetKeyCode() - '0';
obj->GetScenarioEditor().GetObjectSettings().SetPlayerID(playerID);
obj->GetScenarioEditor().GetObjectSettings().NotifyObservers();
}
// Prevent keys from passing through to the scenario editor
return true;
}
}
Viewing;
};
IMPLEMENT_DYNAMIC_CLASS(ActorViewerTool, StateDrivenTool);