Atlas: Camera controls.

Elsewhere: Quaternion stuff.

This was SVN commit r2734.
This commit is contained in:
Ykkrosh 2005-09-15 05:31:49 +00:00
parent 6f90dec78f
commit 599452af85
15 changed files with 379 additions and 47 deletions

View File

@ -473,6 +473,44 @@ void CMatrix3D::Rotate(const CQuaternion& quat)
Concatenate(rotationMatrix);
}
CQuaternion CMatrix3D::GetRotation() const
{
float tr = _data2d[0][0] + _data2d[1][1] + _data2d[2][2];
int next[] = { 1, 2, 0 };
float quat[4];
if (tr > 0.f)
{
float s = sqrtf(tr + 1.f);
quat[3] = s * 0.5f;
s = 0.5f / s;
quat[0] = (_data2d[1][2] - _data2d[2][1]) * s;
quat[1] = (_data2d[2][0] - _data2d[0][2]) * s;
quat[2] = (_data2d[0][1] - _data2d[1][0]) * s;
}
else
{
int i = 0;
if (_data2d[1][1] > _data2d[0][0]) i = 1;
if (_data2d[2][2] > _data2d[i][i]) i = 2;
int j = next[i];
int k = next[j];
float s = sqrtf((_data2d[i][i] - (_data2d[j][j] + _data2d[k][k])) + 1.f);
quat[i] = s * 0.5f;
if (s != 0.f) s = 0.5f / s;
quat[3] = (_data2d[j][k] - _data2d[k][j]) * s;
quat[j] = (_data2d[i][j] + _data2d[j][i]) * s;
quat[k] = (_data2d[i][k] + _data2d[k][i]) * s;
}
return CQuaternion(quat[0], quat[1], quat[2], quat[3]);
}
void CMatrix3D::SetRotation(const CQuaternion& quat)
{
quat.ToMatrix(*this);
@ -506,10 +544,43 @@ static void test_inverse()
}
}
static void test_quats()
{
srand(0);
for (int i = 0; i < 4; ++i)
{
CQuaternion q;
q.FromEulerAngles(
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX),
-6.28f + 12.56f*(rand()/(float)RAND_MAX)
);
CMatrix3D m;
q.ToMatrix(m);
CQuaternion q2 = m.GetRotation();
float epsilon = 0.0001f;
// I hope there's a good reason why they're sometimes negated, and
// it's not just a bug...
bool ok_oneway =
fabs(q2.m_W - q.m_W) < epsilon &&
fabs(q2.m_V.X - q.m_V.X) < epsilon &&
fabs(q2.m_V.Y - q.m_V.Y) < epsilon &&
fabs(q2.m_V.Z - q.m_V.Z) < epsilon;
bool ok_otherway =
fabs(q2.m_W + q.m_W) < epsilon &&
fabs(q2.m_V.X + q.m_V.X) < epsilon &&
fabs(q2.m_V.Y + q.m_V.Y) < epsilon &&
fabs(q2.m_V.Z + q.m_V.Z) < epsilon;
TEST(ok_oneway ^ ok_otherway);
}
}
static void self_test()
{
test_inverse();
test_quats();
}
RUN_SELF_TEST;

View File

