| // Copyright 2015 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 "examples/ui/spinning_cube/spinning_cube_view.h" |
| |
| #ifndef GL_GLEXT_PROTOTYPES |
| #define GL_GLEXT_PROTOTYPES |
| #endif |
| |
| #include <GLES2/gl2.h> |
| #include <GLES2/gl2extmojo.h> |
| |
| #include <cmath> |
| |
| #include "base/bind.h" |
| #include "mojo/public/cpp/system/time.h" |
| #include "mojo/services/geometry/cpp/geometry_util.h" |
| |
| namespace examples { |
| |
| namespace { |
| constexpr uint32_t kCubeImageResourceId = 1; |
| constexpr uint32_t kRootNodeId = mojo::gfx::composition::kSceneRootNodeId; |
| |
| // TODO(johngro) : investigate extending mojom with a formal flags type which it |
| // generates good bindings for, so we don't need to resort to this. |
| constexpr bool operator&(const mojo::EventFlags& f1, |
| const mojo::EventFlags& f2) { |
| return ((static_cast<uint32_t>(f1) & static_cast<uint32_t>(f2)) != 0); |
| } |
| |
| float CalculateDragDistance(const mojo::PointF& start, |
| const mojo::PointF& end) { |
| return std::hypot(start.x - end.x, start.y - end.y); |
| } |
| |
| float GetRandomColor() { |
| return static_cast<float>(rand()) / static_cast<float>(RAND_MAX); |
| } |
| |
| // Return a direction multiplier to apply to drag distances: |
| // 1 for natural (positive) motion, -1 for reverse (negative) motion |
| int GetEventDirection(const mojo::PointF& current, |
| const mojo::PointF& initial, |
| const mojo::PointF& last) { |
| // Axis of motion is determined by coarse alignment of overall movement |
| bool use_x = |
| std::abs(current.y - initial.y) < std::abs(current.x - initial.x); |
| // Current direction is determined by comparison with previous point |
| float delta = use_x ? (current.x - last.x) : (current.y - last.y); |
| return delta > 0 ? -1 : 1; |
| } |
| } // namespace |
| |
| SpinningCubeView::SpinningCubeView( |
| mojo::InterfaceHandle<mojo::ApplicationConnector> app_connector, |
| mojo::InterfaceRequest<mojo::ui::ViewOwner> view_owner_request) |
| : GLView(app_connector.Pass(), view_owner_request.Pass(), "SpinningCube"), |
| choreographer_(scene(), this), |
| input_handler_(GetViewServiceProvider(), this), |
| weak_ptr_factory_(this) { |
| mojo::GLContext::Scope gl_scope(gl_context()); |
| cube_.Init(); |
| } |
| |
| SpinningCubeView::~SpinningCubeView() {} |
| |
| void SpinningCubeView::OnPropertiesChanged( |
| uint32_t old_scene_version, |
| mojo::ui::ViewPropertiesPtr old_properties) { |
| choreographer_.ScheduleDraw(); |
| } |
| |
| void SpinningCubeView::OnEvent(mojo::EventPtr event, |
| const OnEventCallback& callback) { |
| if (!event->pointer_data) { |
| callback.Run(false); |
| return; |
| } |
| |
| switch (event->action) { |
| case mojo::EventType::POINTER_DOWN: |
| if (event->flags & mojo::EventFlags::RIGHT_MOUSE_BUTTON) |
| break; |
| capture_point_.x = event->pointer_data->x; |
| capture_point_.y = event->pointer_data->y; |
| last_drag_point_ = capture_point_; |
| drag_start_time_ = mojo::GetTimeTicksNow(); |
| cube_.SetFlingMultiplier(0.0f, 1.0f); |
| break; |
| |
| case mojo::EventType::POINTER_MOVE: { |
| if (!(event->flags & mojo::EventFlags::LEFT_MOUSE_BUTTON) && |
| event->pointer_data->kind == mojo::PointerKind::MOUSE) { |
| break; |
| } |
| mojo::PointF event_location; |
| event_location.x = event->pointer_data->x; |
| event_location.y = event->pointer_data->y; |
| int direction = |
| GetEventDirection(event_location, capture_point_, last_drag_point_); |
| cube_.UpdateForDragDistance( |
| direction * CalculateDragDistance(last_drag_point_, event_location)); |
| last_drag_point_ = event_location; |
| break; |
| } |
| |
| case mojo::EventType::POINTER_UP: { |
| if (event->flags & mojo::EventFlags::RIGHT_MOUSE_BUTTON) { |
| cube_.set_color(GetRandomColor(), GetRandomColor(), GetRandomColor()); |
| break; |
| } |
| mojo::PointF event_location; |
| event_location.x = event->pointer_data->x; |
| event_location.y = event->pointer_data->y; |
| MojoTimeTicks offset = mojo::GetTimeTicksNow() - drag_start_time_; |
| float delta = static_cast<float>(offset) / 1000000.f; |
| // Last drag point is the same as current point here; use initial capture |
| // point instead |
| int direction = |
| GetEventDirection(event_location, capture_point_, capture_point_); |
| cube_.SetFlingMultiplier( |
| direction * CalculateDragDistance(capture_point_, event_location), |
| delta); |
| capture_point_ = last_drag_point_ = mojo::PointF(); |
| break; |
| } |
| |
| default: |
| break; |
| } |
| |
| callback.Run(true); |
| } |
| |
| void SpinningCubeView::OnDraw( |
| const mojo::gfx::composition::FrameInfo& frame_info, |
| const base::TimeDelta& time_delta) { |
| if (!properties()) |
| return; |
| |
| // Update the state of the cube. |
| cube_.UpdateForTimeDelta(time_delta.InSecondsF()); |
| |
| // Update the contents of the scene. |
| auto update = mojo::gfx::composition::SceneUpdate::New(); |
| |
| const mojo::Size& size = *properties()->view_layout->size; |
| if (size.width > 0 && size.height > 0) { |
| mojo::RectF bounds; |
| bounds.width = size.width; |
| bounds.height = size.height; |
| |
| mojo::gfx::composition::ResourcePtr cube_resource = gl_renderer()->DrawGL( |
| size, true, |
| base::Bind(&SpinningCubeView::DrawCubeWithGL, base::Unretained(this))); |
| DCHECK(cube_resource); |
| update->resources.insert(kCubeImageResourceId, cube_resource.Pass()); |
| |
| auto root_node = mojo::gfx::composition::Node::New(); |
| root_node->content_transform = mojo::Transform::New(); |
| mojo::SetIdentityTransform(root_node->content_transform.get()); |
| root_node->hit_test_behavior = |
| mojo::gfx::composition::HitTestBehavior::New(); |
| root_node->op = mojo::gfx::composition::NodeOp::New(); |
| root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New()); |
| root_node->op->get_image()->content_rect = bounds.Clone(); |
| root_node->op->get_image()->image_resource_id = kCubeImageResourceId; |
| update->nodes.insert(kRootNodeId, root_node.Pass()); |
| } else { |
| auto root_node = mojo::gfx::composition::Node::New(); |
| update->nodes.insert(kRootNodeId, root_node.Pass()); |
| } |
| |
| scene()->Update(update.Pass()); |
| |
| // Publish the scene. |
| auto metadata = mojo::gfx::composition::SceneMetadata::New(); |
| metadata->version = scene_version(); |
| metadata->presentation_time = frame_info.presentation_time; |
| scene()->Publish(metadata.Pass()); |
| |
| // Loop! |
| choreographer_.ScheduleDraw(); |
| } |
| |
| void SpinningCubeView::DrawCubeWithGL(const mojo::GLContext::Scope& gl_scope, |
| const mojo::Size& size) { |
| cube_.set_size(size.width, size.height); |
| cube_.Draw(); |
| } |
| |
| } // namespace examples |