[dali_2.3.50] Merge branch 'devel/master'
[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/events/touch-event.h>
21 #include <dali/public-api/render-tasks/render-task-list.h>
22 #include <dali/public-api/render-tasks/render-task.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 } // namespace
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       // terminate look
250       if(mLookingTouchId == id)
251       {
252         mScreenLookDelta      = Vector2::ZERO;
253         mOldTouchLookPosition = Vector2::ZERO;
254         mLookingTouchId       = -1;
255       }
256       // terminate walking
257       else if(mWalkingTouchId == id)
258       {
259         mScreenWalkDelta      = Vector2::ZERO;
260         mOldTouchWalkPosition = Vector2::ZERO;
261         mWalkingTouchId       = -1;
262       }
263     }
264     else // on motion
265     {
266       // update looking
267       if(mLookingTouchId == id)
268       {
269         mScreenLookDelta.x += (position.x - mOldTouchLookPosition.x);
270         mScreenLookDelta.y += (position.y - mOldTouchLookPosition.y);
271         mOldTouchLookPosition = position;
272       }
273       // update walking
274       else if(mWalkingTouchId == id)
275       {
276         mScreenWalkDelta.x += (position.x - mOldTouchWalkPosition.x);
277         mScreenWalkDelta.y += (position.y - mOldTouchWalkPosition.y);
278         mOldTouchWalkPosition = position;
279       }
280     }
281   }
282   return true;
283 }