@ -13,7 +13,7 @@ class CMatrix3D
{
public:
// the matrix data itself - accessible as either longhand names
// or via a flat array
// or via a flat or 2d array
union {
struct {
float _11, _21, _31, _41;
@ -22,6 +22,8 @@ public:
float _14, _24, _34, _44;
};
float _data[16];
float _data2d[4][4];
// (Be aware that _data2d[3][1] is _13, etc. This is to be considered a feature.)
};
public:
@ -105,6 +107,8 @@ public:
CVector3D GetUp() const;
// return forward vector, derived from rotation
CVector3D GetIn() const;
// return a quaternion representing the matrix's rotation
CQuaternion GetRotation() const;
// transform a 3D vector by this matrix
void Transform(const CVector3D &vector,CVector3D& result) const;

View File

@ -19,8 +19,13 @@ CQuaternion::CQuaternion()
m_W = 1;
}
CQuaternion::CQuaternion(float x, float y, float z, float w)
: m_V(x, y, z), m_W(w)
{
}
//quaternion addition
CQuaternion CQuaternion::operator + (CQuaternion &quat)
CQuaternion CQuaternion::operator + (const CQuaternion &quat) const
{
CQuaternion Temp;
@ -31,7 +36,7 @@ CQuaternion CQuaternion::operator + (CQuaternion &quat)
}
//quaternion addition/assignment
CQuaternion &CQuaternion::operator += (CQuaternion &quat)
CQuaternion &CQuaternion::operator += (const CQuaternion &quat)
{
m_W += quat.m_W;
m_V += quat.m_V;
@ -40,7 +45,7 @@ CQuaternion &CQuaternion::operator += (CQuaternion &quat)
}
//quaternion multiplication
CQuaternion CQuaternion::operator * (CQuaternion &quat)
CQuaternion CQuaternion::operator * (const CQuaternion &quat) const
{
CQuaternion Temp;
@ -51,7 +56,7 @@ CQuaternion CQuaternion::operator * (CQuaternion &quat)
}
//quaternion multiplication/assignment
CQuaternion &CQuaternion::operator *= (CQuaternion &quat)
CQuaternion &CQuaternion::operator *= (const CQuaternion &quat)
{
(*this) = (*this) * quat;
@ -59,7 +64,7 @@ CQuaternion &CQuaternion::operator *= (CQuaternion &quat)
}
void CQuaternion::FromEularAngles (float x, float y, float z)
void CQuaternion::FromEulerAngles (float x, float y, float z)
{
float cr, cp, cy;
float sr, sp, sy;
@ -215,3 +220,19 @@ void CQuaternion::Normalize()
m_W*=invlen;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
CVector3D CQuaternion::Rotate(const CVector3D& vec) const
{
// v' = q * v * q^-1
// (where v is the quat. with w=0, xyz=vec)
return (*this * CQuaternion(vec.X, vec.Y, vec.Z, 0.f) * GetInverse()).m_V;
}
CQuaternion CQuaternion::GetInverse() const
{
float lensqrd = SQR(m_V.X) + SQR(m_V.Y) + SQR(m_V.Z) + SQR(m_W);
return CQuaternion(-m_V.X/lensqrd, -m_V.Y/lensqrd, -m_V.Z/lensqrd, m_W/lensqrd);
}

View File

@ -10,6 +10,7 @@
#define QUATERNION_H
#include "Matrix3D.h"
#include "Vector3D.h"
class CQuaternion
{
@ -19,18 +20,19 @@ public:
public:
CQuaternion();
CQuaternion(float x, float y, float z, float w);
//quaternion addition
CQuaternion operator + (CQuaternion &quat);
CQuaternion operator + (const CQuaternion &quat) const;
//quaternion addition/assignment
CQuaternion &operator += (CQuaternion &quat);
CQuaternion &operator += (const CQuaternion &quat);
//quaternion multiplication
CQuaternion operator * (CQuaternion &quat);
CQuaternion operator * (const CQuaternion &quat) const;
//quaternion multiplication/assignment
CQuaternion &operator *= (CQuaternion &quat);
CQuaternion &operator *= (const CQuaternion &quat);
void FromEularAngles (float x, float y, float z);
void FromEulerAngles (float x, float y, float z);
//convert the quaternion to matrix
CMatrix3D ToMatrix() const;
@ -44,6 +46,12 @@ public:
// normalize this quaternion
void Normalize();
// rotate a vector by this quaternion
CVector3D Rotate(const CVector3D& vec) const;
// calculate q^-1
CQuaternion GetInverse() const;
};
#endif

View File

@ -24,6 +24,11 @@ int CVector3D::operator ! () const
return 1;
}
bool CVector3D::operator== (const CVector3D &vector) const
{
return (X == vector.X && Y == vector.Y && Z == vector.Z);
}
//vector addition
CVector3D CVector3D::operator + (const CVector3D &vector) const
{

View File

@ -30,6 +30,10 @@ class CVector3D
float& operator[](int index) { return *((&X)+index); }
const float& operator[](int index) const { return *((&X)+index); }
//vector equality (testing float equality, so please be careful if necessary)
bool operator== (const CVector3D &vector) const;
bool operator!= (const CVector3D &vector) const { return !operator==(vector); }
//vector addition
CVector3D operator + (const CVector3D &vector) const ;
//vector addition/assignment

View File

@ -25,7 +25,8 @@ class Canvas : public wxGLCanvas
public:
Canvas(wxWindow* parent, int* attribList)
: wxGLCanvas(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS, _T("GLCanvas"), attribList),
m_SuppressResize(true)
m_SuppressResize(true),
m_MouseState(NONE), m_LastMouseState(NONE)
{
}
@ -34,7 +35,7 @@ public:
// Be careful not to send 'resize' messages to the game before we've
// told it that this canvas exists
if (! m_SuppressResize)
ADD_COMMAND(ResizeScreen(GetClientSize().GetWidth(), GetClientSize().GetHeight()));
POST_COMMAND(ResizeScreen(GetClientSize().GetWidth(), GetClientSize().GetHeight()));
// TODO: fix flashing
}
@ -57,18 +58,22 @@ public:
default: return false;
}
float speed = wxGetKeyState(WXK_SHIFT) ? 240.0f : 120.0f;
float speed = 120.f;
if (wxGetKeyState(WXK_SHIFT))
speed *= 4.f;
else if (wxGetKeyState(WXK_CONTROL))
speed /= 4.f;
if (dir == -1) // changed modifier keys - update all currently-scrolling directions
{
if (wxGetKeyState(WXK_LEFT)) ADD_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::LEFT, speed));
if (wxGetKeyState(WXK_RIGHT)) ADD_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::RIGHT, speed));
if (wxGetKeyState(WXK_UP)) ADD_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::FORWARDS, speed));
if (wxGetKeyState(WXK_DOWN)) ADD_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::BACKWARDS, speed));
if (wxGetKeyState(WXK_LEFT)) POST_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::LEFT, speed));
if (wxGetKeyState(WXK_RIGHT)) POST_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::RIGHT, speed));
if (wxGetKeyState(WXK_UP)) POST_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::FORWARDS, speed));
if (wxGetKeyState(WXK_DOWN)) POST_INPUT(ScrollConstant(AtlasMessage::mScrollConstant::BACKWARDS, speed));
}
else
{
ADD_INPUT(ScrollConstant(dir, enable ? speed : 0.0f));
POST_INPUT(ScrollConstant(dir, enable ? speed : 0.0f));
}
return true;
}
@ -96,10 +101,60 @@ public:
void OnMouse(wxMouseEvent& evt)
{
g_CurrentTool->OnMouse(evt);
// TODO: what should happen if the tool and camera both respond to the
// same buttons? (e.g. left+right for rotating)
if (evt.GetWheelRotation())
{
float speed = 16.f;
if (wxGetKeyState(WXK_SHIFT))
speed *= 4.f;
else if (wxGetKeyState(WXK_CONTROL))
speed /= 4.f;
POST_INPUT(SmoothZoom(evt.GetWheelRotation() * speed / evt.GetWheelDelta()));
}
else
{
if (evt.LeftIsDown() && evt.RightIsDown())
m_MouseState = ROTATEAROUND;
else if (evt.MiddleIsDown())
m_MouseState = SCROLL;
else
m_MouseState = NONE;
if (m_MouseState != m_LastMouseState)
{
switch (m_MouseState)
{
case NONE: break;
case SCROLL: POST_INPUT(Scroll(AtlasMessage::mScroll::FROM, evt.GetPosition())); break;
case ROTATEAROUND: POST_INPUT(RotateAround(AtlasMessage::mRotateAround::FROM, evt.GetPosition())); break;
default: wxFAIL;
}
m_LastMouseState = m_MouseState;
}
else if (evt.Dragging())
{
switch (m_MouseState)
{
case NONE: break;
case SCROLL: POST_INPUT(Scroll(AtlasMessage::mScroll::TO, evt.GetPosition())); break;
case ROTATEAROUND: POST_INPUT(RotateAround(AtlasMessage::mRotateAround::TO, evt.GetPosition())); break;
default: wxFAIL;
}
}
}
}
private:
bool m_SuppressResize;
enum { NONE, SCROLL, ROTATEAROUND };
int m_MouseState, m_LastMouseState;
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
@ -107,11 +162,14 @@ BEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
EVT_KEY_DOWN (Canvas::OnKeyDown)
EVT_KEY_UP (Canvas::OnKeyUp)
EVT_LEFT_DOWN (Canvas::OnMouse)
EVT_LEFT_UP (Canvas::OnMouse)
EVT_RIGHT_DOWN(Canvas::OnMouse)
EVT_RIGHT_UP (Canvas::OnMouse)
EVT_MOTION (Canvas::OnMouse)
EVT_LEFT_DOWN (Canvas::OnMouse)
EVT_LEFT_UP (Canvas::OnMouse)
EVT_RIGHT_DOWN (Canvas::OnMouse)
EVT_RIGHT_UP (Canvas::OnMouse)
EVT_MIDDLE_DOWN(Canvas::OnMouse)
EVT_MIDDLE_UP (Canvas::OnMouse)
EVT_MOUSEWHEEL (Canvas::OnMouse)
EVT_MOTION (Canvas::OnMouse)
END_EVENT_TABLE()
// GL functions exported from DLL, and called by game (in a separate
@ -221,7 +279,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
int glAttribList[] = {
WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
WX_GL_DEPTH_SIZE, 24, // TODO: wx documentation doesn't say this is valid
WX_GL_DEPTH_SIZE, 24, // TODO: wx documentation doesn't say 24 is valid
WX_GL_BUFFER_SIZE, 24, // colour bits
WX_GL_MIN_ALPHA, 8, // alpha bits
0
};
Canvas* canvas = new Canvas(splitter, glAttribList);
@ -241,21 +301,25 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
// Send setup messages to game engine:
#ifndef UI_ONLY
ADD_COMMAND(SetContext(canvas->GetContext()));
POST_COMMAND(SetContext(canvas->GetContext()));
ADD_COMMAND(CommandString("init"));
POST_COMMAND(CommandString("init"));
canvas->InitSize();
ADD_COMMAND(GenerateMap(9));
// Start with a blank map (so that the editor can assume there's always
// a valid map loaded)
POST_COMMAND(GenerateMap(9));
ADD_COMMAND(CommandString("render_enable"));
POST_COMMAND(CommandString("render_enable"));
#endif
// XXX
USE_TOOL(AlterElevation);
// Set up a timer to make sure tool-updates happen even when there's no idle time
// Set up a timer to make sure tool-updates happen frequently (in addition
// to the idle handler (which makes then happen more frequently if there's nothing
// else to do))
m_Timer.SetOwner(this);
m_Timer.Start(20);
}
@ -264,9 +328,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
void ScenarioEditor::OnClose(wxCloseEvent&)
{
#ifndef UI_ONLY
ADD_COMMAND(CommandString("shutdown"));
POST_COMMAND(CommandString("shutdown"));
#endif
ADD_COMMAND(CommandString("exit"));
POST_COMMAND(CommandString("exit"));
SetCurrentTool(NULL);
@ -316,7 +380,7 @@ void ScenarioEditor::OnRedo(wxCommandEvent&)
void ScenarioEditor::OnWireframe(wxCommandEvent& event)
{
ADD_COMMAND(RenderStyle(event.IsChecked()));
POST_COMMAND(RenderStyle(event.IsChecked()));
}
//////////////////////////////////////////////////////////////////////////

View File

@ -14,7 +14,7 @@ static void LoadMap()
if (dlg.ShowModal() == wxID_OK)
{
std::wstring map = dlg.GetFilename().c_str();
ADD_COMMAND(LoadMap(map));
POST_COMMAND(LoadMap(map));
}
// TODO: Make this a non-undoable command
@ -22,12 +22,15 @@ static void LoadMap()
static void GenerateMap()
{
ADD_COMMAND(GenerateMap(9));
POST_COMMAND(GenerateMap(9));
}
MapSidebar::MapSidebar(wxWindow* parent)
: Sidebar(parent)
{
// TODO: Less ugliness
// TODO: Intercept arrow keys and send them to the GL window
m_MainSizer->Add(new ActionButton(this, _T("Load existing map"), &LoadMap));
m_MainSizer->Add(new ActionButton(this, _T("Generate empty map"), &GenerateMap));
}

View File

@ -40,10 +40,10 @@ WorldCommand::~WorldCommand()
bool WorldCommand::Do()
{
if (m_AlreadyDone)
ADD_COMMAND(RedoCommand());
POST_COMMAND(RedoCommand());
else
{
ADD_COMMAND(DoCommand(m_Command));
POST_COMMAND(DoCommand(m_Command));
m_AlreadyDone = true;
}
return true;
@ -51,7 +51,7 @@ bool WorldCommand::Do()
bool WorldCommand::Undo()
{
ADD_COMMAND(UndoCommand());
POST_COMMAND(UndoCommand());
return true;
}
@ -68,6 +68,6 @@ bool WorldCommand::Merge(AtlasWindowCommand* p)
if (! m_Command->IsMergeable())
return false;
ADD_COMMAND(MergeCommand());
POST_COMMAND(MergeCommand());
return true;
}

View File

@ -12,9 +12,10 @@ struct GameLoopState
const void* glContext;
float frameLength; // smoothed to avoid large jumps
struct
struct Input
{
float scrollSpeed[4]; // [fwd, bwd, left, right]. 0.0f for disabled.
float zoomDelta;
} input;
};

