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

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

Powered by Google App Engine
This is Rietveld 408576698