Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" | 5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" |
| 6 | 6 |
| 7 #include <chrono> | 7 #include <chrono> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "chrome/browser/android/vr_shell/ui_scene_manager.h" | 21 #include "chrome/browser/android/vr_shell/ui_scene_manager.h" |
| 22 #include "chrome/browser/android/vr_shell/vr_controller.h" | 22 #include "chrome/browser/android/vr_shell/vr_controller.h" |
| 23 #include "chrome/browser/android/vr_shell/vr_gl_thread.h" | 23 #include "chrome/browser/android/vr_shell/vr_gl_thread.h" |
| 24 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 24 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
| 25 #include "chrome/browser/android/vr_shell/vr_shell.h" | 25 #include "chrome/browser/android/vr_shell/vr_shell.h" |
| 26 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" | 26 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" |
| 27 #include "device/vr/android/gvr/gvr_delegate.h" | 27 #include "device/vr/android/gvr/gvr_delegate.h" |
| 28 #include "device/vr/android/gvr/gvr_device.h" | 28 #include "device/vr/android/gvr/gvr_device.h" |
| 29 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h" | 29 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h" |
| 30 #include "device/vr/vr_math.h" | 30 #include "device/vr/vr_math.h" |
| 31 #include "third_party/WebKit/public/platform/WebGestureEvent.h" | |
| 31 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 32 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| 32 #include "third_party/WebKit/public/platform/WebMouseEvent.h" | 33 #include "third_party/WebKit/public/platform/WebMouseEvent.h" |
| 33 #include "ui/gl/android/scoped_java_surface.h" | 34 #include "ui/gl/android/scoped_java_surface.h" |
| 34 #include "ui/gl/android/surface_texture.h" | 35 #include "ui/gl/android/surface_texture.h" |
| 35 #include "ui/gl/gl_bindings.h" | 36 #include "ui/gl/gl_bindings.h" |
| 36 #include "ui/gl/gl_context.h" | 37 #include "ui/gl/gl_context.h" |
| 37 #include "ui/gl/gl_surface.h" | 38 #include "ui/gl/gl_surface.h" |
| 38 #include "ui/gl/init/gl_factory.h" | 39 #include "ui/gl/init/gl_factory.h" |
| 39 | 40 |
| 40 namespace vr_shell { | 41 namespace vr_shell { |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 result.m[0][2] = A; | 131 result.m[0][2] = A; |
| 131 result.m[1][1] = Y; | 132 result.m[1][1] = Y; |
| 132 result.m[1][2] = B; | 133 result.m[1][2] = B; |
| 133 result.m[2][2] = C; | 134 result.m[2][2] = C; |
| 134 result.m[2][3] = D; | 135 result.m[2][3] = D; |
| 135 result.m[3][2] = -1; | 136 result.m[3][2] = -1; |
| 136 | 137 |
| 137 return result; | 138 return result; |
| 138 } | 139 } |
| 139 | 140 |
| 140 std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent(WebInputEvent::Type type, | 141 std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent( |
| 141 double timestamp, | 142 blink::WebInputEvent::Type type, |
| 142 float x, | 143 double timestamp, |
| 143 float y) { | 144 const gfx::Point& loc) { |
| 144 std::unique_ptr<blink::WebMouseEvent> mouse_event(new blink::WebMouseEvent( | 145 std::unique_ptr<blink::WebMouseEvent> mouse_event(new blink::WebMouseEvent( |
| 145 type, blink::WebInputEvent::kNoModifiers, timestamp)); | 146 type, blink::WebInputEvent::kNoModifiers, timestamp)); |
| 146 mouse_event->pointer_type = blink::WebPointerProperties::PointerType::kMouse; | 147 mouse_event->pointer_type = blink::WebPointerProperties::PointerType::kMouse; |
| 147 mouse_event->SetPositionInWidget(x, y); | 148 mouse_event->SetPositionInWidget(loc.x(), loc.y()); |
| 148 mouse_event->click_count = 1; | 149 mouse_event->click_count = 1; |
| 149 | 150 |
| 150 return mouse_event; | 151 return mouse_event; |
| 151 } | 152 } |
| 152 | 153 |
| 153 enum class ViewerType { | 154 enum class ViewerType { |
| 154 UNKNOWN_TYPE = 0, | 155 UNKNOWN_TYPE = 0, |
| 155 CARDBOARD = 1, | 156 CARDBOARD = 1, |
| 156 DAYDREAM = 2, | 157 DAYDREAM = 2, |
| 157 VIEWER_TYPE_MAX, | 158 VIEWER_TYPE_MAX, |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 176 gvr::Rectf UVFromGfxRect(gfx::RectF rect) { | 177 gvr::Rectf UVFromGfxRect(gfx::RectF rect) { |
| 177 return {rect.x(), rect.x() + rect.width(), 1.0f - rect.bottom(), | 178 return {rect.x(), rect.x() + rect.width(), 1.0f - rect.bottom(), |
| 178 1.0f - rect.y()}; | 179 1.0f - rect.y()}; |
| 179 } | 180 } |
| 180 | 181 |
| 181 gfx::RectF GfxRectFromUV(gvr::Rectf rect) { | 182 gfx::RectF GfxRectFromUV(gvr::Rectf rect) { |
| 182 return gfx::RectF(rect.left, 1.0 - rect.top, rect.right - rect.left, | 183 return gfx::RectF(rect.left, 1.0 - rect.top, rect.right - rect.left, |
| 183 rect.top - rect.bottom); | 184 rect.top - rect.bottom); |
| 184 } | 185 } |
| 185 | 186 |
| 187 double NowSeconds() { | |
| 188 return (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); | |
| 189 } | |
| 190 | |
| 186 } // namespace | 191 } // namespace |
| 187 | 192 |
| 188 VrShellGl::VrShellGl(VrBrowserInterface* browser, | 193 VrShellGl::VrShellGl(VrBrowserInterface* browser, |
| 189 gvr_context* gvr_api, | 194 gvr_context* gvr_api, |
| 190 bool initially_web_vr, | 195 bool initially_web_vr, |
| 191 bool reprojected_rendering, | 196 bool reprojected_rendering, |
| 192 UiScene* scene) | 197 UiScene* scene) |
| 193 : web_vr_mode_(initially_web_vr), | 198 : web_vr_mode_(initially_web_vr), |
| 194 surfaceless_rendering_(reprojected_rendering), | 199 surfaceless_rendering_(reprojected_rendering), |
| 195 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 200 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 } | 502 } |
| 498 | 503 |
| 499 void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) { | 504 void VrShellGl::UpdateController(const gfx::Vector3dF& head_direction) { |
| 500 controller_->UpdateState(head_direction); | 505 controller_->UpdateState(head_direction); |
| 501 pointer_start_ = controller_->GetPointerStart(); | 506 pointer_start_ = controller_->GetPointerStart(); |
| 502 | 507 |
| 503 browser_->UpdateGamepadData(controller_->GetGamepadData()); | 508 browser_->UpdateGamepadData(controller_->GetGamepadData()); |
| 504 } | 509 } |
| 505 | 510 |
| 506 void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) { | 511 void VrShellGl::HandleControllerInput(const gfx::Vector3dF& head_direction) { |
| 507 if (ShouldDrawWebVr()) { | 512 HandleWebVrCompatClick(); |
|
cjgrant
2017/05/10 20:16:25
s/Compat/Compatibility/
mthiesse
2017/05/10 21:09:08
Done.
| |
| 508 // Process screen touch events for Cardboard button compatibility. | |
| 509 // Also send tap events for controller "touchpad click" events. | |
| 510 if (touch_pending_ || | |
| 511 controller_->ButtonUpHappened( | |
| 512 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) { | |
| 513 touch_pending_ = false; | |
| 514 std::unique_ptr<WebGestureEvent> gesture(new WebGestureEvent( | |
| 515 WebInputEvent::kGestureTapDown, WebInputEvent::kNoModifiers, | |
| 516 (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF())); | |
| 517 gesture->source_device = blink::kWebGestureDeviceTouchpad; | |
| 518 gesture->x = 0; | |
| 519 gesture->y = 0; | |
| 520 SendGestureToContent(std::move(gesture)); | |
| 521 DVLOG(1) << __FUNCTION__ << ": sent CLICK gesture"; | |
| 522 } | |
| 523 } | |
| 524 | 513 |
| 525 gfx::Vector3dF ergo_neutral_pose; | 514 gfx::Vector3dF ergo_neutral_pose; |
| 526 if (!controller_->IsConnected()) { | 515 if (!controller_->IsConnected()) { |
| 527 // No controller detected, set up a gaze cursor that tracks the | 516 // No controller detected, set up a gaze cursor that tracks the |
| 528 // forward direction. | 517 // forward direction. |
| 529 ergo_neutral_pose = {0.0f, 0.0f, -1.0f}; | 518 ergo_neutral_pose = {0.0f, 0.0f, -1.0f}; |
| 530 controller_quat_ = GetRotationFromZAxis(head_direction); | 519 controller_quat_ = GetRotationFromZAxis(head_direction); |
| 531 } else { | 520 } else { |
| 532 ergo_neutral_pose = {0.0f, -sin(kErgoAngleOffset), -cos(kErgoAngleOffset)}; | 521 ergo_neutral_pose = {0.0f, -sin(kErgoAngleOffset), -cos(kErgoAngleOffset)}; |
| 533 controller_quat_ = controller_->Orientation(); | 522 controller_quat_ = controller_->Orientation(); |
| 534 } | 523 } |
| 535 | 524 |
| 536 vr::Mat4f mat; | 525 vr::Mat4f mat; |
| 537 QuatToMatrix(controller_quat_, &mat); | 526 QuatToMatrix(controller_quat_, &mat); |
| 538 gfx::Vector3dF controller_direction = | 527 gfx::Vector3dF controller_direction = |
| 539 vr::MatrixVectorMul(mat, ergo_neutral_pose); | 528 vr::MatrixVectorMul(mat, ergo_neutral_pose); |
| 540 | 529 |
| 541 HandleControllerAppButtonActivity(controller_direction); | 530 HandleControllerAppButtonActivity(controller_direction); |
| 542 | 531 |
| 543 if (ShouldDrawWebVr()) { | 532 if (ShouldDrawWebVr()) |
| 544 return; | 533 return; |
|
cjgrant
2017/05/10 20:16:26
Blank line after return?
mthiesse
2017/05/10 21:09:08
Done.
| |
| 545 } | 534 gfx::PointF target_local_point; |
| 546 | 535 gfx::Vector3dF eye_to_target; |
| 536 cursor_render_target_ = nullptr; | |
| 537 GetVisualTargetElement(controller_direction, eye_to_target, target_point_, | |
| 538 &cursor_render_target_, target_local_point); | |
| 539 | |
| 540 UiElement* target_element = nullptr; | |
| 541 if (input_locked_element_) { | |
| 542 gfx::Point3F plane_intersection_point; | |
| 543 float distance_to_plane; | |
| 544 GetTargetLocalPoint(eye_to_target, *input_locked_element_, | |
| 545 2 * scene_->GetBackgroundDistance(), target_local_point, | |
| 546 plane_intersection_point, distance_to_plane); | |
| 547 target_element = input_locked_element_; | |
| 548 } else if (!in_scroll_ && !in_click_) { | |
| 549 target_element = cursor_render_target_; | |
| 550 } | |
| 551 | |
| 552 // Handle input targeting on the content quad, ignoring any other elements. | |
| 553 // Content is treated specially to accomodate scrolling, flings, etc. | |
| 554 gfx::Point local_point_pixels; | |
| 555 if (target_element && (target_element->fill() == Fill::CONTENT)) { | |
| 556 gfx::RectF pixel_rect(0, 0, content_tex_css_width_, | |
| 557 content_tex_css_height_); | |
| 558 local_point_pixels.set_x(pixel_rect.x() + | |
| 559 pixel_rect.width() * target_local_point.x()); | |
| 560 local_point_pixels.set_y(pixel_rect.y() + | |
| 561 pixel_rect.height() * target_local_point.y()); | |
| 562 } | |
| 563 std::unique_ptr<GestureList> gesture_list_ptr = controller_->DetectGestures(); | |
| 564 GestureList& gesture_list = *gesture_list_ptr; | |
| 565 for (const std::unique_ptr<blink::WebGestureEvent>& gesture : gesture_list) { | |
| 566 gesture->x = local_point_pixels.x(); | |
| 567 gesture->y = local_point_pixels.y(); | |
| 568 } | |
| 569 SendFlingCancel(gesture_list); | |
| 570 // For simplicity, don't allow scrolling while clicking until we need to. | |
| 571 if (!in_click_) { | |
| 572 SendScrollEnd(gesture_list); | |
| 573 if (!SendScrollBegin(target_element, gesture_list)) { | |
| 574 SendScrollUpdate(gesture_list); | |
| 575 } | |
| 576 } | |
| 577 // If we're still scrolling, don't hover (and we can't be clicking, because | |
| 578 // click ends scroll). | |
| 579 if (in_scroll_) | |
| 580 return; | |
| 581 SendHoverLeave(target_element); | |
| 582 if (!SendHoverEnter(target_element, target_local_point, local_point_pixels)) { | |
| 583 SendHoverMove(target_local_point, local_point_pixels); | |
| 584 } | |
| 585 SendButtonDown(target_element, target_local_point); | |
| 586 if (!SendButtonUp(target_element, target_local_point)) | |
| 587 SendTap(target_element, target_local_point, local_point_pixels); | |
| 588 } | |
| 589 | |
| 590 void VrShellGl::HandleWebVrCompatClick() { | |
| 591 if (!ShouldDrawWebVr()) | |
| 592 return; | |
| 593 // Process screen touch events for Cardboard button compatibility. | |
| 594 // Also send tap events for controller "touchpad click" events. | |
| 595 if (touch_pending_ || | |
| 596 controller_->ButtonUpHappened(gvr::kControllerButtonClick)) { | |
| 597 touch_pending_ = false; | |
| 598 std::unique_ptr<blink::WebGestureEvent> gesture(new blink::WebGestureEvent( | |
| 599 blink::WebInputEvent::kGestureTapDown, | |
| 600 blink::WebInputEvent::kNoModifiers, NowSeconds())); | |
| 601 gesture->source_device = blink::kWebGestureDeviceTouchpad; | |
| 602 gesture->x = 0; | |
| 603 gesture->y = 0; | |
| 604 SendGestureToContent(std::move(gesture)); | |
| 605 DVLOG(1) << __FUNCTION__ << ": sent CLICK gesture"; | |
| 606 } | |
| 607 } | |
| 608 | |
| 609 void VrShellGl::SendFlingCancel(GestureList& gesture_list) { | |
| 610 if (!fling_target_) | |
| 611 return; | |
| 612 if (gesture_list.empty() || (gesture_list.front()->GetType() != | |
| 613 blink::WebInputEvent::kGestureFlingCancel)) | |
| 614 return; | |
| 615 // Scrolling currently only supported on content window. | |
| 616 DCHECK_EQ(fling_target_->fill(), Fill::CONTENT); | |
| 617 SendGestureToContent(std::move(gesture_list.front())); | |
| 618 gesture_list.erase(gesture_list.begin()); | |
| 619 } | |
| 620 | |
| 621 void VrShellGl::SendScrollEnd(GestureList& gesture_list) { | |
| 622 if (!in_scroll_) | |
| 623 return; | |
| 624 DCHECK_NE(input_locked_element_, nullptr); | |
| 625 if (controller_->ButtonDownHappened(gvr::kControllerButtonClick)) { | |
| 626 DCHECK_GT(gesture_list.size(), 0LU); | |
| 627 DCHECK_EQ(gesture_list.front()->GetType(), | |
| 628 blink::WebInputEvent::kGestureScrollEnd); | |
| 629 } | |
| 630 // Scrolling currently only supported on content window. | |
| 631 DCHECK_EQ(input_locked_element_->fill(), Fill::CONTENT); | |
| 632 if (gesture_list.empty() || (gesture_list.front()->GetType() != | |
| 633 blink::WebInputEvent::kGestureScrollEnd)) | |
| 634 return; | |
| 635 DCHECK_LE(gesture_list.size(), 2LU); | |
| 636 SendGestureToContent(std::move(gesture_list.front())); | |
| 637 gesture_list.erase(gesture_list.begin()); | |
| 638 if (!gesture_list.empty()) { | |
| 639 DCHECK_EQ(gesture_list.front()->GetType(), | |
| 640 blink::WebInputEvent::kGestureFlingStart); | |
| 641 SendGestureToContent(std::move(gesture_list.front())); | |
| 642 fling_target_ = input_locked_element_; | |
| 643 gesture_list.erase(gesture_list.begin()); | |
| 644 } | |
| 645 input_locked_element_ = nullptr; | |
| 646 in_scroll_ = false; | |
| 647 } | |
| 648 | |
| 649 bool VrShellGl::SendScrollBegin(UiElement* target, GestureList& gesture_list) { | |
| 650 if (in_scroll_ || !target) | |
| 651 return false; | |
| 652 // Scrolling currently only supported on content window. | |
| 653 if (target->fill() != Fill::CONTENT) | |
| 654 return false; | |
| 655 if (gesture_list.empty() || (gesture_list.front()->GetType() != | |
| 656 blink::WebInputEvent::kGestureScrollBegin)) | |
| 657 return false; | |
| 658 input_locked_element_ = target; | |
| 659 in_scroll_ = true; | |
| 660 | |
| 661 SendGestureToContent(std::move(gesture_list.front())); | |
| 662 gesture_list.erase(gesture_list.begin()); | |
| 663 return true; | |
| 664 } | |
| 665 | |
| 666 void VrShellGl::SendScrollUpdate(GestureList& gesture_list) { | |
| 667 if (!in_scroll_) | |
| 668 return; | |
| 669 DCHECK(input_locked_element_); | |
| 670 if (gesture_list.empty() || (gesture_list.front()->GetType() != | |
| 671 blink::WebInputEvent::kGestureScrollUpdate)) | |
| 672 return; | |
| 673 // Scrolling currently only supported on content window. | |
| 674 DCHECK_EQ(input_locked_element_->fill(), Fill::CONTENT); | |
| 675 SendGestureToContent(std::move(gesture_list.front())); | |
| 676 gesture_list.erase(gesture_list.begin()); | |
| 677 } | |
| 678 | |
| 679 void VrShellGl::SendHoverLeave(UiElement* target) { | |
| 680 if (!hover_target_ || (target == hover_target_)) | |
| 681 return; | |
| 682 if (hover_target_->fill() == Fill::CONTENT) { | |
| 683 SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseLeave, | |
| 684 NowSeconds(), gfx::Point())); | |
| 685 } else { | |
| 686 hover_target_->OnHoverLeave(); | |
| 687 } | |
| 688 hover_target_ = nullptr; | |
| 689 } | |
| 690 | |
| 691 bool VrShellGl::SendHoverEnter(UiElement* target, | |
| 692 const gfx::PointF& target_point, | |
| 693 const gfx::Point& local_point_pixels) { | |
| 694 if (!target || target == hover_target_) | |
| 695 return false; | |
| 696 if (target->fill() == Fill::CONTENT) { | |
| 697 SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseEnter, | |
| 698 NowSeconds(), local_point_pixels)); | |
| 699 } else { | |
| 700 target->OnHoverEnter(target_point); | |
| 701 } | |
| 702 hover_target_ = target; | |
| 703 return true; | |
| 704 } | |
| 705 | |
| 706 void VrShellGl::SendHoverMove(const gfx::PointF& target_point, | |
| 707 const gfx::Point& local_point_pixels) { | |
| 708 if (!hover_target_) | |
| 709 return; | |
| 710 if (hover_target_->fill() == Fill::CONTENT) { | |
| 711 SendGestureToContent(MakeMouseEvent(blink::WebInputEvent::kMouseMove, | |
| 712 NowSeconds(), local_point_pixels)); | |
| 713 } else { | |
| 714 hover_target_->OnMove(target_point); | |
| 715 } | |
| 716 } | |
| 717 | |
| 718 void VrShellGl::SendButtonDown(UiElement* target, | |
| 719 const gfx::PointF& target_point) { | |
| 720 if (in_click_) | |
| 721 return; | |
| 722 if (!controller_->ButtonDownHappened(gvr::kControllerButtonClick)) | |
|
cjgrant
2017/05/10 20:16:26
Isn't it more intuitive to not call SendButtonDown
mthiesse
2017/05/10 21:09:08
So this is a stylistic choice. I decided to avoid
| |
| 723 return; | |
| 724 input_locked_element_ = target; | |
| 725 in_click_ = true; | |
| 726 // We don't support down/up for content yet. | |
| 727 if (!target || target->fill() == Fill::CONTENT) | |
| 728 return; | |
| 729 target->OnButtonDown(target_point); | |
| 730 } | |
| 731 | |
| 732 bool VrShellGl::SendButtonUp(UiElement* target, | |
| 733 const gfx::PointF& target_point) { | |
| 734 if (!in_click_) | |
| 735 return false; | |
| 736 if (!controller_->ButtonUpHappened(gvr::kControllerButtonClick)) | |
| 737 return false; | |
| 738 DCHECK(input_locked_element_ == target); | |
| 739 input_locked_element_ = nullptr; | |
| 740 in_click_ = false; | |
| 741 // We don't support down/up for content yet. | |
| 742 if (target->fill() == Fill::CONTENT) | |
| 743 return false; | |
| 744 target->OnButtonUp(target_point); | |
| 745 return true; | |
| 746 } | |
| 747 | |
| 748 void VrShellGl::SendTap(UiElement* target, | |
| 749 const gfx::PointF& target_point, | |
| 750 const gfx::Point& local_point_pixels) { | |
| 751 if (!target) | |
| 752 return; | |
| 753 if (controller_->ButtonUpHappened(gvr::kControllerButtonClick) && | |
| 754 target->fill() == Fill::CONTENT) | |
| 755 touch_pending_ = true; | |
| 756 if (!touch_pending_) | |
| 757 return; | |
| 758 touch_pending_ = false; | |
| 759 if (target->fill() == Fill::CONTENT) { | |
| 760 auto gesture = base::MakeUnique<blink::WebGestureEvent>( | |
| 761 blink::WebInputEvent::kGestureTapDown, | |
| 762 blink::WebInputEvent::kNoModifiers, NowSeconds()); | |
| 763 gesture->source_device = blink::kWebGestureDeviceTouchpad; | |
| 764 gesture->x = local_point_pixels.x(); | |
| 765 gesture->y = local_point_pixels.y(); | |
| 766 SendGestureToContent(std::move(gesture)); | |
| 767 } else { | |
| 768 target->OnButtonDown(target_point); | |
| 769 target->OnButtonUp(target_point); | |
| 770 } | |
| 771 } | |
| 772 | |
| 773 void VrShellGl::GetVisualTargetElement( | |
| 774 const gfx::Vector3dF& controller_direction, | |
| 775 gfx::Vector3dF& eye_to_target, | |
| 776 gfx::Point3F& target_point, | |
| 777 UiElement** target_element, | |
| 778 gfx::PointF& target_local_point) const { | |
| 547 // If we place the reticle based on elements intersecting the controller beam, | 779 // If we place the reticle based on elements intersecting the controller beam, |
| 548 // we can end up with the reticle hiding behind elements, or jumping laterally | 780 // we can end up with the reticle hiding behind elements, or jumping laterally |
| 549 // in the field of view. This is physically correct, but hard to use. For | 781 // in the field of view. This is physically correct, but hard to use. For |
| 550 // usability, do the following instead: | 782 // usability, do the following instead: |
| 551 // | 783 // |
| 552 // - Project the controller laser onto a distance-limiting sphere. | 784 // - Project the controller laser onto a distance-limiting sphere. |
| 553 // - Create a vector between the eyes and the outer surface point. | 785 // - Create a vector between the eyes and the outer surface point. |
| 554 // - If any UI elements intersect this vector, and is within the bounding | 786 // - If any UI elements intersect this vector, and is within the bounding |
| 555 // sphere, choose the closest to the eyes, and place the reticle at the | 787 // sphere, choose the closest to the eyes, and place the reticle at the |
| 556 // intersection point. | 788 // intersection point. |
| 557 | 789 |
| 558 // Compute the distance from the eyes to the distance limiting sphere. Note | 790 // Compute the distance from the eyes to the distance limiting sphere. Note |
| 559 // that the sphere is centered at the controller, rather than the eye, for | 791 // that the sphere is centered at the controller, rather than the eye, for |
| 560 // simplicity. | 792 // simplicity. |
| 561 float distance = scene_->GetBackgroundDistance(); | 793 float distance = scene_->GetBackgroundDistance(); |
| 562 target_point_ = | 794 target_point = |
| 563 vr::GetRayPoint(pointer_start_, controller_direction, distance); | 795 vr::GetRayPoint(pointer_start_, controller_direction, distance); |
| 564 gfx::Vector3dF eye_to_target = target_point_ - kOrigin; | 796 eye_to_target = target_point - kOrigin; |
| 565 vr::NormalizeVector(&eye_to_target); | 797 vr::NormalizeVector(&eye_to_target); |
| 566 | 798 |
| 567 // Determine which UI element (if any) intersects the line between the eyes | 799 // Determine which UI element (if any) intersects the line between the eyes |
| 568 // and the controller target position. | 800 // and the controller target position. |
| 569 float closest_element_distance = (target_point_ - kOrigin).Length(); | 801 float closest_element_distance = (target_point - kOrigin).Length(); |
| 570 previous_target_element_ = target_element_; | |
| 571 target_element_ = nullptr; | |
| 572 float target_x; | |
| 573 float target_y; | |
| 574 | 802 |
| 575 for (auto& plane : scene_->GetUiElements()) { | 803 for (auto& element : scene_->GetUiElements()) { |
| 576 if (!plane->IsHitTestable()) | 804 if (!element->IsHitTestable()) |
| 805 continue; | |
| 806 gfx::PointF local_point; | |
| 807 gfx::Point3F plane_intersection_point; | |
| 808 float distance_to_plane; | |
| 809 if (!GetTargetLocalPoint(eye_to_target, *element.get(), | |
|
cjgrant
2017/05/10 20:16:26
So to be totally clear, the idea of having an elem
mthiesse
2017/05/10 21:09:08
yes.
| |
| 810 closest_element_distance, local_point, | |
| 811 plane_intersection_point, distance_to_plane)) | |
| 577 continue; | 812 continue; |
| 578 | 813 |
| 579 float distance_to_plane; | 814 if (local_point.x() < 0.0f || local_point.x() >= 1.0f || |
| 580 if (!plane->GetRayDistance(kOrigin, eye_to_target, &distance_to_plane)) | 815 local_point.y() < 0.0f || local_point.y() >= 1.0f) |
| 581 continue; | |
| 582 | |
| 583 if (distance_to_plane < 0 || distance_to_plane >= closest_element_distance) | |
| 584 continue; | |
| 585 | |
| 586 gfx::Point3F plane_intersection_point = | |
| 587 vr::GetRayPoint(kOrigin, eye_to_target, distance_to_plane); | |
| 588 gfx::PointF unit_xy_point = | |
| 589 plane->GetUnitRectangleCoordinates(plane_intersection_point); | |
| 590 | |
| 591 float x = 0.5f + unit_xy_point.x(); | |
| 592 float y = 0.5f - unit_xy_point.y(); | |
| 593 if (x < 0.0f || x >= 1.0f || y < 0.0f || y >= 1.0f) | |
| 594 continue; | 816 continue; |
| 595 | 817 |
| 596 closest_element_distance = distance_to_plane; | 818 closest_element_distance = distance_to_plane; |
| 597 target_point_ = plane_intersection_point; | 819 target_point = plane_intersection_point; |
| 598 target_element_ = plane.get(); | 820 *target_element = element.get(); |
| 599 target_x = x; | 821 target_local_point = local_point; |
| 600 target_y = y; | |
| 601 } | 822 } |
| 823 } | |
| 602 | 824 |
| 603 // Handle input targeting on the content quad, ignoring any other elements. | 825 bool VrShellGl::GetTargetLocalPoint(const gfx::Vector3dF& eye_to_target, |
| 604 // Content is treated specially to accomodate scrolling, flings, etc. | 826 const UiElement& element, |
| 605 InputTarget input_target = InputTarget::NONE; | 827 float max_distance_to_plane, |
| 606 int pixel_x = 0; | 828 gfx::PointF& target_local_point, |
| 607 int pixel_y = 0; | 829 gfx::Point3F& target_point, |
| 608 if (target_element_ != nullptr && target_element_->fill() == Fill::CONTENT) { | 830 float& distance_to_plane) const { |
| 609 input_target = InputTarget::CONTENT; | 831 if (!element.GetRayDistance(kOrigin, eye_to_target, &distance_to_plane)) |
| 610 gfx::RectF pixel_rect(0, 0, content_tex_css_width_, | 832 return false; |
| 611 content_tex_css_height_); | |
| 612 pixel_x = pixel_rect.x() + pixel_rect.width() * target_x; | |
| 613 pixel_y = pixel_rect.y() + pixel_rect.height() * target_y; | |
| 614 } | |
| 615 SendInputToContent(input_target, pixel_x, pixel_y); | |
| 616 | 833 |
| 617 // Handle input targeting on all non-content elements. | 834 if (distance_to_plane < 0 || distance_to_plane >= max_distance_to_plane) |
| 618 SendInputToUiElements(target_element_); | 835 return false; |
| 836 | |
| 837 target_point = vr::GetRayPoint(kOrigin, eye_to_target, distance_to_plane); | |
| 838 gfx::PointF unit_xy_point = element.GetUnitRectangleCoordinates(target_point); | |
| 839 | |
| 840 target_local_point.set_x(0.5f + unit_xy_point.x()); | |
| 841 target_local_point.set_y(0.5f - unit_xy_point.y()); | |
| 842 return true; | |
| 619 } | 843 } |
| 620 | 844 |
| 621 void VrShellGl::HandleControllerAppButtonActivity( | 845 void VrShellGl::HandleControllerAppButtonActivity( |
| 622 const gfx::Vector3dF& controller_direction) { | 846 const gfx::Vector3dF& controller_direction) { |
| 623 // Note that button up/down state is transient, so ButtonDownHappened only | 847 // Note that button up/down state is transient, so ButtonDownHappened only |
| 624 // returns true for a single frame (and we're guaranteed not to miss it). | 848 // returns true for a single frame (and we're guaranteed not to miss it). |
| 625 if (controller_->ButtonDownHappened( | 849 if (controller_->ButtonDownHappened( |
| 626 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_APP)) { | 850 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_APP)) { |
| 627 controller_start_direction_ = controller_direction; | 851 controller_start_direction_ = controller_direction; |
| 628 } | 852 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 641 direction = | 865 direction = |
| 642 gesture_xz_angle < 0 ? UiInterface::LEFT : UiInterface::RIGHT; | 866 gesture_xz_angle < 0 ? UiInterface::LEFT : UiInterface::RIGHT; |
| 643 browser_->AppButtonGesturePerformed(direction); | 867 browser_->AppButtonGesturePerformed(direction); |
| 644 } | 868 } |
| 645 } | 869 } |
| 646 if (direction == UiInterface::NONE) | 870 if (direction == UiInterface::NONE) |
| 647 browser_->AppButtonClicked(); | 871 browser_->AppButtonClicked(); |
| 648 } | 872 } |
| 649 } | 873 } |
| 650 | 874 |
| 651 void VrShellGl::SendInputToContent(InputTarget input_target, | |
| 652 int pixel_x, | |
| 653 int pixel_y) { | |
| 654 std::vector<std::unique_ptr<WebGestureEvent>> gesture_list = | |
| 655 controller_->DetectGestures(); | |
| 656 double timestamp = gesture_list.front()->TimeStampSeconds(); | |
| 657 | |
| 658 if (touch_pending_) { | |
| 659 touch_pending_ = false; | |
| 660 std::unique_ptr<WebGestureEvent> event( | |
| 661 new WebGestureEvent(WebInputEvent::kGestureTapDown, | |
| 662 WebInputEvent::kNoModifiers, timestamp)); | |
| 663 event->source_device = blink::kWebGestureDeviceTouchpad; | |
| 664 event->x = pixel_x; | |
| 665 event->y = pixel_y; | |
| 666 gesture_list.push_back(std::move(event)); | |
| 667 } | |
| 668 | |
| 669 for (auto& gesture : gesture_list) { | |
| 670 gesture->x = pixel_x; | |
| 671 gesture->y = pixel_y; | |
| 672 auto movableGesture = base::MakeUnique<WebGestureEvent>(*gesture); | |
| 673 | |
| 674 switch (gesture->GetType()) { | |
| 675 // Once the user starts scrolling send all the scroll events to this | |
| 676 // element until the scrolling stops. | |
| 677 case WebInputEvent::kGestureScrollBegin: | |
| 678 current_scroll_target_ = input_target; | |
| 679 if (current_scroll_target_ != InputTarget::NONE) { | |
| 680 SendGestureToContent(std::move(movableGesture)); | |
| 681 } | |
| 682 break; | |
| 683 case WebInputEvent::kGestureScrollEnd: | |
| 684 if (current_scroll_target_ != InputTarget::NONE) { | |
| 685 SendGestureToContent(std::move(movableGesture)); | |
| 686 } | |
| 687 current_fling_target_ = current_scroll_target_; | |
| 688 current_scroll_target_ = InputTarget::NONE; | |
| 689 break; | |
| 690 case WebInputEvent::kGestureScrollUpdate: | |
| 691 if (current_scroll_target_ != InputTarget::NONE) { | |
| 692 SendGestureToContent(std::move(movableGesture)); | |
| 693 } | |
| 694 break; | |
| 695 case WebInputEvent::kGestureFlingStart: | |
| 696 if (current_fling_target_ != InputTarget::NONE) { | |
| 697 SendGestureToContent(std::move(movableGesture)); | |
| 698 } | |
| 699 current_fling_target_ = InputTarget::NONE; | |
| 700 break; | |
| 701 case WebInputEvent::kGestureFlingCancel: | |
| 702 current_fling_target_ = InputTarget::NONE; | |
| 703 if (input_target != InputTarget::NONE) { | |
| 704 SendGestureToContent(std::move(movableGesture)); | |
| 705 } | |
| 706 break; | |
| 707 case WebInputEvent::kGestureTapDown: | |
| 708 current_fling_target_ = InputTarget::NONE; | |
| 709 if (input_target != InputTarget::NONE) { | |
| 710 SendGestureToContent(std::move(movableGesture)); | |
| 711 } | |
| 712 break; | |
| 713 case WebInputEvent::kUndefined: | |
| 714 break; | |
| 715 default: | |
| 716 NOTREACHED(); | |
| 717 } | |
| 718 } | |
| 719 | |
| 720 // Hover support | |
| 721 bool new_target = input_target != current_input_target_; | |
| 722 if (new_target && current_input_target_ != InputTarget::NONE) { | |
| 723 // Send a move event indicating that the pointer moved off of an element. | |
| 724 SendGestureToContent( | |
| 725 MakeMouseEvent(WebInputEvent::kMouseLeave, timestamp, 0, 0)); | |
| 726 } | |
| 727 current_input_target_ = input_target; | |
| 728 if (current_input_target_ != InputTarget::NONE) { | |
| 729 WebInputEvent::Type type = | |
| 730 new_target ? WebInputEvent::kMouseEnter : WebInputEvent::kMouseMove; | |
| 731 SendGestureToContent(MakeMouseEvent(type, timestamp, pixel_x, pixel_y)); | |
| 732 } | |
| 733 } | |
| 734 | |
| 735 void VrShellGl::SendInputToUiElements(UiElement* target_element) { | |
| 736 if (target_element != previous_target_element_) { | |
| 737 if (previous_target_element_ && | |
| 738 previous_target_element_->fill() != Fill::CONTENT) { | |
| 739 task_runner_->PostTask( | |
| 740 FROM_HERE, base::Bind(&UiElement::OnHoverLeave, | |
| 741 base::Unretained(previous_target_element_))); | |
| 742 } | |
| 743 if (target_element && target_element->fill() != Fill::CONTENT) { | |
| 744 task_runner_->PostTask(FROM_HERE, | |
| 745 base::Bind(&UiElement::OnHoverEnter, | |
| 746 base::Unretained(target_element))); | |
| 747 } | |
| 748 click_target_element_ = nullptr; | |
| 749 } | |
| 750 if (target_element && target_element->fill() != Fill::CONTENT) { | |
| 751 if (controller_->ButtonDownHappened( | |
| 752 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) { | |
| 753 task_runner_->PostTask(FROM_HERE, | |
| 754 base::Bind(&UiElement::OnButtonDown, | |
| 755 base::Unretained(target_element))); | |
| 756 click_target_element_ = target_element; | |
| 757 } | |
| 758 if (controller_->ButtonUpHappened( | |
| 759 gvr::ControllerButton::GVR_CONTROLLER_BUTTON_CLICK)) { | |
| 760 if (click_target_element_ == target_element) { | |
| 761 task_runner_->PostTask(FROM_HERE, | |
| 762 base::Bind(&UiElement::OnButtonUp, | |
| 763 base::Unretained(target_element))); | |
| 764 } | |
| 765 click_target_element_ = nullptr; | |
| 766 } | |
| 767 } | |
| 768 } | |
| 769 | |
| 770 void VrShellGl::SendGestureToContent( | 875 void VrShellGl::SendGestureToContent( |
| 771 std::unique_ptr<blink::WebInputEvent> event) { | 876 std::unique_ptr<blink::WebInputEvent> event) { |
| 772 browser_->ProcessContentGesture(std::move(event)); | 877 browser_->ProcessContentGesture(std::move(event)); |
| 773 } | 878 } |
| 774 | 879 |
| 775 void VrShellGl::DrawFrame(int16_t frame_index) { | 880 void VrShellGl::DrawFrame(int16_t frame_index) { |
| 776 TRACE_EVENT1("gpu", "VrShellGl::DrawFrame", "frame", frame_index); | 881 TRACE_EVENT1("gpu", "VrShellGl::DrawFrame", "frame", frame_index); |
| 777 | 882 |
| 778 base::TimeTicks current_time = base::TimeTicks::Now(); | 883 base::TimeTicks current_time = base::TimeTicks::Now(); |
| 779 | 884 |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1034 default: | 1139 default: |
| 1035 break; | 1140 break; |
| 1036 } | 1141 } |
| 1037 } | 1142 } |
| 1038 vr_shell_renderer_->Flush(); | 1143 vr_shell_renderer_->Flush(); |
| 1039 } | 1144 } |
| 1040 | 1145 |
| 1041 std::vector<const UiElement*> VrShellGl::GetElementsInDrawOrder( | 1146 std::vector<const UiElement*> VrShellGl::GetElementsInDrawOrder( |
| 1042 const vr::Mat4f& view_matrix, | 1147 const vr::Mat4f& view_matrix, |
| 1043 const std::vector<const UiElement*>& elements) { | 1148 const std::vector<const UiElement*>& elements) { |
| 1044 typedef std::pair<float, const UiElement*> DistanceElementPair; | 1149 std::vector<const UiElement*> sorted_elements = elements; |
| 1045 std::vector<DistanceElementPair> zOrderedElementPairs; | |
| 1046 zOrderedElementPairs.reserve(elements.size()); | |
| 1047 | |
| 1048 for (const auto* element : elements) { | |
| 1049 // Distance is the abs(z) value in view space. | |
| 1050 gfx::Vector3dF element_position = | |
| 1051 vr::GetTranslation(element->TransformMatrix()); | |
| 1052 | |
| 1053 float distance = | |
| 1054 std::fabs(vr::MatrixVectorMul(view_matrix, element_position).z()); | |
| 1055 zOrderedElementPairs.push_back(std::make_pair(distance, element)); | |
| 1056 } | |
| 1057 | 1150 |
| 1058 // Sort elements primarily based on their draw phase (lower draw phase first) | 1151 // Sort elements primarily based on their draw phase (lower draw phase first) |
| 1059 // and secondarily based on their distance (larger distance first). | 1152 // and secondarily based on their distance (larger z-axis first). |
|
cjgrant
2017/05/10 20:16:26
"...based on their Z-axis distance..." maybe?
mthiesse
2017/05/10 21:09:08
Done.
mthiesse
2017/05/10 21:09:08
Didn't mean to include these changes in this CL. W
| |
| 1060 std::sort( | 1153 // TODO(mthiesse): This will not work well for elements not directly in front |
| 1061 zOrderedElementPairs.begin(), zOrderedElementPairs.end(), | 1154 // of the user, but works well enough for our initial release, and provides a |
| 1062 [](const DistanceElementPair& first, const DistanceElementPair& second) { | 1155 // consistent ordering that we can easily design around. |
| 1063 if (first.second->draw_phase() != second.second->draw_phase()) { | 1156 std::sort(sorted_elements.begin(), sorted_elements.end(), |
| 1064 return first.second->draw_phase() < second.second->draw_phase(); | 1157 [](const UiElement* first, const UiElement* second) { |
| 1065 } else { | 1158 if (first->draw_phase() != second->draw_phase()) { |
| 1066 return first.first > second.first; | 1159 return first->draw_phase() < second->draw_phase(); |
| 1067 } | 1160 } else { |
| 1068 }); | 1161 return first->translation().z() < second->translation().z(); |
| 1162 } | |
| 1163 }); | |
| 1069 | 1164 |
| 1070 std::vector<const UiElement*> zOrderedElements; | 1165 return sorted_elements; |
| 1071 zOrderedElements.reserve(elements.size()); | |
| 1072 for (auto distanceElementPair : zOrderedElementPairs) { | |
| 1073 zOrderedElements.push_back(distanceElementPair.second); | |
| 1074 } | |
| 1075 return zOrderedElements; | |
| 1076 } | 1166 } |
| 1077 | 1167 |
| 1078 void VrShellGl::DrawCursor(const vr::Mat4f& render_matrix) { | 1168 void VrShellGl::DrawCursor(const vr::Mat4f& render_matrix) { |
| 1079 vr::Mat4f mat; | 1169 vr::Mat4f mat; |
| 1080 vr::SetIdentityM(&mat); | 1170 vr::SetIdentityM(&mat); |
| 1081 | 1171 |
| 1082 // Draw the reticle. | 1172 // Draw the reticle. |
| 1083 | 1173 |
| 1084 // Scale the pointer to have a fixed FOV size at any distance. | 1174 // Scale the pointer to have a fixed FOV size at any distance. |
| 1085 const float eye_to_target = | 1175 const float eye_to_target = |
| 1086 std::sqrt(target_point_.SquaredDistanceTo(kOrigin)); | 1176 std::sqrt(target_point_.SquaredDistanceTo(kOrigin)); |
| 1087 vr::ScaleM( | 1177 vr::ScaleM( |
| 1088 mat, | 1178 mat, |
| 1089 {kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1.0f}, | 1179 {kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1.0f}, |
| 1090 &mat); | 1180 &mat); |
| 1091 | 1181 |
| 1092 vr::Quatf rotation; | 1182 vr::Quatf rotation; |
| 1093 if (target_element_ != nullptr) { | 1183 if (cursor_render_target_ != nullptr) { |
| 1094 // Make the reticle planar to the element it's hitting. | 1184 // Make the reticle planar to the element it's hitting. |
| 1095 rotation = GetRotationFromZAxis(target_element_->GetNormal()); | 1185 rotation = GetRotationFromZAxis(cursor_render_target_->GetNormal()); |
| 1096 } else { | 1186 } else { |
| 1097 // Rotate the cursor to directly face the eyes. | 1187 // Rotate the cursor to directly face the eyes. |
| 1098 rotation = GetRotationFromZAxis(target_point_ - kOrigin); | 1188 rotation = GetRotationFromZAxis(target_point_ - kOrigin); |
| 1099 } | 1189 } |
| 1100 vr::Mat4f rotation_mat; | 1190 vr::Mat4f rotation_mat; |
| 1101 vr::QuatToMatrix(rotation, &rotation_mat); | 1191 vr::QuatToMatrix(rotation, &rotation_mat); |
| 1102 vr::MatrixMul(rotation_mat, mat, &mat); | 1192 vr::MatrixMul(rotation_mat, mat, &mat); |
| 1103 | 1193 |
| 1104 gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset); | 1194 gfx::Point3F target_point = ScalePoint(target_point_, kReticleOffset); |
| 1105 // Place the pointer slightly in front of the plane intersection point. | 1195 // Place the pointer slightly in front of the plane intersection point. |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1337 // This assumes that the initial webvr_surface_size_ was set to the | 1427 // This assumes that the initial webvr_surface_size_ was set to the |
| 1338 // appropriate recommended render resolution as the default size during | 1428 // appropriate recommended render resolution as the default size during |
| 1339 // InitializeGl. Revisit if the initialization order changes. | 1429 // InitializeGl. Revisit if the initialization order changes. |
| 1340 device::mojom::VRDisplayInfoPtr info = | 1430 device::mojom::VRDisplayInfoPtr info = |
| 1341 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), | 1431 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), |
| 1342 webvr_surface_size_, device_id); | 1432 webvr_surface_size_, device_id); |
| 1343 browser_->RunVRDisplayInfoCallback(callback, &info); | 1433 browser_->RunVRDisplayInfoCallback(callback, &info); |
| 1344 } | 1434 } |
| 1345 | 1435 |
| 1346 } // namespace vr_shell | 1436 } // namespace vr_shell |
| OLD | NEW |