View File

@ -3,6 +3,11 @@
#include "MessageHandler.h"
#include "../GameLoop.h"
#include "maths/Vector3D.h"
#include "maths/Quaternion.h"
#include "ps/Game.h"
#include "renderer/Renderer.h"
#include <assert.h>
namespace AtlasMessage {
@ -20,4 +25,89 @@ MESSAGEHANDLER(ScrollConstant)
}
}
MESSAGEHANDLER(Scroll)
{
static CVector3D targetPos;
static float targetDistance = 0.f;
CMatrix3D& camera = g_Game->GetView()->GetCamera()->m_Orientation;
static CVector3D lastCameraPos = camera.GetTranslation();
// Ensure roughly correct motion when dragging is combined with other
// movements
if (lastCameraPos != camera.GetTranslation())
targetPos += camera.GetTranslation() - lastCameraPos;
if (msg->type == mScroll::FROM)
{
msg->pos.GetWorldSpace(targetPos);
targetDistance = (targetPos - camera.GetTranslation()).GetLength();
}
else if (msg->type == mScroll::TO)
{
CVector3D origin, dir;
float x, y;
msg->pos.GetScreenSpace(x, y);
g_Game->GetView()->GetCamera()->BuildCameraRay(x, y, origin, dir);
dir *= targetDistance;
camera.Translate(targetPos - dir - origin);
}
else
{
debug_warn("Scroll: Invalid type");
}
lastCameraPos = camera.GetTranslation();
}
MESSAGEHANDLER(SmoothZoom)
{
g_GameLoop->input.zoomDelta += msg->amount;
}
MESSAGEHANDLER(RotateAround)
{
static CVector3D focusPos;
static float lastX = 0.f, lastY = 0.f;
CMatrix3D& camera = g_Game->GetView()->GetCamera()->m_Orientation;
if (msg->type == mRotateAround::FROM)
{
msg->pos.GetScreenSpace(lastX, lastY);
msg->pos.GetWorldSpace(focusPos);
}
else if (msg->type == mRotateAround::TO)
{
float x, y;
msg->pos.GetScreenSpace(x, y);
float rotX = 6.f * (y-lastY) / g_Renderer.GetHeight();
float rotY = 6.f * (x-lastX) / g_Renderer.GetWidth();
// TODO: Stop the camera tilting
CQuaternion q0, q1;
q0.FromAxisAngle(camera.GetLeft(), -rotX);
q1.FromAxisAngle(CVector3D(0.f, 1.f, 0.f), rotY);
CQuaternion q = q0*q1;
CVector3D origin = camera.GetTranslation();
CVector3D offset = q.Rotate(origin - focusPos);
q *= camera.GetRotation();
q.Normalize(); // to avoid things blowing up for some reason when turning upside-down
q.ToMatrix(camera);
camera.Translate(focusPos + offset);
lastX = x;
lastY = y;
}
else
{
debug_warn("RotateAround: Invalid type");
}
}
}

