Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / motion / modes / free_head.cpp
blob80f0fb21ad1114b898cf3a71c2807dac72412af7
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
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/>.
20 //////////////
21 // Includes //
22 //////////////
23 #include "stdpch.h"
24 // 3D Interface.
25 #include "nel/3d/u_driver.h"
26 #include "nel/3d/u_scene.h"
27 #include "nel/3d/u_camera.h"
28 // Client.
29 #include "input.h"
30 #include "user_controls.h"
31 #include "actions_client.h"
32 #include "user_entity.h"
33 #include "view.h"
34 #include "time_client.h"
35 #include "interface_manager.h"
36 #include "misc.h"
39 ///////////
40 // Using //
41 ///////////
42 using namespace std;
43 using namespace NLMISC;
44 using namespace NL3D;
47 /////////////
48 // Externs //
49 /////////////
50 extern UDriver *Driver;
51 extern UScene *Scene;
54 ///////////////
55 // Functions //
56 ///////////////
57 //---------------------------------------------------
58 // accelerationFromLengthCoeff :
59 // ...
60 //---------------------------------------------------
61 static float accelerationFromLengthCoeff(float v0, float d0, float coeff)
63 // Whithout acceleration, time to cover d0 at velocity v0 is : to = d0/v0
64 // We want to cover the same distance in to*coeff :
65 // What's the acceleration ?
66 // rq : x = v0*t + 0.5*a*t*t
67 float a = 2*(1-coeff)*v0*v0/(coeff*coeff*d0);
69 return a;
70 }// accelerationFromLengthCoeff //
73 //---------------------------------------------------
74 // turnBack
75 // ...
76 //---------------------------------------------------
77 void CUserControls::turnBack()
79 _T0 = _T;
80 _T = (float)T1*0.001f;
81 float dt = _T-_T0;
83 // turn head
84 if(_TurnBack)
86 if(fabs(_Teta)<Pi/2)
88 _Teta += 4*dt*_TetaCoef*ClientCfg.RotKeySpeedMax;
90 CMatrix mV;
91 mV.rotateZ( 4*dt*_TetaCoef*ClientCfg.RotKeySpeedMax);
92 UserEntity->head((mV * UserEntity->head()).normed());
94 CMatrix mB;
95 mB.rotateZ( 8*dt*_TetaCoef*ClientCfg.RotKeySpeedMax);
96 UserEntity->front((mB * UserEntity->front()).normed());
98 else
100 _TurnBack = false;
101 _PrevTeta = _Teta;
102 _Teta = 0;
105 }// turnBack //
108 //---------------------------------------------------
109 // updateCursorPosition :
110 // Update the cursor position.
111 //---------------------------------------------------
112 void CUserControls::updateCursorPosition()
114 float angle;
116 // Updating _CursorX
117 //==================
118 float cosinus = UserEntity->head()*UserEntity->front();
119 if(cosinus>1)
121 cosinus = 1;
123 if(cosinus<-1)
125 cosinus = -1;
127 angle = (float) acos(cosinus);
128 // the cross product gives the angle's sign
129 CVector temp = UserEntity->head()^UserEntity->front();
130 if(temp.z<0)
132 angle = -angle;
134 if(_UpdateView)
136 angle = -angle;
139 _CursorX = (float)( angle/Pi + 0.5f );
142 // Updating _CursorY
143 //==================
144 angle = 0; // pitch(); // TODO.
145 if(angle>=0)
147 // up look range : Pi/2
148 // |_
150 _CursorY = (float)( angle/Pi + 0.5f );
152 else
154 // down look range : Pi/4 _
155 // \
157 _CursorY = (float)( 2*angle/Pi + 0.5f );
159 }// updateCursorPosition //
162 //---------------------------------------------------
163 // updateViewHeading :
164 // ...
165 //---------------------------------------------------
166 void CUserControls::updateViewHeading()
168 if(_UpdateView)
170 // At first step _Teta==_PrevTeta
171 // _Teta always >=0 and decreasing as getting closer of bodyheading
172 if(_Teta-_PrevTeta <= 0)
174 if(_Teta<(float)Pi/12 && _T0View==0)
176 _T0View = (float)T1*0.001f;
178 if(_T0View!=0)
180 _TView = (float)T1*0.001f;
181 float acc = accelerationFromLengthCoeff(1,_Teta,2); //length is twice
182 float tmpSpeed = _ViewSpeed;
183 _ViewSpeed += acc*(_TView-_T0View);
184 if(_ViewSpeed<=0)
186 _ViewSpeed = tmpSpeed;
191 _PrevTeta = _Teta;
192 CMatrix m;
193 m.identity();
194 m.rotateZ( DT*_TetaCoef*_ViewSpeed );
195 UserEntity->head((m * UserEntity->head()).normed());
196 _Teta = (float) fabs(acos(UserEntity->front()*UserEntity->head()));
197 if(_Teta-_PrevTeta > 0)
199 _UpdateView = false;
200 UserEntity->head(UserEntity->front());
201 _PrevTeta = _Teta;
202 _Teta = 0;
203 _T0View = 0;
207 }// updateViewHeading //
210 //---------------------------------------------------
211 // findDestination :
212 // Calculate the destination point.
213 //---------------------------------------------------
214 void CUserControls::findDestination(float x, float y)
216 uint32 width, height;
217 Driver->getWindowSize(width, height);
219 uint32 mx = (uint32)(x*width);
220 uint32 my = (uint32)(y*height);
222 // Get zbuffer corresponding to the cursor position.
223 CRect rect(mx,my,1,1);
224 vector<float> zbuffer;
225 Driver->getZBufferPart(zbuffer, rect);
227 // If the part of the zbuffer is empty -> return.
228 if(zbuffer.size()==0)
229 return;
231 // Get the destination position.
232 UCamera camera = Scene->getCam();
233 camera.setTransformMode(UTransform::DirectMatrix);
234 CMatrix cam = camera.getMatrix();
235 CFrustum fst = camera.getFrustum();
236 _Destination = CVector(x,y,zbuffer[0]);
237 _Destination = fst.unProject(_Destination);
238 _Destination = cam * _Destination;
239 // Get the star position.
240 _Start = UserEntity->pos();
242 // path
243 CVector path = _Destination-_Start;
245 // If the distance is too far -> do not move the character.
246 if(path.norm() > 10)
247 return;
249 _Acc = 0;
250 _T0 = 0;
251 _TransSpeed = _V0;
252 _TurnBack = false;
253 _Dist = -1;
255 // Update body heading.
256 path.z = 0;
257 UserEntity->front(path.normed());
259 // Teta : abs value of angle between future view heading and current body heading
260 _UpdateView = true;
261 _Teta = (float) fabs(acos(UserEntity->front()*UserEntity->head()));
262 _PrevTeta = _Teta;
263 if(x>0.5f)
264 _TetaCoef = -1;
265 else if(x<0.5f)
266 _TetaCoef = 1;
267 else
268 _TetaCoef = 0;
270 // speed for updating view
271 _ViewSpeed = 1;
273 // go
274 UserEntity->frontVelocity( _TransSpeed );
275 _ClickMove = true;
276 }// findDestination //
279 //-----------------------------------------------
280 // freeHeadModeStart :
281 // Manage interactions in free head mode (start).
282 //-----------------------------------------------
283 void CUserControls::freeHeadModeStart()
285 // Get the interface instace.
286 CInterfaceManager *instance = CInterfaceManager::getInstance();
287 if(instance == 0)
288 return;
290 // Get the cursor instance
291 CViewPointer *cursor = instance->getPointer();
292 if(cursor == 0)
293 return;
295 // Mouse free look
296 SetMouseFreeLook ();
298 updateCursorPosition();
299 }// freeHeadModeStart //
301 //-----------------------------------------------
302 // freeHeadModeStop :
303 // Manage interactions in free head mode (stop).
304 //-----------------------------------------------
305 void CUserControls::freeHeadModeStop()
307 }// freeHeadModeStop //
309 //-----------------------------------------------
310 // freeHeadMode :
311 // Manage interactions in free head mode.
312 //-----------------------------------------------
313 void CUserControls::freeHeadMode()
315 // Left Mouse Button.
316 if(Actions.isMouseButtonReleased (leftButton))
317 UserEntity->head(UserEntity->front());
319 // Left Mouse Button.
320 if(Actions.isMouseButtonReleased (rightButton))
321 mode(_LastMode);
323 if (EventsListener.isMouseAngleX())
325 // If the mouse move on the axis X.
326 UserEntity->rotHeadHorizontally(-Actions.getMouseAngleX ());
329 if (EventsListener.isMouseAngleY())
331 // Mouse Angle Y
332 UserEntity->rotHeadVertically(Actions.getMouseAngleY ());
335 // Right / Left rotation
336 float accel = 0;
337 bool left = Actions.valide("strafe_left");
338 bool right = Actions.valide("strafe_right");
339 if (left || right)
341 if (left)
343 accel += ClientCfg.RotAccel;
344 _RotateVelocity = std::max (_RotateVelocity, ClientCfg.RotKeySpeedMin);
347 if (right)
349 accel -= ClientCfg.RotAccel;
350 _RotateVelocity = std::min (_RotateVelocity, -ClientCfg.RotKeySpeedMin);
352 updateVelocity (DT, accel, ClientCfg.RotAccel, ClientCfg.RotKeySpeedMax, _RotateVelocity);
353 UserEntity->rotHeadHorizontally(DT*_RotateVelocity);
356 updateCursorPosition();
358 // Up / Down rotation
359 accel = 0;
360 bool up = Actions.valide("look_up");
361 bool down = Actions.valide("look_down");
362 if (up || down)
364 if (up)
366 accel += ClientCfg.RotAccel;
367 _RotateVerticalVelocity = std::max (_RotateVerticalVelocity, ClientCfg.RotKeySpeedMin);
370 if (down)
372 accel -= ClientCfg.RotAccel;
373 _RotateVerticalVelocity = std::min (_RotateVerticalVelocity, -ClientCfg.RotKeySpeedMin);
375 updateVelocity (DT, accel, ClientCfg.RotAccel, ClientCfg.RotKeySpeedMax, _RotateVerticalVelocity);
376 UserEntity->rotHeadVertically(DT*ClientCfg._RotateVerticalVelocity);
379 // Auto-walk
380 // (rq : is disabled by forward/backward keyboard action )
381 if(Actions.begin("toggle_auto_walk"))
382 _DirectionMove ^= autowalk;
384 // Action "Foraward" is valide -> Autowalk false, forward true.
385 if(Actions.valide("forward"))
387 _DirectionMove |= forward;
388 _DirectionMove &= ~autowalk;
391 // Action "backward" is valide -> Autowalk false, backward true.
392 if(Actions.valide("backward"))
394 _DirectionMove |= backward;
395 _DirectionMove &= ~autowalk;
398 if( !isSit() )
400 // Action "strafe_left" is valide -> strafeLeft true.
401 if(Actions.valide("turn_left"))
402 _DirectionMove |= left;
404 // Action "strafe_right" is valide -> strafeRight true.
405 if(Actions.valide("turn_right"))
406 _DirectionMove |= right;
409 // if there's no move due to a click
410 if(_ClickMove==false)
412 move();
414 // Turn-back
415 //==========
416 const float margin = 0.006f;
417 if(UserEntity->frontVelocity()==0)
419 if(!_TurnBack)
421 if(_CursorX < margin)
423 _TetaCoef = 1;
424 _TurnBack = true;
425 _Teta = 0;
426 _T0 = (float)T1*0.001f;
427 _T = (float)T1*0.001f;
430 if(_CursorX > 1-margin)
432 _TetaCoef = -1;
433 _TurnBack = true;
434 _Teta = 0;
435 _T0 = (float)T1*0.001f;
436 _T = (float)T1*0.001f;
441 if(_TurnBack)
442 turnBack();
444 else if(UserEntity->frontVelocity() != 0 )
446 CVector tmp = _Destination-UserEntity->pos();
447 _PrevDist = _Dist;
448 _Dist = (float)sqrt(tmp.x*tmp.x + tmp.y*tmp.y);
450 if(_Dist>=_PrevDist && _PrevDist!=-1)
452 _Dist = -1;
453 UserEntity->frontVelocity(0);
454 _T0 = 0;
455 _T = 0;
456 _Acc = 0;
457 _TransSpeed = _V0;
458 _ClickMove = false;
460 else
462 float remainingDist = (_Destination-UserEntity->pos()).norm();
463 float totalDist = (_Destination-_Start).norm();
464 if(remainingDist<totalDist*20.f/100 && _Acc==0)
466 _T0 = (float)T1*0.001f;
467 _T = _T0;
468 _V0 = _TransSpeed;
471 if(_T0!=0)
473 if(_Acc == 0)
475 _Acc = accelerationFromLengthCoeff(_V0,remainingDist,2); //length is twice
477 else // _Acc!=0
479 _T = (float)T1*0.001f;
480 _TransSpeed = _V0 + _Acc*(_T-_T0);
481 if(_TransSpeed>=0)
483 UserEntity->frontVelocity(_TransSpeed);
488 float time = (float)T1*0.001f;
489 // we suppose : 2 step in one second (one step <-> one period(2Pi))
490 // origin's phase : -Pi/2
491 // +1 to have only positive values
492 // amplitude is 5 centimeters at velocity 3.33 (sin+1 is between 0 and 2(->2m))
493 _ZOscil = (float) (sin(2*Pi*2*(time-_StartTime) -Pi/2) + 1 )*(0.05f*_TransSpeed/(3.333333f*2));
494 _ZOscil *= (UserEntity->front())*UserEntity->head();
498 updateViewHeading();
500 // Set the view.
501 View.viewPos(UserEntity->pos() + CVector(0,0, UserEntity->eyesHeight()) + CVector(0,0,_ZOscil));
502 View.view(UserEntity->head());
503 }// freeHeadMode //