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

Unified Diff: chrome/browser/android/vr_shell/vr_controller.cc

Issue 2350253004: Controller support for VrShell (Closed)
Patch Set: 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/android/vr_shell/vr_controller.cc
diff --git a/chrome/browser/android/vr_shell/vr_controller.cc b/chrome/browser/android/vr_shell/vr_controller.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9d2ca5562e7a5cc889f74cfc73b4600d6044a052
--- /dev/null
+++ b/chrome/browser/android/vr_shell/vr_controller.cc
@@ -0,0 +1,370 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/vr_shell/vr_controller.h"
+
+#include <android/log.h>
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace vr_shell {
+
+inline void clamp_touchpad_position(vec2f* position) {
bshe 2016/09/21 15:18:41 nit: rename function names to CamelCase. And if th
asimjour 2016/09/22 14:48:35 Done.
+ position->x = std::min(std::max(0.0f, position->x), 1.0f);
+ position->y = std::min(std::max(0.0f, position->y), 1.0f);
+}
+
+inline void vect_set_zero(vec2f* v) {
+ v->x = 0;
+ v->y = 0;
+}
+
+inline vec2f vect_subtract(vec2f v1, vec2f v2) {
+ vec2f result;
+ result.x = v1.x - v2.x;
+ result.y = v1.y - v2.y;
+ return result;
+}
+
+inline vec2f vect_scalar_mult(vec2f v, float scalar) {
+ vec2f vect_prod;
+ vect_prod.x = v.x * scalar;
+ vect_prod.y = v.y * scalar;
+ return vect_prod;
+}
+
+inline bool vect_equal(const vec2f v1, const vec2f v2) {
+ return (std::abs(v1.x - v2.x) < kDelta) && (std::abs(v1.y - v2.y) < kDelta);
+}
+
+inline float vect_squared_length(vec2f v) {
+ return v.x * v.x + v.y * v.y;
+}
+
+inline vec2f vect_add(vec2f v1, vec2f v2) {
+ vec2f vect_sum;
+ vect_sum.x = v1.x + v2.x;
+ vect_sum.y = v1.y + v2.y;
+ return vect_sum;
+}
+
+VrController::VrController(gvr_context_* vr_context) : zoom_in_progress(false) {
mthiesse 2016/09/21 16:13:43 optional nit: We've been putting default values in
asimjour 2016/09/22 14:48:34 Done.
+ Reset();
+}
+
+VrController::~VrController() {}
+
+void VrController::OnResume() {
+ if (controller_api_)
+ controller_api_->Resume();
+}
+
+void VrController::OnPause() {
+ if (controller_api_)
+ controller_api_->Pause();
+}
+
+bool VrController::IsTouching() {
+ return controller_state_.IsTouching();
+}
+
+float VrController::TouchPosX() {
+ return controller_state_.GetTouchPos().x;
+}
+
+float VrController::TouchPosY() {
+ return controller_state_.GetTouchPos().y;
+}
+
+const quatf VrController::Orientation() {
+ quatf orientation = {controller_state_.GetOrientation().qx,
mthiesse 2016/09/21 16:13:43 optional: return *(quatf*)&controller_state_.GetOr
asimjour 2016/09/22 14:48:35 replaced with controller_state_.GetOrientation()
+ controller_state_.GetOrientation().qy,
+ controller_state_.GetOrientation().qz,
+ controller_state_.GetOrientation().qw};
+ return orientation;
+}
+
+bool VrController::IsTouchDown() {
+ return controller_state_.GetTouchDown();
+}
+
+bool VrController::IsTouchUp() {
+ return controller_state_.GetTouchUp();
+}
+
+bool VrController::ButtonDown(const int32_t button) {
+ return controller_state_.GetButtonDown(button);
+}
+
+bool VrController::ButtonUp(const int32_t button) {
+ return controller_state_.GetButtonUp(button);
+}
+
+bool VrController::IsConnected() {
+ return controller_state_.GetConnectionState() == gvr::kControllerConnected;
+}
+
+void VrController::UpdateState() {
+ const int32_t old_status = controller_state_.GetApiStatus();
+ const int32_t old_connection_state = controller_state_.GetConnectionState();
+ // Read current controller state.
+ controller_state_.Update(*controller_api_);
+ // Print new API status and connection state, if they changed.
+ if (controller_state_.GetApiStatus() != old_status ||
+ controller_state_.GetConnectionState() != old_connection_state) {
+ VLOG(1) << "Controller Connection status: "
+ << gvr_controller_connection_state_to_string(
+ controller_state_.GetConnectionState());
+ }
+ return;
+}
+
+void VrController::Update(bool touch_up,
+ bool touch_down,
+ bool is_touching,
+ const vec2f position,
+ int64_t timestamp) {
+ if (touch_info_ == nullptr)
mthiesse 2016/09/21 16:13:43 CHECK(touch_info_ != nullptr) << "touch_info_ not
asimjour 2016/09/22 14:48:35 Done.
+ LOG(ERROR) << "touch_info_ not initialized properly.";
+ touch_info_->touch_up = touch_up;
+ touch_info_->touch_down = touch_down;
+ touch_info_->is_touching = is_touching;
+ touch_info_->touch_point.position = position;
+ clamp_touchpad_position(&(touch_info_->touch_point.position));
mthiesse 2016/09/21 16:13:43 nit: unnecessary parens
asimjour 2016/09/22 14:48:35 Done.
+ touch_info_->touch_point.timestamp = timestamp;
+
+ UpdateGestureFromTouchInfo();
+}
+
+void VrController::Initialize(gvr_context_* gvr_context) {
+ controller_api_.reset(new gvr::ControllerApi);
+ CHECK(controller_api_);
mthiesse 2016/09/21 16:13:43 unnecessary CHECK. Did you mean to CHECK gvr_conte
asimjour 2016/09/22 14:48:35 Done.
+ int32_t options = gvr::ControllerApi::DefaultOptions();
+ // Enable non-default options, if you need them:
+ // options |= GVR_CONTROLLER_ENABLE_GYRO;
+ CHECK(controller_api_->Init(options, gvr_context));
+ controller_api_->Resume();
+}
+
+VrGesture VrController::DetectGesture() {
+ if (controller_state_.GetConnectionState() == gvr::kControllerConnected) {
+ vec2f position;
+ position.x = TouchPosX();
+ position.y = TouchPosY();
+ Update(IsTouchUp(), IsTouchDown(), IsTouching(), position,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos);
+ if (GetGestureListSize() > 0 &&
+ GetGesturePtr(0)->type == kGestureTypeScroll) {
+ switch (GetGesturePtr(0)->details.scroll.state) {
+ case GESTURE_EVENT_TYPE_SCROLL_START:
+ return VrGesture(
+ kGestureScroll,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor,
+ GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor,
+ GESTURE_EVENT_TYPE_SCROLL_START, Orientation());
+ case GESTURE_EVENT_TYPE_SCROLL_END:
+ return VrGesture(
+ kGestureScroll,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, 0, 0,
+ GESTURE_EVENT_TYPE_SCROLL_END, Orientation());
+ case GESTURE_EVENT_TYPE_SCROLL_BY:
+ return VrGesture(
+ kGestureScroll,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ GetGesturePtr(0)->displacement.x * kDisplacementScaleFactor,
+ GetGesturePtr(0)->displacement.y * kDisplacementScaleFactor,
+ GESTURE_EVENT_TYPE_SCROLL_BY, Orientation());
+ }
+ }
+
+ if (ButtonDown(gvr::kControllerButtonClick)) {
+ return VrGesture(
+ kGestureButtonsChange,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos, 1, 0,
+ Orientation());
+ }
+ float dqx = 0.0f;
+
+ dqx = last_qx - Orientation().qx;
+ last_qx = Orientation().qx;
+
+ if (ButtonDown(gvr::kControllerButtonApp))
+ zoom_in_progress = true;
+ if (ButtonUp(gvr::kControllerButtonApp)) {
+ zoom_in_progress = false;
+ if (pinch_started) {
+ pinch_started = false;
+ }
+ }
+ if (zoom_in_progress) {
+ if (dqx != 0.0f) {
+ return VrGesture(
+ kGestureZoom,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ (dqx * 2) + 1, Orientation());
mthiesse 2016/09/21 17:27:46 Can you comment on why * 2 + 1? Also, unnecessary
asimjour 2016/09/22 14:48:35 Done.
+ }
+ if (Orientation().qz < 0.25f && Orientation().qz > -0.25f &&
mthiesse 2016/09/21 17:27:46 Magic numbers to constants?
asimjour 2016/09/22 14:48:35 Done.
+ pinch_started) {
+ pinch_started = false;
+ }
+ }
+ return VrGesture(kGestureAngularMove,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos,
+ Orientation());
+ }
+ return VrGesture();
+}
+
+void VrController::UpdateGestureFromTouchInfo() {
+ // Clear the gesture list.
+ gesture_list_.clear();
+
+ switch (state_) {
+ // user has not put finger on touch pad.
+ case WAITING:
+ HandleWaitingState();
+ break;
+ // user has not started a gesture (by moving out of slop).
+ case TOUCHING:
+ HandleDetectingState();
+ break;
+ // user is scrolling on touchpad
+ case SCROLLING:
+ HandleScrollingState();
+ break;
+ default:
+ LOG(ERROR) << "Wrong gesture detector state: " << state_;
+ break;
+ }
+}
+
+const VrGesture* VrController::GetGesturePtr(const int index) {
mthiesse 2016/09/21 16:13:43 const size_t index?
asimjour 2016/09/22 14:48:35 Done.
+ if (index >= (int)gesture_list_.size())
mthiesse 2016/09/21 16:13:43 CHECK this
asimjour 2016/09/22 14:48:35 Done.
+ LOG(ERROR) << "The gesture index exceeds the size of gesture "
+ "list.";
mthiesse 2016/09/21 16:13:43 nit: I think this fits on previous line.
asimjour 2016/09/22 14:48:35 Done.
+ return const_cast<VrGesture*>(&gesture_list_[index]);
+}
+
+void VrController::Update(const gvr_controller_state* controller_state) {
+ // Update touch information.
+ if (touch_info_ == nullptr)
mthiesse 2016/09/21 16:13:43 CHECK this
asimjour 2016/09/22 14:48:35 Done.
+ LOG(ERROR) << "touch_info_ not initialized properly.";
+ touch_info_->touch_up = gvr_controller_state_get_touch_up(controller_state);
+ touch_info_->touch_down =
+ gvr_controller_state_get_touch_down(controller_state);
+ touch_info_->is_touching = gvr_controller_state_is_touching(controller_state);
+ touch_info_->touch_point.position.x =
+ gvr_controller_state_get_touch_pos(controller_state).x;
+ touch_info_->touch_point.position.y =
+ gvr_controller_state_get_touch_pos(controller_state).y;
+ clamp_touchpad_position(&(touch_info_->touch_point.position));
+ touch_info_->touch_point.timestamp =
+ gvr_controller_state_get_last_touch_timestamp(controller_state);
+
+ UpdateGestureFromTouchInfo();
+}
+
+void VrController::HandleWaitingState() {
+ // user puts finger on touch pad (or when the touch down for current gesture
mthiesse 2016/09/21 16:13:43 nit: Capital and period. Also below
asimjour 2016/09/22 14:48:35 Done.
+ // is missed, initiate gesture from current touch point)
+ if (touch_info_->touch_down || touch_info_->is_touching) {
+ // update initial touchpoint
+ *init_touch_point_ = touch_info_->touch_point;
+ // update current touchpoint
+ *cur_touch_point_ = touch_info_->touch_point;
+ state_ = TOUCHING;
+ }
+}
+
+void VrController::HandleDetectingState() {
+ // user lifts up finger from touch pad.
+ if (touch_info_->touch_up || !(touch_info_->is_touching)) {
+ Reset();
+ return;
+ }
+
+ // Touch position is changed and the touch point moves outside of slop
+ if (UpdateCurrentTouchpoint() && touch_info_->is_touching &&
+ !InSlop(touch_info_->touch_point.position)) {
+ state_ = SCROLLING;
+ VrGesture gesture;
+ gesture.type = kGestureTypeScroll;
+ gesture.details.scroll.state = GESTURE_EVENT_TYPE_SCROLL_START;
+ UpdateGesture(&gesture);
+ gesture_list_.push_back(gesture);
+ }
+}
+
+void VrController::HandleScrollingState() {
+ // Update current touch point.
+ bool touch_position_changed = UpdateCurrentTouchpoint();
+ if (touch_info_->touch_up || !(touch_info_->is_touching)) { // gesture ends
+ VrGesture scroll_end;
+ scroll_end.type = kGestureTypeScroll;
+ scroll_end.details.scroll.state = GESTURE_EVENT_TYPE_SCROLL_END;
+ UpdateGesture(&scroll_end);
+ gesture_list_.push_back(scroll_end);
+
+ Reset();
+ } else if (touch_position_changed) { // User continues scrolling and there is
+ // a change in touch position.
+ VrGesture scroll_update;
+ scroll_update.type = kGestureTypeScroll;
+ scroll_update.details.scroll.state = GESTURE_EVENT_TYPE_SCROLL_BY;
+ UpdateGesture(&scroll_update);
+ gesture_list_.push_back(scroll_update);
+ }
+}
+
+bool VrController::InSlop(const vec2f touch_position) {
+ return (std::abs(touch_position.x - init_touch_point_->position.x) <
+ kSlopHorizontal) &&
+ (std::abs(touch_position.y - init_touch_point_->position.y) <
+ kSlopVertical);
+}
+
+void VrController::Reset() {
+ // Reset state.
+ state_ = WAITING;
+
+ // Reset the pointers.
+ prev_touch_point_.reset(new TouchPoint);
+ cur_touch_point_.reset(new TouchPoint);
+ init_touch_point_.reset(new TouchPoint);
+ touch_info_.reset(new TouchInfo);
+ vect_set_zero(&overall_velocity_);
+}
+
+void VrController::UpdateGesture(VrGesture* gesture) {
+ if (!gesture)
+ LOG(ERROR) << "The gesture pointer is not initiated properly.";
+ gesture->velocity = overall_velocity_;
+ gesture->displacement =
+ vect_subtract(cur_touch_point_->position, prev_touch_point_->position);
+}
+
+bool VrController::UpdateCurrentTouchpoint() {
+ if (touch_info_->is_touching || touch_info_->touch_up) {
+ // Update the touch point when the touch position has changed.
+ if (!vect_equal(cur_touch_point_->position,
+ touch_info_->touch_point.position)) {
+ prev_touch_point_.swap(cur_touch_point_);
+ *cur_touch_point_ = touch_info_->touch_point;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace vr_shell

Powered by Google App Engine
This is Rietveld 408576698