Changes after TouchedSignal changes
[platform/core/uifw/dali-demo.git] / examples / fpp-game / game-camera.cpp
1 /*
2  * Copyright (c) 2020 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/render-tasks/render-task-list.h>
21 #include <dali/public-api/render-tasks/render-task.h>
22 #include <dali/public-api/events/touch-event.h>
23
24 using namespace Dali;
25
26 namespace
27 {
28 // Input sensitivity, the larger value, the more sensitive input
29 // Default value has been chosen empirically
30 const float   CAMERA_SENSITIVITY        ( 90.0f );
31
32 // Vertical angle limit of the camera
33 const float   CAMERA_VERTICAL_LIMIT     ( 80.0f );
34
35 // Position where camera is instantiated by default
36 const Vector3 CAMERA_DEFAULT_POSITION   ( 1.0f, -1.5f, -3.0f );
37
38 // Field-of-View in degrees
39 const float   CAMERA_DEFAULT_FOV        ( 60.0f );
40
41 // Near plane
42 const float   CAMERA_DEFAULT_NEAR       ( 0.1f );
43
44 // Far plane
45 const float   CAMERA_DEFAULT_FAR        ( 100.0f );
46
47 // Default forward vector
48 const Vector3 CAMERA_FORWARD            ( 0.0f, 0.0f, 1.0f );
49
50 // Default up vector
51 const Vector3 CAMERA_UP                 ( Vector3::YAXIS );
52 }
53
54 GameCamera::GameCamera()
55 : mFovY( CAMERA_DEFAULT_FOV ),
56   mNear( CAMERA_DEFAULT_NEAR ),
57   mFar( CAMERA_DEFAULT_FAR ),
58   mWalkingTouchId( -1 ),
59   mLookingTouchId( -1 ),
60   mPortraitMode( false )
61 {
62 }
63
64 GameCamera::~GameCamera()
65 {
66   mTimer.Stop();
67   mCameraActor.Remove( mInterceptorActor );
68 }
69
70 void GameCamera::Initialise( CameraActor defaultCamera, float fovY, float near, float far, const Vector2& sceneSize )
71 {
72   mCameraActor = defaultCamera;
73
74   mFovY = fovY;
75   mNear = near;
76   mFar = far;
77
78   mSceneSize = sceneSize;
79   mPortraitMode = mSceneSize.x < mSceneSize.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   // ---------------------------------------------------------------------
96   // update rotation
97   Vector2 tmp( mScreenLookDelta );
98   mScreenLookDelta = Vector2::ZERO;
99
100   if( mPortraitMode )
101   {
102     float yaw = ( (tmp.y / mSceneSize.y ) * CAMERA_SENSITIVITY );
103     float pitch = ( (tmp.x / mSceneSize.x ) * CAMERA_SENSITIVITY );
104     mCameraYawPitch.y -= yaw;
105     mCameraYawPitch.x -= pitch;
106     if( abs( mCameraYawPitch.y ) > CAMERA_VERTICAL_LIMIT )
107     {
108       mCameraYawPitch.y = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.y < 0) ? -1.0f : 1.0f );
109     }
110   }
111   else
112   {
113     float yaw = ( (tmp.y / mSceneSize.x ) * CAMERA_SENSITIVITY );
114     float pitch = ( (tmp.x / mSceneSize.y ) * CAMERA_SENSITIVITY );
115     mCameraYawPitch.x -= yaw;
116     mCameraYawPitch.y -= pitch;
117     if( abs( mCameraYawPitch.x ) > CAMERA_VERTICAL_LIMIT )
118     {
119       mCameraYawPitch.x = CAMERA_VERTICAL_LIMIT * ((mCameraYawPitch.x < 0) ? -1.0f : 1.0f );
120     }
121   }
122
123   Quaternion rotation;
124   Quaternion rotX( Degree( mCameraYawPitch.x), Vector3( 1.0f, 0.0f, 0.0f ) );
125   Quaternion rotY( Degree( mCameraYawPitch.y), Vector3( 0.0f, 1.0f, 0.0f ) );
126   if (mPortraitMode )
127   {
128     Quaternion rotZ( Degree( mPortraitMode ? 90.0 : 0.0f), Vector3( 0.0f, 0.0f, 1.0f ) );
129     rotation = ( rotZ * rotX * rotY );
130   }
131   else
132   {
133     rotation = ( rotY * rotX );
134   }
135   mCameraActor.SetProperty( Actor::Property::ORIENTATION, rotation );
136
137   // ---------------------------------------------------------------------
138   // update position
139   Vector3 position( mCameraPosition );
140
141   // Rotate CAMERA_FORWARD vector
142   Vector3 forwardVector = rotation.Rotate( CAMERA_FORWARD );
143
144   // Cancel vertical movement
145   forwardVector.y = 0.0f;
146
147   // Normalize
148   forwardVector.Normalize();
149
150   // compute sideways vector
151   Vector3 sidewaysVector = forwardVector.Cross( CAMERA_UP );
152
153   sidewaysVector.Normalize();
154
155   const float forwardSpeed( mScreenWalkDelta.y / mSceneSize.y );
156   const float sidewaysSpeed( mScreenWalkDelta.x / mSceneSize.x );
157
158   // Adjust walking speed
159   if ( mPortraitMode )
160   {
161     position += forwardVector * (forwardSpeed * 0.5f);
162   }
163   else
164   {
165     position += forwardVector * (-forwardSpeed * 0.5f);
166   }
167
168   position += sidewaysVector * (sidewaysSpeed * 0.5f);
169
170   mCameraActor.SetProperty( Actor::Property::POSITION, position );
171
172   mCameraPosition = position;
173
174   return true;
175 }
176
177 void GameCamera::InitialiseDefaultCamera()
178 {
179   mCameraActor.SetProperty( Dali::Actor::Property::NAME, "GameCamera" );
180   mCameraActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
181   mCameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
182   mCameraActor.SetFieldOfView( Radian( Degree( mFovY ) ) );
183
184   // should be read from file
185   mCameraActor.SetNearClippingPlane( mNear );
186   mCameraActor.SetFarClippingPlane( mFar );
187   mCameraActor.SetProperty( Actor::Property::POSITION, CAMERA_DEFAULT_POSITION );
188
189   // Camera position is shadowed in order to avoid using.GetCurrentProperty< Vector3 >( Actor::Property::POSITION )
190   mCameraPosition = CAMERA_DEFAULT_POSITION;
191 }
192
193 void GameCamera::CreateInterceptorActor()
194 {
195   mInterceptorActor = Actor::New();
196   mInterceptorActor.SetProperty( Dali::Actor::Property::NAME, "GameInputInterceptor" );
197   mInterceptorActor.SetProperty( Actor::Property::SIZE, Vector3( mSceneSize.x, mSceneSize.y, 1 ) );
198   mInterceptorActor.SetProperty( Actor::Property::POSITION, Vector3( 0.0, 0.0, 1.0  ) );
199   mInterceptorActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
200   mInterceptorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
201   mCameraActor.Add( mInterceptorActor );
202
203   // Connect TouchedSignal to interceptor actor
204   mInterceptorActor.TouchedSignal().Connect( this, &GameCamera::OnTouch );
205 }
206
207 bool GameCamera::OnTouch( Actor actor, const TouchEvent& touch )
208 {
209   for( int i = 0; i < (int)touch.GetPointCount() && i < 3; ++i )
210   {
211     int id = touch.GetDeviceId( i );
212     Vector2 tmp( touch.GetScreenPosition( i ) );
213     Vector2 position;
214     float halfWindowSize;
215     if( mPortraitMode )
216     {
217       position.x = tmp.y;
218       position.y = tmp.x;
219       halfWindowSize = mSceneSize.y / 2;
220     }
221     else
222     {
223       position.x = tmp.x;
224       position.y = tmp.y;
225       halfWindowSize = mSceneSize.x / 2;
226     }
227
228     // touch started
229     if( touch.GetState( i ) == PointState::STARTED )
230     {
231       // start looking
232       if( position.x > halfWindowSize && mLookingTouchId < 0 )
233       {
234         mLookingTouchId = id;
235         mOldTouchLookPosition = position;
236       }
237       // start walking
238       else if( position.x < halfWindowSize && mWalkingTouchId < 0 )
239       {
240         mWalkingTouchId = id;
241         mOldTouchWalkPosition = position;
242         mScreenWalkDelta = Vector2::ZERO;
243       }
244     }
245     else if( touch.GetState( i ) == PointState::FINISHED ||
246              touch.GetState( i ) == PointState::LEAVE ||
247              touch.GetState( i ) == PointState::INTERRUPTED
248              )
249     {
250       // terminate look
251       if( mLookingTouchId == id )
252       {
253         mScreenLookDelta = Vector2::ZERO;
254         mOldTouchLookPosition = Vector2::ZERO;
255         mLookingTouchId = -1;
256       }
257       // terminate walking
258       else if( mWalkingTouchId == id )
259       {
260         mScreenWalkDelta = Vector2::ZERO;
261         mOldTouchWalkPosition = Vector2::ZERO;
262         mWalkingTouchId = -1;
263       }
264     }
265     else // on motion
266     {
267       // update looking
268       if( mLookingTouchId == id )
269       {
270         mScreenLookDelta.x += ( position.x - mOldTouchLookPosition.x );
271         mScreenLookDelta.y += ( position.y - mOldTouchLookPosition.y );
272         mOldTouchLookPosition = position;
273       }
274       // update walking
275       else if ( mWalkingTouchId == id )
276       {
277         mScreenWalkDelta.x += ( position.x - mOldTouchWalkPosition.x );
278         mScreenWalkDelta.y += ( position.y - mOldTouchWalkPosition.y );
279         mOldTouchWalkPosition = position;
280       }
281     }
282   }
283   return true;
284 }