Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: chrome/browser/android/vr_shell/vr_controller.cc

Issue 2350253004: Controller support for VrShell (Closed)
Patch Set: Controller support for VrShell Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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>
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 // Minimum angle needed to start zoom gesture.
37 constexpr float kMinZoomAngle = 0.25f;
38
39 class Vector {
40 public:
41 static inline void ClampTouchpadPosition(gvr::Vec2f* position) {
tdresser 2016/09/23 20:36:44 We can't modify Vec2f? Where is it defined?
asimjour 2016/09/30 13:37:43 We can't. It's in gvr library (third_party/gvr-and
42 position->x = std::min(std::max(0.0f, position->x), 1.0f);
43 position->y = std::min(std::max(0.0f, position->y), 1.0f);
44 }
45
46 static inline void VectSetZero(gvr::Vec2f* v) {
47 v->x = 0;
48 v->y = 0;
49 }
50
51 static inline gvr::Vec2f VectSubtract(gvr::Vec2f v1, gvr::Vec2f v2) {
52 gvr::Vec2f result;
53 result.x = v1.x - v2.x;
54 result.y = v1.y - v2.y;
55 return result;
56 }
57
58 static inline bool VectEqual(const gvr::Vec2f v1, const gvr::Vec2f v2) {
59 return (std::abs(v1.x - v2.x) < kDelta) && (std::abs(v1.y - v2.y) < kDelta);
60 }
61 }; // Vector
62
63 } // namespace
64
65 VrController::VrController(gvr_context* vr_context) {
66 Initialize(vr_context);
67 Reset();
68 }
69
70 VrController::~VrController() {}
71
72 void VrController::OnResume() {
73 if (controller_api_)
74 controller_api_->Resume();
75 }
76
77 void VrController::OnPause() {
78 if (controller_api_)
79 controller_api_->Pause();
80 }
81
82 bool VrController::IsTouching() {
83 return controller_state_.IsTouching();
84 }
85
86 float VrController::TouchPosX() {
87 return controller_state_.GetTouchPos().x;
88 }
89
90 float VrController::TouchPosY() {
91 return controller_state_.GetTouchPos().y;
92 }
93
94 const gvr::Quatf VrController::Orientation() {
95 return controller_state_.GetOrientation();
96 }
97
98 bool VrController::IsTouchDown() {
99 return controller_state_.GetTouchDown();
100 }
101
102 bool VrController::IsTouchUp() {
103 return controller_state_.GetTouchUp();
104 }
105
106 bool VrController::IsButtonDown(const int32_t button) {
107 return controller_state_.GetButtonDown(button);
108 }
109
110 bool VrController::IsButtonUp(const int32_t button) {
111 return controller_state_.GetButtonUp(button);
112 }
113
114 bool VrController::IsConnected() {
115 return controller_state_.GetConnectionState() == gvr::kControllerConnected;
116 }
117
118 void VrController::UpdateState() {
119 const int32_t old_status = controller_state_.GetApiStatus();
120 const int32_t old_connection_state = controller_state_.GetConnectionState();
121 // Read current controller state.
122 controller_state_.Update(*controller_api_);
123 // Print new API status and connection state, if they changed.
124 if (controller_state_.GetApiStatus() != old_status ||
125 controller_state_.GetConnectionState() != old_connection_state) {
126 VLOG(1) << "Controller Connection status: "
127 << gvr_controller_connection_state_to_string(
128 controller_state_.GetConnectionState());
129 }
130 }
131
132 void VrController::Update(bool touch_up,
133 bool touch_down,
134 bool is_touching,
135 const gvr::Vec2f position,
136 int64_t timestamp) {
137 CHECK(touch_info_ != nullptr) << "touch_info_ not initialized properly.";
138 touch_info_->touch_up = touch_up;
139 touch_info_->touch_down = touch_down;
140 touch_info_->is_touching = is_touching;
141 touch_info_->touch_point.position = position;
142 Vector::ClampTouchpadPosition(&touch_info_->touch_point.position);
143 touch_info_->touch_point.timestamp = timestamp;
144
145 UpdateGestureFromTouchInfo();
146 }
147
148 void VrController::Initialize(gvr_context* gvr_context) {
149 CHECK(gvr_context != nullptr) << "invalid gvr_context";
150 controller_api_.reset(new gvr::ControllerApi);
151 int32_t options = gvr::ControllerApi::DefaultOptions();
152
153 // Enable non-default options, if you need them:
154 // options |= GVR_CONTROLLER_ENABLE_GYRO;
155 CHECK(controller_api_->Init(options, gvr_context));
156 controller_api_->Resume();
157 }
158
159 VrGesture VrController::DetectGesture() {
160 if (controller_state_.GetConnectionState() == gvr::kControllerConnected) {
161 gvr::Vec2f position;
162 position.x = TouchPosX();
163 position.y = TouchPosY();
164 Update(IsTouchUp(), IsTouchDown(), IsTouching(), position,
165 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos);
166 if (GetGestureListSize() > 0 &&
167 GetGesturePtr(0)->type == kGestureTypeScroll) {
168 switch (GetGesturePtr(0)->details.scroll.state) {
169 case WebInputEvent::GestureScrollBegin:
170 return VrGesture(
171 kGestureScroll,
172 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
173 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
174 GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor,
175 GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor,
176 WebInputEvent::GestureScrollBegin, Orientation());
177 case WebInputEvent::GestureScrollUpdate:
178 return VrGesture(
179 kGestureScroll,
180 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
181 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
182 GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor,
183 GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor,
184 WebInputEvent::GestureScrollUpdate, Orientation());
185 case WebInputEvent::GestureScrollEnd:
186 return VrGesture(
187 kGestureScroll,
188 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
189 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
190 GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor,
191 GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor,
192 WebInputEvent::GestureScrollEnd, Orientation());
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 float dqx = 0.0f;
204
205 dqx = last_qx_ - Orientation().qx;
206
207 // don't accept rapid moves
208 if (dqx < -1.0f || dqx > 1.0f)
209 dqx = 0.0f;
210 last_qx_ = Orientation().qx;
211
212 if (IsButtonDown(gvr::kControllerButtonApp))
213 zoom_in_progress_ = true;
214 if (IsButtonUp(gvr::kControllerButtonApp)) {
215 zoom_in_progress_ = false;
216 if (pinch_started_) {
217 pinch_started_ = false;
218 }
219 }
220 if (zoom_in_progress_) {
221 if (dqx != 0.0f) {
222 // dz == 1 means no zoom. dz < 1 means zoom-out and dz > 1 means
223 // zoom-in.
224 // dqx * 2 + 1 results to dz \in [0,2]
225 return VrGesture(
226 kGestureZoom,
227 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
228 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
229 dqx * 2 + 1, Orientation());
230 }
231 if (Orientation().qz < kMinZoomAngle &&
232 Orientation().qz > -1 * kMinZoomAngle && pinch_started_) {
233 pinch_started_ = false;
234 }
235 }
236 return VrGesture(kGestureAngularMove,
237 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
238 gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
239 Orientation());
240 }
241 return VrGesture();
242 }
243
244 void VrController::UpdateGestureFromTouchInfo() {
245 // Clear the gesture list.
246 gesture_list_.clear();
247
248 switch (state_) {
249 // user has not put finger on touch pad.
250 case WAITING:
251 HandleWaitingState();
252 break;
253 // user has not started a gesture (by moving out of slop).
254 case TOUCHING:
255 HandleDetectingState();
256 break;
257 // user is scrolling on touchpad
258 case SCROLLING:
259 HandleScrollingState();
260 break;
261 default:
262 LOG(ERROR) << "Wrong gesture detector state: " << state_;
263 break;
264 }
265 }
266
267 const VrGesture* VrController::GetGesturePtr(const size_t index) {
268 CHECK(index < gesture_list_.size()) << "The gesture index exceeds the"
269 "size of gesture list.";
270 return const_cast<VrGesture*>(&gesture_list_[index]);
271 }
272
273 void VrController::Update(const gvr_controller_state* controller_state) {
274 // Update touch information.
275 CHECK(touch_info_ != nullptr) << "touch_info_ not initialized properly.";
276 touch_info_->touch_up = gvr_controller_state_get_touch_up(controller_state);
277 touch_info_->touch_down =
278 gvr_controller_state_get_touch_down(controller_state);
279 touch_info_->is_touching = gvr_controller_state_is_touching(controller_state);
280 touch_info_->touch_point.position.x =
281 gvr_controller_state_get_touch_pos(controller_state).x;
282 touch_info_->touch_point.position.y =
283 gvr_controller_state_get_touch_pos(controller_state).y;
284 Vector::ClampTouchpadPosition(&(touch_info_->touch_point.position));
285 touch_info_->touch_point.timestamp =
286 gvr_controller_state_get_last_touch_timestamp(controller_state);
287
288 UpdateGestureFromTouchInfo();
289 }
290
291 void VrController::HandleWaitingState() {
292 // User puts finger on touch pad (or when the touch down for current gesture
293 // is missed, initiate gesture from current touch point).
294 if (touch_info_->touch_down || touch_info_->is_touching) {
295 // update initial touchpoint
296 *init_touch_point_ = touch_info_->touch_point;
297 // update current touchpoint
298 *cur_touch_point_ = touch_info_->touch_point;
299 state_ = TOUCHING;
300 }
301 }
302
303 void VrController::HandleDetectingState() {
304 // User lifts up finger from touch pad.
305 if (touch_info_->touch_up || !(touch_info_->is_touching)) {
306 Reset();
307 return;
308 }
309
310 // Touch position is changed and the touch point moves outside of slop.
311 if (UpdateCurrentTouchpoint() && touch_info_->is_touching &&
312 !InSlop(touch_info_->touch_point.position)) {
313 state_ = SCROLLING;
314 VrGesture gesture;
315 gesture.type = kGestureTypeScroll;
316 gesture.details.scroll.state = WebInputEvent::GestureScrollBegin;
317 UpdateGesture(&gesture);
318 gesture_list_.push_back(gesture);
319 }
320 }
321
322 void VrController::HandleScrollingState() {
323 // Update current touch point.
324 bool touch_position_changed = UpdateCurrentTouchpoint();
325 if (touch_info_->touch_up || !(touch_info_->is_touching)) { // gesture ends
326 VrGesture scroll_end;
327 scroll_end.type = kGestureTypeScroll;
328 scroll_end.details.scroll.state = WebInputEvent::GestureScrollEnd;
329 UpdateGesture(&scroll_end);
330 gesture_list_.push_back(scroll_end);
331
332 Reset();
333 } else if (touch_position_changed) { // User continues scrolling and there is
334 // a change in touch position.
335 VrGesture scroll_update;
336 scroll_update.type = kGestureTypeScroll;
337 scroll_update.details.scroll.state = WebInputEvent::GestureScrollUpdate;
338 UpdateGesture(&scroll_update);
339 gesture_list_.push_back(scroll_update);
340 }
341 }
342
343 bool VrController::InSlop(const gvr::Vec2f touch_position) {
344 return (std::abs(touch_position.x - init_touch_point_->position.x) <
345 kSlopHorizontal) &&
346 (std::abs(touch_position.y - init_touch_point_->position.y) <
347 kSlopVertical);
348 }
349
350 void VrController::Reset() {
351 // Reset state.
352 state_ = WAITING;
353
354 // Reset the pointers.
355 prev_touch_point_.reset(new TouchPoint);
356 cur_touch_point_.reset(new TouchPoint);
357 init_touch_point_.reset(new TouchPoint);
358 touch_info_.reset(new TouchInfo);
359 Vector::VectSetZero(&overall_velocity_);
360 }
361
362 void VrController::UpdateGesture(VrGesture* gesture) {
363 if (!gesture)
364 LOG(ERROR) << "The gesture pointer is not initiated properly.";
365 gesture->velocity = overall_velocity_;
366 gesture->displacement = Vector::VectSubtract(cur_touch_point_->position,
367 prev_touch_point_->position);
368 }
369
370 bool VrController::UpdateCurrentTouchpoint() {
371 if (touch_info_->is_touching || touch_info_->touch_up) {
372 // Update the touch point when the touch position has changed.
373 if (!Vector::VectEqual(cur_touch_point_->position,
374 touch_info_->touch_point.position)) {
375 prev_touch_point_.swap(cur_touch_point_);
376 *cur_touch_point_ = touch_info_->touch_point;
377
378 return true;
379 }
380 }
381 return false;
382 }
383
384 } // namespace vr_shell
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698