Added aqua_speed for rite geo 50 tryker
[ryzomcore.git] / nel / tools / 3d / object_viewer / basis_edit.cpp
blob6f4b06065cb9dfe6da6f590c58db3305466e3ec9
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std_afx.h"
18 #include "object_viewer.h"
19 #include "basis_edit.h"
20 #include "nel/misc/matrix.h"
21 #include "nel/misc/vector.h"
23 /////////////////////////////////////////////////////////////////////////////
24 // CBasisEdit dialog
27 CBasisEdit::CBasisEdit(CWnd* pParent /*=NULL*/)
29 //{{AFX_DATA_INIT(CBasisEdit)
30 m_Psi = 0;
31 m_Theta = 0;
32 m_Phi = 0;
33 //}}AFX_DATA_INIT
37 void CBasisEdit::DoDataExchange(CDataExchange* pDX)
39 CDialog::DoDataExchange(pDX);
40 //{{AFX_DATA_MAP(CBasisEdit)
41 DDX_Control(pDX, IDC_PHI_SCROLLBAR, m_PhiCtrl);
42 DDX_Control(pDX, IDC_PSI_SCROLLBAR, m_PsiCtrl);
43 DDX_Control(pDX, IDC_THETA_SCROLLBAR, m_ThetaCtrl);
44 DDX_Text(pDX, IDC_PSI_VALUE, m_Psi);
45 DDX_Text(pDX, IDC_THETA_VALUE, m_Theta);
46 DDX_Text(pDX, IDC_PHI_VALUE, m_Phi);
47 //}}AFX_DATA_MAP
51 BEGIN_MESSAGE_MAP(CBasisEdit, CDialog)
52 //{{AFX_MSG_MAP(CBasisEdit)
53 ON_WM_PAINT()
54 ON_WM_HSCROLL()
55 //}}AFX_MSG_MAP
56 END_MESSAGE_MAP()
58 /////////////////////////////////////////////////////////////////////////////
59 // CBasisEdit message handlers
65 void CBasisEdit::init(uint32 x, uint32 y, CWnd *pParent)
67 nlassert(_Wrapper); // _Wrapper should have been set before init !!
68 Create(IDD_BASIS_EDIT, pParent);
69 RECT r;
70 GetClientRect(&r);
72 m_PsiCtrl.SetScrollRange(0, 359);
73 m_ThetaCtrl.SetScrollRange(0, 359);
74 m_PhiCtrl.SetScrollRange(0, 359);
76 MoveWindow(x, y, r.right, r.bottom);
77 updateAnglesFromReader();
78 ShowWindow(SW_SHOW);
79 UpdateData(FALSE);
86 // build an euler matrix
87 NLMISC::CMatrix BuildEulerMatrix(float psi, float theta, float phi)
89 float ca = cosf(psi), sa = sinf(psi)
90 , cb = cosf(theta), sb = sinf(theta)
91 , cc = cosf(phi), sc = sinf(phi);
92 NLMISC::CMatrix m;
93 m.identity();
94 m.setRot(NLMISC::CVector(ca * cb * cc - sa * sc, -cc * sa - ca * cb *sc, ca * sb)
95 ,NLMISC::CVector(cb * cc * sa + ca * sc, ca * cc - cb * sa * sc, sa *sb)
96 ,NLMISC::CVector(-cc * sb, sb * sc, cb)
98 return m;
101 // get back the euler angles from a matrix
102 NLMISC::CVector GetEulerAngles(const NLMISC::CMatrix &mat)
104 float m[3][3];
105 // we got cos theta = m33
106 NLMISC::CVector v[3];
107 mat.getRot(v[0], v[1], v[2]);
108 for (uint l = 0; l < 3; ++l)
110 m[0][l] = v[l].x; m[1][l] = v[l].y; m[2][l] = v[l].z;
113 // there are eight triplet that may satisfy the equation
114 // we compute them all, and test them against the matrix
116 float b0, b1, a0, a1, a2, a3, c0, c1, c2, c3;
117 b0 = acosf(m[2][2]);
118 b1 = (float) NLMISC::Pi - b0;
119 float sb0 = sinf(b0), sb1 = sinf(b1);
120 if (fabsf(sb0) > 10E-6)
122 a0 = m[2][0] / sb0;
123 c0 = m[1][2] / sb0;
125 else
127 a0 = c0 = 1.f;
129 if (fabs(sb1) > 10E-6)
131 a1 = m[2][0] / sb1;
132 c1 = m[1][2] / sb1;
134 else
136 a1 = c1 = 1.f;
140 a2 = (float) NLMISC::Pi - a0;
141 a3 = (float) NLMISC::Pi - a1;
144 c2 = (float) NLMISC::Pi - c0;
145 c3 = (float) NLMISC::Pi - c1;
147 NLMISC::CVector sol[] =
149 NLMISC::CVector(b0, a0, c0)
150 ,NLMISC::CVector(b0, a2, c0)
151 ,NLMISC::CVector(b0, a0, c2)
152 ,NLMISC::CVector(b0, a2, c2)
153 ,NLMISC::CVector(b1, a1, c1)
154 ,NLMISC::CVector(b1, a3, c1)
155 ,NLMISC::CVector(b1, a1, c3)
156 ,NLMISC::CVector(b1, a3, c3)
159 // now we take the triplet that fit best the 6 other equations
161 float bestGap = 0.f;
162 uint bestIndex;
164 for (uint k = 0; k < 8; ++k)
166 float ca = cosf(sol[k].x), sa = sinf(sol[k].x)
167 , cb = cosf(sol[k].y), sb = sinf(sol[k].y)
168 , cc = cosf(sol[k].z), sc = sinf(sol[k].z);
170 float gap = fabsf(m[0][0] - ca * cb * cc + sa * sc);
171 gap += fabsf(m[1][0] + cc * sa + ca * cb *sc);
172 gap += fabsf(m[0][1] - cb * cc * sa - ca * sc);
173 gap += fabsf(m[0][1] - cb * cc * sa - ca * sc);
174 gap += fabsf(m[1][1] - ca * cc + cb * sa * sc);
175 gap += fabsf(m[2][1] - sb *ca);
176 gap += fabsf(m[0][2] + cc * sb);
178 if (k == 0 || gap < bestGap)
180 bestGap = gap;
181 bestIndex = k;
185 return sol[bestIndex];
190 void CBasisEdit::updateAnglesFromReader()
192 nlassert(_Wrapper); // _Wrapper should have been set before init !!
194 // read plane basis
195 NL3D::CPlaneBasis pb = _Wrapper->get();
196 NLMISC::CMatrix mat;
197 mat.setRot(pb.X, pb.Y, pb.X ^ pb.Y);
198 NLMISC::CVector angles = GetEulerAngles(mat);
199 m_PsiCtrl.SetScrollPos((uint) (360.f * angles.x / (2.f * (float) NLMISC::Pi)));
200 m_ThetaCtrl.SetScrollPos((uint) (360.f * angles.y / (2.f * (float) NLMISC::Pi)));
201 m_PhiCtrl.SetScrollPos((uint) (360.f * angles.z / (2.f * (float) NLMISC::Pi)));
202 UpdateData(FALSE);
209 // just project a vector with orthogonal proj
210 static CPoint BasisVectXForm(NLMISC::CVector &v, float size)
212 const float sq = sqrtf(2.f) / 2.f;
213 return CPoint((int) (size * (sq * (v.x + v.y) )), (int) (size * (-v.z + sq * (v.x - v.y))));
216 // draw a basis using the given colors, and hte given dc
218 void DrawBasisInDC(const CPoint &center, float size, const NLMISC::CMatrix &m, CDC &dc, NLMISC::CRGBA col[3])
220 // draw the basis
221 CPoint px = center + BasisVectXForm(m.getI(), size);
222 CPoint py = center + BasisVectXForm(m.getJ(), size);
223 CPoint pz = center + BasisVectXForm(m.getK(), size);
226 CPen p[3];
227 p[0].CreatePen(PS_SOLID, 1, col[0].R + (col[0].G << 8) + (col[0].B << 16) );
228 p[1].CreatePen(PS_SOLID, 1, col[1].R + (col[1].G << 8) + (col[1].B << 16) );
229 p[2].CreatePen(PS_SOLID, 1, col[2].R + (col[2].G << 8) + (col[2].B << 16) );
236 // draw letters indicating each axis
237 // X
238 CPen *old = dc.SelectObject(&p[0]);
239 dc.MoveTo(center);
240 dc.LineTo(px);
241 dc.MoveTo(px + CPoint(2, 2));
242 dc.LineTo(px + CPoint(5, 5));
243 dc.MoveTo(px + CPoint(4, 2));
244 dc.LineTo(px + CPoint(3, 5));
247 // Y
248 dc.SelectObject(&p[1]);
249 dc.MoveTo(center);
250 dc.LineTo(py);
252 dc.MoveTo(py + CPoint(2, 2));
253 dc.LineTo(py + CPoint(4, 4));
254 dc.MoveTo(py + CPoint(4, 2));
255 dc.LineTo(py + CPoint(1, 5));
257 // Z
258 dc.SelectObject(&p[2]);
259 dc.MoveTo(center);
260 dc.LineTo(pz);
262 dc.MoveTo(pz + CPoint(2, 2));
263 dc.LineTo(pz + CPoint(5, 2));
264 dc.MoveTo(pz + CPoint(4, 2));
265 dc.LineTo(pz + CPoint(1, 5));
266 dc.MoveTo(pz + CPoint(2, 4));
267 dc.LineTo(pz + CPoint(5, 4));
269 dc.SelectObject(old);
273 void CBasisEdit::OnPaint()
275 CPaintDC dc(this); // device context for painting
277 NLMISC::CRGBA c1[] ={ NLMISC::CRGBA::White, NLMISC::CRGBA::White, NLMISC::CRGBA::White };
278 NLMISC::CRGBA c2[] ={ NLMISC::CRGBA::Green, NLMISC::CRGBA::Green, NLMISC::CRGBA::Red };
280 if (_Wrapper)
283 // read plane basis
284 NL3D::CPlaneBasis pb = _Wrapper->get();
286 CPoint center(20, 20);
287 // draw a white box on the left
288 dc.FillSolidRect(0, 0, 39, 39, 0x777777);
291 NLMISC::CMatrix m;
292 m.identity();
293 DrawBasisInDC(center, 18, m, dc, c1);
294 m.setRot(pb.X, pb.Y, pb.X ^ pb.Y);
295 DrawBasisInDC(center, 18, m, dc, c2);
299 // Do not call CDialog::OnPaint() for painting messages
302 void CBasisEdit::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
304 UpdateData();
305 if (nSBCode == SB_THUMBPOSITION || nSBCode == SB_THUMBTRACK)
307 NLMISC::CVector angles(2.f * (float) NLMISC::Pi * m_PsiCtrl.GetScrollPos() / 360.f
308 , 2.f * (float) NLMISC::Pi * m_ThetaCtrl.GetScrollPos() / 360.f
309 , 2.f * (float) NLMISC::Pi * m_PhiCtrl.GetScrollPos() / 360.f
311 if (pScrollBar == &m_PsiCtrl)
313 angles.x = 2.f * (float) NLMISC::Pi * nPos / 360.f;
314 m_PsiCtrl.SetScrollPos(nPos);
317 if (pScrollBar == &m_ThetaCtrl)
319 angles.y = 2.f * (float) NLMISC::Pi * nPos / 360.f;
320 m_ThetaCtrl.SetScrollPos(nPos);
323 if (pScrollBar == &m_PhiCtrl)
325 angles.z = 2.f * (float) NLMISC::Pi * nPos / 360.f;
326 m_PhiCtrl.SetScrollPos(nPos);
329 NLMISC::CMatrix mat = BuildEulerMatrix(angles.x, angles.y, angles.z);
330 NL3D::CPlaneBasis pb;
331 pb.X = mat.getI();
332 pb.Y = mat.getJ();
333 _Wrapper->setAndUpdateModifiedFlag(pb);
334 Invalidate();
336 CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
337 UpdateData(FALSE);