| // Copyright 2013 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. |
| |
| #ifndef GL_GLEXT_PROTOTYPES |
| #define GL_GLEXT_PROTOTYPES |
| #endif |
| |
| #include "examples/spinning_cube/gles2_client_impl.h" |
| |
| #include <math.h> |
| #include <stdlib.h> |
| #include <cmath> |
| #include <utility> |
| |
| #include "mojo/public/c/gpu/MGL/mgl.h" |
| #include "mojo/public/c/gpu/MGL/mgl_onscreen.h" |
| #include "mojo/public/cpp/environment/environment.h" |
| #include "mojo/public/cpp/system/time.h" |
| #include "mojo/public/cpp/utility/run_loop.h" |
| |
| namespace examples { |
| namespace { |
| |
| // 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. |
| static inline 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 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 |
| |
| GLES2ClientImpl::GLES2ClientImpl(mojo::ContextProviderPtr context_provider) |
| : last_time_(mojo::GetTimeTicksNow()), |
| waiting_to_draw_(false), |
| context_provider_(context_provider.Pass()), |
| context_(nullptr) { |
| context_provider_->Create( |
| nullptr, |
| [this](mojo::InterfaceHandle<mojo::CommandBuffer> command_buffer) { |
| ContextCreated(std::move(command_buffer)); |
| }); |
| } |
| |
| GLES2ClientImpl::~GLES2ClientImpl() { |
| MGLDestroyContext(context_); |
| } |
| |
| void GLES2ClientImpl::SetSize(const mojo::Size& size) { |
| size_ = size; |
| cube_.set_size(size_.width, size_.height); |
| if (size_.width == 0 || size_.height == 0 || !context_) |
| return; |
| MGLResizeSurface(size_.width, size_.height); |
| WantToDraw(); |
| } |
| |
| void GLES2ClientImpl::HandleInputEvent(const mojo::Event& event) { |
| 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)); |
| WantToDraw(); |
| |
| 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(); |
| WantToDraw(); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| |
| void GLES2ClientImpl::ContextCreated( |
| mojo::InterfaceHandle<mojo::CommandBuffer> command_buffer) { |
| context_ = MGLCreateContext(MGL_API_VERSION_GLES2, |
| command_buffer.PassHandle().release().value(), |
| MGL_NO_CONTEXT, &ContextLostThunk, this, |
| mojo::Environment::GetDefaultAsyncWaiter()); |
| MGLMakeCurrent(context_); |
| cube_.Init(); |
| WantToDraw(); |
| } |
| |
| void GLES2ClientImpl::ContextLost() { |
| cube_.OnGLContextLost(); |
| MGLDestroyContext(context_); |
| context_ = nullptr; |
| context_provider_->Create( |
| nullptr, |
| [this](mojo::InterfaceHandle<mojo::CommandBuffer> command_buffer) { |
| ContextCreated(std::move(command_buffer)); |
| }); |
| } |
| |
| void GLES2ClientImpl::ContextLostThunk(void* closure) { |
| static_cast<GLES2ClientImpl*>(closure)->ContextLost(); |
| } |
| |
| void GLES2ClientImpl::WantToDraw() { |
| if (waiting_to_draw_ || !context_) |
| return; |
| waiting_to_draw_ = true; |
| mojo::RunLoop::current()->PostDelayedTask([this]() { Draw(); }, |
| MojoTimeTicks(16667)); |
| } |
| |
| void GLES2ClientImpl::Draw() { |
| waiting_to_draw_ = false; |
| if (!context_) |
| return; |
| MojoTimeTicks now = mojo::GetTimeTicksNow(); |
| MojoTimeTicks offset = now - last_time_; |
| float delta = static_cast<float>(offset) / 1000000.; |
| last_time_ = now; |
| cube_.UpdateForTimeDelta(delta); |
| cube_.Draw(); |
| |
| MGLSwapBuffers(); |
| WantToDraw(); |
| } |
| |
| } // namespace examples |