forked from 0ad/0ad
Atlas: Camera controls.
Elsewhere: Quaternion stuff. This was SVN commit r2734.
This commit is contained in:
parent
6f90dec78f
commit
599452af85
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 };
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user