218 lines
5.5 KiB
C++
218 lines
5.5 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program 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 Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
#include "std_afx.h"
|
|
#include "object_viewer.h"
|
|
#include "direction_edit.h"
|
|
#include "direction_attr.h"
|
|
#include "popup_notify.h"
|
|
|
|
#include "nel/misc/vector.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CDirectionEdit dialog
|
|
|
|
|
|
CDirectionEdit::CDirectionEdit(IPSWrapper<NLMISC::CVector> *wrapper)
|
|
: _Wrapper(wrapper), _MouseState(CDirectionEdit::Wait)
|
|
|
|
{
|
|
nlassert(wrapper);
|
|
//{{AFX_DATA_INIT(CDirectionEdit)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
}
|
|
|
|
|
|
void CDirectionEdit::init(IPopupNotify *pn, CWnd *pParent)
|
|
{
|
|
Create(IDD_DIRECTION_EDIT, pParent);
|
|
_Parent = pn;
|
|
ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
|
|
void CDirectionEdit::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CDirectionEdit)
|
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CDirectionEdit, CDialog)
|
|
//{{AFX_MSG_MAP(CDirectionEdit)
|
|
ON_WM_PAINT()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_CLOSE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
// private : draw a basis with the given letters
|
|
static void DrawBasis(CDC &dc, sint x, sint y, sint size, const char *xStr, const char *yStr)
|
|
{
|
|
dc.FillSolidRect(x, y, size, size, 0xffffff);
|
|
|
|
CPen p;
|
|
p.CreatePen(PS_SOLID, 1, (COLORREF) 0);
|
|
|
|
CPen *oldPen = dc.SelectObject(&p);
|
|
|
|
dc.MoveTo(x + 5, y + size / 2);
|
|
dc.LineTo(x + size - 5, y + size / 2);
|
|
dc.MoveTo(x + size / 2, y + 5);
|
|
dc.LineTo(x + size / 2, y + size - 5);
|
|
|
|
dc.TextOut(x + size - 20, y + size / 2 - 18, CString(xStr));
|
|
dc.TextOut(x + 5 + size / 2, y + 5, CString(yStr));
|
|
|
|
dc.SelectObject(oldPen);
|
|
}
|
|
|
|
|
|
/// private : draw a vector in a basis
|
|
static void DrawVector(CDC &dc, float vx, float vy, sint x, sint y, sint size)
|
|
{
|
|
CPen p;
|
|
p.CreatePen(PS_SOLID, 1, (COLORREF) 0xff);
|
|
CPen *oldPen = dc.SelectObject(&p);
|
|
|
|
dc.MoveTo(x + size / 2, y + size / 2);
|
|
dc.LineTo(int(x + size / 2 + vx * 0.9f * size / 2), int(y + size / 2 - vy * 0.9f * size / 2));
|
|
|
|
dc.SelectObject(oldPen);
|
|
|
|
}
|
|
|
|
// size in pixel of the basis that is drawn in the dialog
|
|
const uint32 BasisSize = 120;
|
|
|
|
// the gap between 2 basis on the screen
|
|
const uint32 BasisGap = 20;
|
|
|
|
// the distance to the upper left corner for the basis drawing
|
|
const uint CornerDist = 10;
|
|
|
|
|
|
|
|
|
|
/// private get back a screen coord (pox, py) to a part of a vector. The basis of click is (x, y) - (x + size, y + size)
|
|
static void ScreenToVect(float &vx, float &vy, sint px, sint py, sint x, sint y, sint size)
|
|
{
|
|
vx = (px - (x + size / 2)) / 0.9f;
|
|
vy = ((y + size / 2) - py) / 0.9f;
|
|
}
|
|
|
|
void CDirectionEdit::OnPaint()
|
|
{
|
|
CPaintDC dc(this);
|
|
|
|
// get the current vector;
|
|
NLMISC::CVector v = _Wrapper->get();
|
|
|
|
|
|
// draw a white square, and draw the vector in it
|
|
|
|
DrawBasis(dc, CornerDist, CornerDist, BasisSize, "X", "Z");
|
|
DrawVector(dc, v.x, v.z, CornerDist, CornerDist, BasisSize);
|
|
|
|
DrawBasis(dc, CornerDist, CornerDist + BasisGap + BasisSize, BasisSize, "Y", "Z");
|
|
DrawVector(dc, v.y, v.z, CornerDist, CornerDist + BasisGap + BasisSize, BasisSize);
|
|
|
|
}
|
|
|
|
void CDirectionEdit::selectNewVect(const CPoint &point)
|
|
{
|
|
const float epsilon = 10E-3f;
|
|
NLMISC::CVector v = _Wrapper->get();
|
|
if (point.x > CornerDist && point.y > CornerDist && point.x < (CornerDist + BasisSize) && point.y < (CornerDist + BasisSize))
|
|
{
|
|
ScreenToVect(v.x, v.z, point.x, point.y, CornerDist, CornerDist, BasisSize);
|
|
float d = v.x * v.x + v.z * v.z;
|
|
float f;
|
|
if (fabsf(d > epsilon))
|
|
{
|
|
f = sqrtf((1.f - v.y * v.y) / d);
|
|
}
|
|
else
|
|
{
|
|
f = 1;
|
|
}
|
|
|
|
v.x *= f;
|
|
v.z *= f;
|
|
}
|
|
|
|
if (point.x > CornerDist && point.y > (BasisGap + BasisSize + CornerDist) && point.x < (CornerDist + BasisSize) && point.y < (CornerDist + BasisGap + 2 * BasisSize))
|
|
{
|
|
ScreenToVect(v.y, v.z, point.x, point.y, CornerDist, CornerDist + BasisGap + BasisSize, BasisSize);
|
|
float d = v.y * v.y + v.z * v.z;
|
|
float f;
|
|
if (fabsf(d > epsilon))
|
|
{
|
|
f = sqrtf((1.f - v.x * v.x) / d);
|
|
}
|
|
else
|
|
{
|
|
f = 1;
|
|
}
|
|
|
|
v.y *= f;
|
|
v.z *= f;
|
|
}
|
|
|
|
v.normalize();
|
|
_Wrapper->setAndUpdateModifiedFlag(v);
|
|
|
|
Invalidate();
|
|
|
|
}
|
|
|
|
void CDirectionEdit::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
selectNewVect(point);
|
|
_MouseState = Drag;
|
|
CDialog::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CDirectionEdit::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
if (_MouseState == Drag)
|
|
{
|
|
selectNewVect(point);
|
|
|
|
}
|
|
CDialog::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
void CDirectionEdit::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
_MouseState = Wait;
|
|
CDialog::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
|
|
void CDirectionEdit::OnClose()
|
|
{
|
|
nlassert(_Parent);
|
|
CDialog::OnClose();
|
|
_Parent->childPopupClosed(this);
|
|
}
|