View File

@ -5,6 +5,8 @@
#include "ps/Game.h"
#include "graphics/Camera.h"
static float g_ViewZoomSmoothness = 0.02f; // TODO: configurable, like GameView
bool InputProcessor::ProcessInput(GameLoopState* state)
{
if (! g_Game)
@ -14,8 +16,10 @@ bool InputProcessor::ProcessInput(GameLoopState* state)
CVector3D leftwards = camera->m_Orientation.GetLeft();
CVector3D inwards = camera->m_Orientation.GetIn();
// Calculate a vector pointing forwards, parallel to the ground
CVector3D forwards = camera->m_Orientation.GetIn();
CVector3D forwards = inwards;
forwards.Y = 0.0f;
if (forwards.GetLength() < 0.001f) // be careful if the camera is looking straight down
forwards = CVector3D(1.f, 0.f, 0.f);
@ -24,27 +28,41 @@ bool InputProcessor::ProcessInput(GameLoopState* state)
bool moved = false;
GameLoopState::Input& input = state->input;
if (state->input.scrollSpeed[0] != 0.0f)
{
camera->m_Orientation.Translate(forwards * (state->input.scrollSpeed[0] * state->frameLength));
camera->m_Orientation.Translate(forwards * (input.scrollSpeed[0] * state->frameLength));
moved = true;
}
if (state->input.scrollSpeed[1] != 0.0f)
{
camera->m_Orientation.Translate(forwards * (-state->input.scrollSpeed[1] * state->frameLength));
camera->m_Orientation.Translate(forwards * (-input.scrollSpeed[1] * state->frameLength));
moved = true;
}
if (state->input.scrollSpeed[2] != 0.0f)
{
camera->m_Orientation.Translate(leftwards * (state->input.scrollSpeed[2] * state->frameLength));
camera->m_Orientation.Translate(leftwards * (input.scrollSpeed[2] * state->frameLength));
moved = true;
}
if (state->input.scrollSpeed[3] != 0.0f)
{
camera->m_Orientation.Translate(leftwards * (-state->input.scrollSpeed[3] * state->frameLength));
camera->m_Orientation.Translate(leftwards * (-input.scrollSpeed[3] * state->frameLength));
moved = true;
}
if (state->input.zoomDelta != 0.0f)
{
float zoom_proportion = powf(g_ViewZoomSmoothness, state->frameLength);
camera->m_Orientation.Translate(inwards * (input.zoomDelta * (1.0f - zoom_proportion)));
input.zoomDelta *= zoom_proportion;
if (fabsf(input.zoomDelta) < 0.1f)
input.zoomDelta = 0.0f;
moved = true;
}

View File

@ -16,8 +16,8 @@ struct mInput;
extern MessagePasser<mCommand>* g_MessagePasser_Command;
extern MessagePasser<mInput>* g_MessagePasser_Input;
#define ADD_COMMAND(type) AtlasMessage::g_MessagePasser_Command->Add(new AtlasMessage::m##type)
#define ADD_INPUT(type) AtlasMessage::g_MessagePasser_Input -> Add(new AtlasMessage::m##type)
#define POST_COMMAND(type) AtlasMessage::g_MessagePasser_Command->Add(new AtlasMessage::m##type)
#define POST_INPUT(type) AtlasMessage::g_MessagePasser_Input -> Add(new AtlasMessage::m##type)
}

