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