6b4c6729f615402631148127e1f38650eadb177a
[platform/core/uifw/dali-demo.git] / examples / fpp-game / game-camera.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include "game-camera.h"
19
20 #include <dali/public-api/common/stage.h>
21 #include <dali/public-api/render-tasks/render-task-list.h>
22 #include <dali/public-api/render-tasks/render-task.h>
23 #include <dali/public-api/events/touch-data.h>
24 #include <dali/public-api/events/touch-event.h>
25
26 using namespace Dali;
27
28 namespace
29 {
30 // Input sensitivity, the larger value, the more sensitive input
31 // Default value has been chosen empirically
32 const float   CAMERA_SENSITIVITY        ( 90.0f );
33
34 // Vertical angle limit of the camera
35 const float   CAMERA_VERTICAL_LIMIT     ( 80.0f );
36
37 // Position where camera is instantiated by default
38 const Vector3 CAMERA_DEFAULT_POSITION   ( 1.0f, -1.5f, -3.0f );
39
40 // Field-of-View in degrees
41 const float   CAMERA_DEFAULT_FOV        ( 60.0f );
42
43 // Near plane
44 const float   CAMERA_DEFAULT_NEAR       ( 0.1f );
45
46 // Far plane
47 const float   CAMERA_DEFAULT_FAR        ( 100.0f );
48
49 // Default forward vector
50 const Vector3 CAMERA_FORWARD            ( 0.0f, 0.0f, 1.0f );
51
52 // Default up vector
53 const Vector3 CAMERA_UP                 ( Vector3::YAXIS );
54 }
55
56 GameCamera::GameCamera()
57 : mFovY( CAMERA_DEFAULT_FOV ),
58   mNear( CAMERA_DEFAULT_NEAR ),
59   mFar( CAMERA_DEFAULT_FAR ),
60   mWalkingTouchId( -1 ),
61   mLookingTouchId( -1 ),
62   mPortraitMode( false )
63 {
64 }
65
66 GameCamera::~GameCamera()
67 {
68   mTimer.Stop();
69   mCameraActor.Remove( mInterceptorActor );
70 }
71
72 void GameCamera::Initialise( float fovY, float near, float far )
73 {
74   mFovY = fovY;
75   mNear = near;
76   mFar = far;
77
78   Vector2 stageSize = Stage::GetCurrent().GetSize();
79   mPortraitMode = stageSize.x < stageSize.y ? true : false;
80
81   // Initialise default camera
82   InitialiseDefaultCamera();
83
84   // Create input interceptor actor
85   CreateInterceptorActor();
86
87   // Start timer
88   mTimer = Timer::New( 16 );
89   mTimer.TickSignal().Connect( this, &GameCamera::OnTick );
90   mTimer.Start();
91 }
92
93 bool GameCamera::OnTick()
94 {
95   Vector2 stageSize = Stage::GetCurrent().GetSize();
96
97   // ---------------------------------------------------------------------
98   // update rotation
99   Vector2 tmp( mScreenLookDelta );
100   mScreenLookDelta = Vector2::ZERO;
101
102   if( mPortraitMode )
103   {
104     float yaw = ( (tmp.y / stageSize.y ) * CAMERA_SENSITIVITY );
105     float pitch = ( (tmp.x / stageSize.x ) * CAMERA_SENSITIVITY );
106     mCameraYawPitch.y -= yaw;
107     mCameraYawPitch.x -= pitch;
108     if( abs( mCameraYawPitch.y ) > CAMERA_VERTICAL_LIMIT )
109     {
110       mCameraYawPitch.y = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.y < 0) ? -1.0f : 1.0f );
111     }
112   }
113   else
114   {
115     float yaw = ( (tmp.y / stageSize.x ) * CAMERA_SENSITIVITY );
116     float pitch = ( (tmp.x / stageSize.y ) * CAMERA_SENSITIVITY );
117     mCameraYawPitch.x -= yaw;
118     mCameraYawPitch.y -= pitch;
119     if( abs( mCameraYawPitch.x ) > CAMERA_VERTICAL_LIMIT )
120     {
121       mCameraYawPitch.x = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.x < 0) ? -1.0f : 1.0f );
122     }
123   }
124
125   Quaternion rotation;
126   Quaternion rotX( Degree( mCameraYawPitch.x), Vector3( 1.0f, 0.0f, 0.0f ) );
127   Quaternion rotY( Degree( mCameraYawPitch.y), Vector3( 0.0f, 1.0f, 0.0f ) );
128   if (mPortraitMode )
129   {
130     Quaternion rotZ( Degree( mPortraitMode ? 90.0 : 0.0f), Vector3( 0.0f, 0.0f, 1.0f ) );
131     rotation = ( rotZ * rotX * rotY );
132   }
133   else
134   {
135     rotation = ( rotY * rotX );
136   }
137   mCameraActor.SetProperty( Actor::Property::ORIENTATION, rotation );
138
139   // ---------------------------------------------------------------------
140   // update position
141   Vector3 position( mCameraPosition );
142
143   // Rotate CAMERA_FORWARD vector
144   Vector3 forwardVector = rotation.Rotate( CAMERA_FORWARD );
145
146   // Cancel vertical movement
147   forwardVector.y = 0.0f;
148
149   // Normalize
150   forwardVector.Normalize();
151
152   // compute sideways vector
153   Vector3 sidewaysVector = forwardVector.Cross( CAMERA_UP );
154
155   sidewaysVector.Normalize();
156
157   const float forwardSpeed( mScreenWalkDelta.y / stageSize.y );
158   const float sidewaysSpeed( mScreenWalkDelta.x / stageSize.x );
159
160   // Adjust walking speed
161   if ( mPortraitMode )
162   {
163     position += forwardVector * (forwardSpeed * 0.5f);
164   }
165   else
166   {
167     position += forwardVector * (-forwardSpeed * 0.5f);
168   }
169
170   position += sidewaysVector * (sidewaysSpeed * 0.5f);
171
172   mCameraActor.SetPosition( position );
173
174   mCameraPosition = position;
175
176   return true;
177 }
178
179 void GameCamera::InitialiseDefaultCamera()
180 {
181   Stage stage = Stage::GetCurrent();
182   mCameraActor = stage.GetRenderTaskList().GetTask(0).GetCameraActor();
183   mCameraActor.SetProperty( Dali::Actor::Property::NAME, "GameCamera" );
184   mCameraActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
185   mCameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
186   mCameraActor.SetFieldOfView( Radian( Degree( mFovY ) ) );
187
188   // should be read from file
189   mCameraActor.SetNearClippingPlane( mNear );
190   mCameraActor.SetFarClippingPlane( mFar );
191   mCameraActor.SetPosition( CAMERA_DEFAULT_POSITION );
192
193   // Camera position is shadowed in order to avoid using.GetCurrentProperty< Vector3 >( Actor::Property::POSITION )
194   mCameraPosition = CAMERA_DEFAULT_POSITION;
195 }
196
197 void GameCamera::CreateInterceptorActor()
198 {
199   Stage stage = Stage::GetCurrent();
200
201   mInterceptorActor = Actor::New();
202   mInterceptorActor.SetProperty( Dali::Actor::Property::NAME, "GameInputInterceptor" );
203   mInterceptorActor.SetSize( Vector3( stage.GetSize().x, stage.GetSize().y, 1 ) );
204   mInterceptorActor.SetPosition( Vector3( 0.0, 0.0, 1.0  ) );
205   mInterceptorActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
206   mInterceptorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
207   mCameraActor.Add( mInterceptorActor );
208
209   // Connect TouchSignal to interceptor actor
210   mInterceptorActor.TouchSignal().Connect( this, &GameCamera::OnTouch );
211 }
212
213 bool GameCamera::OnTouch( Actor actor, const TouchData& touch )
214 {
215   Stage stage = Stage::GetCurrent();
216
217   for( int i = 0; i < (int)touch.GetPointCount() && i < 3; ++i )
218   {
219     int id = touch.GetDeviceId( i );
220     Vector2 tmp( touch.GetScreenPosition( i ) );
221     Vector2 position;
222     float halfWindowSize;
223     if( mPortraitMode )
224     {
225       position.x = tmp.y;
226       position.y = tmp.x;
227       halfWindowSize = stage.GetSize().y / 2;
228     }
229     else
230     {
231       position.x = tmp.x;
232       position.y = tmp.y;
233       halfWindowSize = stage.GetSize().x / 2;
234     }
235
236     // touch started
237     if( touch.GetState( i ) == PointState::STARTED )
238     {
239       // start looking
240       if( position.x > halfWindowSize && mLookingTouchId < 0 )
241       {
242         mLookingTouchId = id;
243         mOldTouchLookPosition = position;
244       }
245       // start walking
246       else if( position.x < halfWindowSize && mWalkingTouchId < 0 )
247       {
248         mWalkingTouchId = id;
249         mOldTouchWalkPosition = position;
250         mScreenWalkDelta = Vector2::ZERO;
251       }
252     }
253     else if( touch.GetState( i ) == PointState::FINISHED ||
254              touch.GetState( i ) == PointState::LEAVE ||
255              touch.GetState( i ) == PointState::INTERRUPTED
256              )
257     {
258       // terminate look
259       if( mLookingTouchId == id )
260       {
261         mScreenLookDelta = Vector2::ZERO;
262         mOldTouchLookPosition = Vector2::ZERO;
263         mLookingTouchId = -1;
264       }
265       // terminate walking
266       else if( mWalkingTouchId == id )
267       {
268         mScreenWalkDelta = Vector2::ZERO;
269         mOldTouchWalkPosition = Vector2::ZERO;
270         mWalkingTouchId = -1;
271       }
272     }
273     else // on motion
274     {
275       // update looking
276       if( mLookingTouchId == id )
277       {
278         mScreenLookDelta.x += ( position.x - mOldTouchLookPosition.x );
279         mScreenLookDelta.y += ( position.y - mOldTouchLookPosition.y );
280         mOldTouchLookPosition = position;
281       }
282       // update walking
283       else if ( mWalkingTouchId == id )
284       {
285         mScreenWalkDelta.x += ( position.x - mOldTouchWalkPosition.x );
286         mScreenWalkDelta.y += ( position.y - mOldTouchWalkPosition.y );
287         mOldTouchWalkPosition = position;
288       }
289     }
290   }
291   return true;
292 }