View File

@ -28,6 +28,7 @@ struct Position
// 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)
};
@ -82,6 +83,10 @@ const bool NOMERGE = false;
//////////////////////////////////////////////////////////////////////////
// TODO: Make the command definitions less inelegant.
//////////////////////////////////////////////////////////////////////////
COMMAND(CommandString)
mCommandString(const std::string& name_) : name(name_) {}
const std::string name;
@ -127,6 +132,25 @@ INPUT(ScrollConstant)
enum { FORWARDS, BACKWARDS, LEFT, RIGHT };
};
INPUT(Scroll)
mScroll(int type_, Position pos_) : type(type_), pos(pos_) {}
const int type;
const Position pos;
enum { FROM, TO };
};
INPUT(SmoothZoom)
mSmoothZoom(float amount_) : amount(amount_) {}
const float amount;
};
INPUT(RotateAround)
mRotateAround(int type_, Position pos_) : type(type_), pos(pos_) {}
const int type;
const Position pos;
enum { FROM, TO };
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

View File

@ -24,3 +24,22 @@ void AtlasMessage::Position::GetWorldSpace(CVector3D& vec) const
vec.Set(0.f, 0.f, 0.f);
}
}
void AtlasMessage::Position::GetScreenSpace(float& x, float& y) const
{
switch (type)
{
case 0:
g_Game->GetView()->GetCamera()->GetScreenCoordinates(CVector3D(type0.x, type0.y, type0.x), x, y);
break;
case 1:
x = type1.x;
y = type1.y;
break;
default:
debug_warn("Invalid Position type");
x = y = 0.f;
}
}