1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
25 #include "nel/3d/u_driver.h"
26 #include "nel/3d/u_scene.h"
27 #include "nel/3d/u_camera.h"
30 #include "user_controls.h"
31 #include "actions_client.h"
32 #include "user_entity.h"
34 #include "time_client.h"
35 #include "interface_manager.h"
43 using namespace NLMISC
;
50 extern UDriver
*Driver
;
57 //---------------------------------------------------
58 // accelerationFromLengthCoeff :
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
);
70 }// accelerationFromLengthCoeff //
73 //---------------------------------------------------
76 //---------------------------------------------------
77 void CUserControls::turnBack()
80 _T
= (float)T1
*0.001f
;
88 _Teta
+= 4*dt
*_TetaCoef
*ClientCfg
.RotKeySpeedMax
;
91 mV
.rotateZ( 4*dt
*_TetaCoef
*ClientCfg
.RotKeySpeedMax
);
92 UserEntity
->head((mV
* UserEntity
->head()).normed());
95 mB
.rotateZ( 8*dt
*_TetaCoef
*ClientCfg
.RotKeySpeedMax
);
96 UserEntity
->front((mB
* UserEntity
->front()).normed());
108 //---------------------------------------------------
109 // updateCursorPosition :
110 // Update the cursor position.
111 //---------------------------------------------------
112 void CUserControls::updateCursorPosition()
118 float cosinus
= UserEntity
->head()*UserEntity
->front();
127 angle
= (float) acos(cosinus
);
128 // the cross product gives the angle's sign
129 CVector temp
= UserEntity
->head()^UserEntity
->front();
139 _CursorX
= (float)( angle
/Pi
+ 0.5f
);
144 angle
= 0; // pitch(); // TODO.
147 // up look range : Pi/2
150 _CursorY
= (float)( angle
/Pi
+ 0.5f
);
154 // down look range : Pi/4 _
157 _CursorY
= (float)( 2*angle
/Pi
+ 0.5f
);
159 }// updateCursorPosition //
162 //---------------------------------------------------
163 // updateViewHeading :
165 //---------------------------------------------------
166 void CUserControls::updateViewHeading()
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
;
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
);
186 _ViewSpeed
= tmpSpeed
;
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)
200 UserEntity
->head(UserEntity
->front());
207 }// updateViewHeading //
210 //---------------------------------------------------
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)
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();
243 CVector path
= _Destination
-_Start
;
245 // If the distance is too far -> do not move the character.
255 // Update body heading.
257 UserEntity
->front(path
.normed());
259 // Teta : abs value of angle between future view heading and current body heading
261 _Teta
= (float) fabs(acos(UserEntity
->front()*UserEntity
->head()));
270 // speed for updating view
274 UserEntity
->frontVelocity( _TransSpeed
);
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();
290 // Get the cursor instance
291 CViewPointer
*cursor
= instance
->getPointer();
298 updateCursorPosition();
299 }// freeHeadModeStart //
301 //-----------------------------------------------
302 // freeHeadModeStop :
303 // Manage interactions in free head mode (stop).
304 //-----------------------------------------------
305 void CUserControls::freeHeadModeStop()
307 }// freeHeadModeStop //
309 //-----------------------------------------------
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
))
323 if (EventsListener
.isMouseAngleX())
325 // If the mouse move on the axis X.
326 UserEntity
->rotHeadHorizontally(-Actions
.getMouseAngleX ());
329 if (EventsListener
.isMouseAngleY())
332 UserEntity
->rotHeadVertically(Actions
.getMouseAngleY ());
335 // Right / Left rotation
337 bool left
= Actions
.valide("strafe_left");
338 bool right
= Actions
.valide("strafe_right");
343 accel
+= ClientCfg
.RotAccel
;
344 _RotateVelocity
= std::max (_RotateVelocity
, ClientCfg
.RotKeySpeedMin
);
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
360 bool up
= Actions
.valide("look_up");
361 bool down
= Actions
.valide("look_down");
366 accel
+= ClientCfg
.RotAccel
;
367 _RotateVerticalVelocity
= std::max (_RotateVerticalVelocity
, ClientCfg
.RotKeySpeedMin
);
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
);
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
;
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)
416 const float margin
= 0.006f
;
417 if(UserEntity
->frontVelocity()==0)
421 if(_CursorX
< margin
)
426 _T0
= (float)T1
*0.001f
;
427 _T
= (float)T1
*0.001f
;
430 if(_CursorX
> 1-margin
)
435 _T0
= (float)T1
*0.001f
;
436 _T
= (float)T1
*0.001f
;
444 else if(UserEntity
->frontVelocity() != 0 )
446 CVector tmp
= _Destination
-UserEntity
->pos();
448 _Dist
= (float)sqrt(tmp
.x
*tmp
.x
+ tmp
.y
*tmp
.y
);
450 if(_Dist
>=_PrevDist
&& _PrevDist
!=-1)
453 UserEntity
->frontVelocity(0);
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
;
475 _Acc
= accelerationFromLengthCoeff(_V0
,remainingDist
,2); //length is twice
479 _T
= (float)T1
*0.001f
;
480 _TransSpeed
= _V0
+ _Acc
*(_T
-_T0
);
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();
501 View
.viewPos(UserEntity
->pos() + CVector(0,0, UserEntity
->eyesHeight()) + CVector(0,0,_ZOscil
));
502 View
.view(UserEntity
->head());