OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/android/vr_shell/vr_controller.h" | |
6 | |
7 #include <android/log.h> | |
mthiesse
2016/09/30 14:09:36
remove this
asimjour
2016/09/30 15:38:08
Done.
| |
8 | |
9 #include <cmath> | |
10 | |
11 #include "base/logging.h" | |
12 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
13 | |
14 using blink::WebInputEvent; | |
15 | |
16 namespace vr_shell { | |
17 | |
18 namespace { | |
19 | |
20 constexpr float kDisplacementScaleFactor = 800.0f; | |
21 | |
22 // A slop represents a small rectangular region around the first touch point of | |
23 // a gesture. | |
24 // If the user does not move outside of the slop, no gesture is detected. | |
25 // Gestures start to be detected when the user moves outside of the slop. | |
26 // Vertical distance from the border to the center of slop. | |
27 constexpr float kSlopVertical = 0.165f; | |
28 | |
29 // Horizontal distance from the border to the center of slop. | |
30 constexpr float kSlopHorizontal = 0.125f; | |
31 | |
32 // Minimum distance needed in at least one direction to call two vectors | |
33 // not equal. | |
34 constexpr float kDelta = 1.0e-7f; | |
35 | |
36 class Vector { | |
37 public: | |
38 static inline void ClampTouchpadPosition(gvr::Vec2f* position) { | |
39 position->x = std::min(std::max(0.0f, position->x), 1.0f); | |
40 position->y = std::min(std::max(0.0f, position->y), 1.0f); | |
41 } | |
42 | |
43 static inline void VectSetZero(gvr::Vec2f* v) { | |
44 v->x = 0; | |
45 v->y = 0; | |
46 } | |
47 | |
48 static inline gvr::Vec2f VectSubtract(gvr::Vec2f v1, gvr::Vec2f v2) { | |
49 gvr::Vec2f result; | |
50 result.x = v1.x - v2.x; | |
51 result.y = v1.y - v2.y; | |
52 return result; | |
53 } | |
54 | |
55 static inline bool VectEqual(const gvr::Vec2f v1, const gvr::Vec2f v2) { | |
56 return (std::abs(v1.x - v2.x) < kDelta) && (std::abs(v1.y - v2.y) < kDelta); | |
57 } | |
58 }; // Vector | |
59 | |
60 } // namespace | |
61 | |
62 VrController::VrController(gvr_context* vr_context) { | |
63 Initialize(vr_context); | |
64 Reset(); | |
65 } | |
66 | |
67 VrController::~VrController() {} | |
68 | |
69 void VrController::OnResume() { | |
70 if (controller_api_) | |
71 controller_api_->Resume(); | |
72 } | |
73 | |
74 void VrController::OnPause() { | |
75 if (controller_api_) | |
76 controller_api_->Pause(); | |
77 } | |
78 | |
79 bool VrController::IsTouching() { | |
80 return controller_state_.IsTouching(); | |
81 } | |
82 | |
83 float VrController::TouchPosX() { | |
84 return controller_state_.GetTouchPos().x; | |
85 } | |
86 | |
87 float VrController::TouchPosY() { | |
88 return controller_state_.GetTouchPos().y; | |
89 } | |
90 | |
91 const gvr::Quatf VrController::Orientation() { | |
92 return controller_state_.GetOrientation(); | |
93 } | |
94 | |
95 bool VrController::IsTouchDown() { | |
96 return controller_state_.GetTouchDown(); | |
97 } | |
98 | |
99 bool VrController::IsTouchUp() { | |
100 return controller_state_.GetTouchUp(); | |
101 } | |
102 | |
103 bool VrController::IsButtonDown(const int32_t button) { | |
104 return controller_state_.GetButtonDown(button); | |
105 } | |
106 | |
107 bool VrController::IsButtonUp(const int32_t button) { | |
108 return controller_state_.GetButtonUp(button); | |
109 } | |
110 | |
111 bool VrController::IsConnected() { | |
112 return controller_state_.GetConnectionState() == gvr::kControllerConnected; | |
113 } | |
114 | |
115 void VrController::UpdateState() { | |
116 const int32_t old_status = controller_state_.GetApiStatus(); | |
117 const int32_t old_connection_state = controller_state_.GetConnectionState(); | |
118 // Read current controller state. | |
119 controller_state_.Update(*controller_api_); | |
120 // Print new API status and connection state, if they changed. | |
121 if (controller_state_.GetApiStatus() != old_status || | |
122 controller_state_.GetConnectionState() != old_connection_state) { | |
123 VLOG(1) << "Controller Connection status: " | |
124 << gvr_controller_connection_state_to_string( | |
125 controller_state_.GetConnectionState()); | |
126 } | |
127 } | |
128 | |
129 void VrController::Update(bool touch_up, | |
130 bool touch_down, | |
131 bool is_touching, | |
132 const gvr::Vec2f position, | |
133 int64_t timestamp) { | |
134 CHECK(touch_info_ != nullptr) << "touch_info_ not initialized properly."; | |
135 touch_info_->touch_up = touch_up; | |
136 touch_info_->touch_down = touch_down; | |
137 touch_info_->is_touching = is_touching; | |
138 touch_info_->touch_point.position = position; | |
139 Vector::ClampTouchpadPosition(&touch_info_->touch_point.position); | |
140 touch_info_->touch_point.timestamp = timestamp; | |
141 | |
142 UpdateGestureFromTouchInfo(); | |
143 } | |
144 | |
145 void VrController::Initialize(gvr_context* gvr_context) { | |
146 CHECK(gvr_context != nullptr) << "invalid gvr_context"; | |
147 controller_api_.reset(new gvr::ControllerApi); | |
148 int32_t options = gvr::ControllerApi::DefaultOptions(); | |
149 | |
150 // Enable non-default options, if you need them: | |
151 // options |= GVR_CONTROLLER_ENABLE_GYRO; | |
152 CHECK(controller_api_->Init(options, gvr_context)); | |
153 controller_api_->Resume(); | |
154 } | |
155 | |
156 VrGesture VrController::DetectGesture() { | |
157 if (controller_state_.GetConnectionState() == gvr::kControllerConnected) { | |
158 gvr::Vec2f position; | |
159 position.x = TouchPosX(); | |
160 position.y = TouchPosY(); | |
161 Update(IsTouchUp(), IsTouchDown(), IsTouching(), position, | |
162 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos); | |
163 if (GetGestureListSize() > 0 && | |
164 (GetGesturePtr(0)->type == WebInputEvent::GestureScrollBegin || | |
165 GetGesturePtr(0)->type == WebInputEvent::GestureScrollUpdate || | |
166 GetGesturePtr(0)->type == WebInputEvent::GestureScrollEnd)) { | |
167 switch (GetGesturePtr(0)->type) { | |
168 case WebInputEvent::GestureScrollBegin: | |
169 return VrGesture( | |
170 kGestureScroll, | |
171 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
172 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
173 GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor, | |
174 GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor, | |
175 WebInputEvent::GestureScrollBegin, Orientation()); | |
176 case WebInputEvent::GestureScrollUpdate: | |
177 return VrGesture( | |
178 kGestureScroll, | |
179 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
180 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
181 GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor, | |
182 GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor, | |
183 WebInputEvent::GestureScrollUpdate, Orientation()); | |
184 case WebInputEvent::GestureScrollEnd: | |
185 return VrGesture( | |
186 kGestureScroll, | |
187 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
188 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, 0, 0, | |
189 WebInputEvent::GestureScrollEnd, Orientation()); | |
190 default: | |
191 LOG(ERROR) << "Unknown Gesture"; | |
192 return VrGesture(); | |
193 } | |
194 } | |
195 | |
196 if (IsButtonDown(gvr::kControllerButtonClick)) { | |
197 return VrGesture( | |
198 kGestureButtonsChange, | |
199 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
200 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, 1, 0, | |
201 Orientation()); | |
202 } | |
203 return VrGesture(kGestureAngularMove, | |
204 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
205 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, | |
206 Orientation()); | |
207 } | |
208 return VrGesture(); | |
209 } | |
210 | |
211 void VrController::UpdateGestureFromTouchInfo() { | |
212 // Clear the gesture list. | |
213 gesture_list_.clear(); | |
214 | |
215 switch (state_) { | |
216 // User has not put finger on touch pad. | |
217 case WAITING: | |
218 HandleWaitingState(); | |
219 break; | |
220 // User has not started a gesture (by moving out of slop). | |
221 case TOUCHING: | |
222 HandleDetectingState(); | |
223 break; | |
224 // User is scrolling on touchpad | |
225 case SCROLLING: | |
226 HandleScrollingState(); | |
227 break; | |
228 default: | |
229 LOG(ERROR) << "Wrong gesture detector state: " << state_; | |
230 break; | |
231 } | |
232 } | |
233 | |
234 const VrGesture* VrController::GetGesturePtr(const size_t index) { | |
235 CHECK(index < gesture_list_.size()) << "The gesture index exceeds the" | |
236 "size of gesture list."; | |
237 return const_cast<VrGesture*>(&gesture_list_[index]); | |
238 } | |
239 | |
240 void VrController::Update(const gvr_controller_state* controller_state) { | |
241 // Update touch information. | |
242 CHECK(touch_info_ != nullptr) << "touch_info_ not initialized properly."; | |
243 touch_info_->touch_up = gvr_controller_state_get_touch_up(controller_state); | |
244 touch_info_->touch_down = | |
245 gvr_controller_state_get_touch_down(controller_state); | |
246 touch_info_->is_touching = gvr_controller_state_is_touching(controller_state); | |
247 touch_info_->touch_point.position.x = | |
248 gvr_controller_state_get_touch_pos(controller_state).x; | |
249 touch_info_->touch_point.position.y = | |
250 gvr_controller_state_get_touch_pos(controller_state).y; | |
251 Vector::ClampTouchpadPosition(&(touch_info_->touch_point.position)); | |
252 touch_info_->touch_point.timestamp = | |
253 gvr_controller_state_get_last_touch_timestamp(controller_state); | |
254 | |
255 UpdateGestureFromTouchInfo(); | |
256 } | |
257 | |
258 void VrController::HandleWaitingState() { | |
259 // User puts finger on touch pad (or when the touch down for current gesture | |
260 // is missed, initiate gesture from current touch point). | |
261 if (touch_info_->touch_down || touch_info_->is_touching) { | |
262 // update initial touchpoint | |
263 *init_touch_point_ = touch_info_->touch_point; | |
264 // update current touchpoint | |
265 *cur_touch_point_ = touch_info_->touch_point; | |
266 state_ = TOUCHING; | |
267 } | |
268 } | |
269 | |
270 void VrController::HandleDetectingState() { | |
271 // User lifts up finger from touch pad. | |
272 if (touch_info_->touch_up || !(touch_info_->is_touching)) { | |
273 Reset(); | |
274 return; | |
275 } | |
276 | |
277 // Touch position is changed and the touch point moves outside of slop. | |
278 if (UpdateCurrentTouchpoint() && touch_info_->is_touching && | |
279 !InSlop(touch_info_->touch_point.position)) { | |
280 state_ = SCROLLING; | |
281 VrGesture gesture; | |
282 gesture.type = WebInputEvent::GestureScrollBegin; | |
283 UpdateGesture(&gesture); | |
284 gesture_list_.push_back(gesture); | |
285 } | |
286 } | |
287 | |
288 void VrController::HandleScrollingState() { | |
289 // Update current touch point. | |
290 bool touch_position_changed = UpdateCurrentTouchpoint(); | |
291 if (touch_info_->touch_up || !(touch_info_->is_touching)) { // gesture ends | |
292 VrGesture scroll_end; | |
293 scroll_end.type = WebInputEvent::GestureScrollEnd; | |
294 UpdateGesture(&scroll_end); | |
295 gesture_list_.push_back(scroll_end); | |
296 | |
297 Reset(); | |
298 } else if (touch_position_changed) { // User continues scrolling and there is | |
299 // a change in touch position. | |
300 VrGesture scroll_update; | |
301 scroll_update.type = WebInputEvent::GestureScrollUpdate; | |
302 UpdateGesture(&scroll_update); | |
303 gesture_list_.push_back(scroll_update); | |
304 } | |
305 } | |
306 | |
307 bool VrController::InSlop(const gvr::Vec2f touch_position) { | |
308 return (std::abs(touch_position.x - init_touch_point_->position.x) < | |
309 kSlopHorizontal) && | |
310 (std::abs(touch_position.y - init_touch_point_->position.y) < | |
311 kSlopVertical); | |
312 } | |
313 | |
314 void VrController::Reset() { | |
315 // Reset state. | |
316 state_ = WAITING; | |
317 | |
318 // Reset the pointers. | |
319 prev_touch_point_.reset(new TouchPoint); | |
320 cur_touch_point_.reset(new TouchPoint); | |
321 init_touch_point_.reset(new TouchPoint); | |
322 touch_info_.reset(new TouchInfo); | |
323 Vector::VectSetZero(&overall_velocity_); | |
324 } | |
325 | |
326 void VrController::UpdateGesture(VrGesture* gesture) { | |
327 if (!gesture) | |
328 LOG(ERROR) << "The gesture pointer is not initiated properly."; | |
329 gesture->velocity = overall_velocity_; | |
330 gesture->displacement = Vector::VectSubtract(cur_touch_point_->position, | |
331 prev_touch_point_->position); | |
332 } | |
333 | |
334 bool VrController::UpdateCurrentTouchpoint() { | |
335 if (touch_info_->is_touching || touch_info_->touch_up) { | |
336 // Update the touch point when the touch position has changed. | |
337 if (!Vector::VectEqual(cur_touch_point_->position, | |
338 touch_info_->touch_point.position)) { | |
339 prev_touch_point_.swap(cur_touch_point_); | |
340 *cur_touch_point_ = touch_info_->touch_point; | |
341 | |
342 return true; | |
343 } | |
344 } | |
345 return false; | |
346 } | |
347 | |
348 } // namespace vr_shell | |
OLD | NEW |