From ea1bff1f1030f4eae41200bb232357cfef8f59e4 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 18 Apr 2017 01:10:06 +0200 Subject: [PATCH] added basic gesture system on Android --- android/src/main/cpp/main.cpp | 64 +++++++++++++++++++++++++++++++++-- engine/app.cpp | 42 +++++++++++++++++++++++ engine/app.h | 6 ++++ engine/event.h | 17 ++++++++++ engine/layout.h | 15 ++++++++ 5 files changed, 141 insertions(+), 3 deletions(-) diff --git a/android/src/main/cpp/main.cpp b/android/src/main/cpp/main.cpp index ea9b25d..3b3ce1f 100755 --- a/android/src/main/cpp/main.cpp +++ b/android/src/main/cpp/main.cpp @@ -373,20 +373,78 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) // case AINPUT_SOURCE_TOUCHSCREEN: { int action = AKeyEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK; - float x = AMotionEvent_getX(event, 0); - float y = AMotionEvent_getY(event, 0); + int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) + >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + int pointer_id = AMotionEvent_getPointerId(event, index); + int32_t count = AMotionEvent_getPointerCount(event); + struct Pointer + { + int id = -1; + int idx; + glm::vec2 pos; + }; + static Pointer p0, p1; + static int tracked = 0; + float x = AMotionEvent_getX(event, index); + float y = AMotionEvent_getY(event, index); //LOG("event source: %d", AInputEvent_getSource(event)); MouseEvent e; switch (action) { case AMOTION_EVENT_ACTION_DOWN: + p0.id = AMotionEvent_getPointerId(event, 0); + p0.pos = {x, y}; App::I.mouse_down(0, x, y); + tracked = 1; + LOG("first down"); + return 1; + case AMOTION_EVENT_ACTION_POINTER_DOWN: + if (count == 2) + { + p1.id = AMotionEvent_getPointerId(event, index); + p1.idx = index; + p1.pos = {x, y}; + tracked = 2; + LOG("second down"); + App::I.mouse_cancel(0); + App::I.gesture_start(p0.pos, p1.pos); + } return 1; case AMOTION_EVENT_ACTION_UP: + tracked = 0; + p0.id = -1; + p1.id = -1; App::I.mouse_up(0, x, y); + LOG("first up"); + return 1; + case AMOTION_EVENT_ACTION_POINTER_UP: + if (p1.id == AMotionEvent_getPointerId(event, index)) + { + p1.id = -1; + LOG("second up"); + App::I.gesture_end(); + } return 1; case AMOTION_EVENT_ACTION_HOVER_MOVE: // pen move before touching case AMOTION_EVENT_ACTION_MOVE: - App::I.mouse_move(x, y); + if (tracked == 1) + { + App::I.mouse_move(x, y); + LOG("single move"); + } + else + { + if (p0.id == pointer_id) + { + LOG("first move"); + p0.pos = {x, y}; + } + if (p1.id == pointer_id) + { + LOG("second move"); + p1.pos = {x, y}; + } + App::I.gesture_move(p0.pos, p1.pos); + } return 1; default: //LOG("motion action: %d", action); diff --git a/engine/app.cpp b/engine/app.cpp index ef40384..87ccee0 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -652,6 +652,48 @@ bool App::mouse_scroll(float x, float y, float delta) layout[main_id]->update(); return ret == kEventResult::Consumed; } +bool App::mouse_cancel(int button) +{ + MouseEvent e; + e.m_type = kEventType::MouseCancel; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1) +{ + GestureEvent e; + glm::vec2 p = glm::lerp(p0, p1, 0.5f); + e.m_type = kEventType::GestureStart; + e.m_pos = p; + e.m_distance = glm::distance(p0, p1); + gesture_p0 = p0; + gesture_p1 = p1; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1) +{ + GestureEvent e; + glm::vec2 p = glm::lerp(p0, p1, 0.5f); + e.m_type = kEventType::GestureMove; + e.m_pos = p; + e.m_distance = glm::distance(p0, p1); + e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1); + e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f); + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_end() +{ + GestureEvent e; + e.m_type = kEventType::GestureEnd; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} bool App::key_down(kKey key) { KeyEvent e; diff --git a/engine/app.h b/engine/app.h index e8f2d13..34b6182 100644 --- a/engine/app.h +++ b/engine/app.h @@ -34,6 +34,8 @@ public: const uint16_t main_id = const_hash("main"); float width; float height; + glm::vec2 gesture_p0; + glm::vec2 gesture_p1; #ifdef __ANDROID__ float zoom = 3.0; #else @@ -52,6 +54,10 @@ public: bool mouse_move(float x, float y); bool mouse_up(int button, float x, float y); bool mouse_scroll(float x, float y, float delta); + bool mouse_cancel(int button); + bool gesture_start(const glm::vec2& p0, const glm::vec2& p1); + bool gesture_move(const glm::vec2& p0, const glm::vec2& p1); + bool gesture_end(); bool key_down(kKey key); bool key_up(kKey key); bool key_char(char key); diff --git a/engine/event.h b/engine/event.h index f3bfee9..62a0660 100644 --- a/engine/event.h +++ b/engine/event.h @@ -21,6 +21,7 @@ enum class kEventCategory : uint8_t MouseEvent, KeyEvent, ButtonEvent, + GestureEvent, }; enum class kEventType : uint8_t @@ -33,6 +34,10 @@ enum class kEventType : uint8_t MouseEnter, MouseLeave, MouseScroll, + MouseCancel, + GestureStart, + GestureMove, + GestureEnd, KeyDown, KeyUp, KeyChar, @@ -62,3 +67,15 @@ public: kKey m_key; char m_char; }; + +class GestureEvent : public Event +{ +public: + GestureEvent() { m_cat = kEventCategory::GestureEvent; } + float m_distance; + float m_distance_delta; + float m_angle; + float m_angle_delta; + glm::vec2 m_pos; + glm::vec2 m_pos_delta; +}; diff --git a/engine/layout.h b/engine/layout.h index d395e40..d058b45 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -1860,6 +1860,7 @@ class NodeCanvas : public Node glm::vec2 m_pan_start; glm::vec2 m_pan; float m_zoom_canvas = 1.f; + float m_zoom_start; public: std::unique_ptr m_canvas; ui::Brush m_brush; @@ -1944,6 +1945,7 @@ public: Node::handle_event(e); MouseEvent* me = static_cast(e); KeyEvent* ke = static_cast(e); + GestureEvent* ge = static_cast(e); auto loc = me->m_pos - m_pos; auto clip_space = glm::vec2(loc.x, m_size.y - loc.y - 1.f) / m_size * 2.f - 1.f; auto fb_space = glm::inverse(m_canvas->m_mvp) * glm::vec4(clip_space, 0, 1); @@ -1982,6 +1984,10 @@ public: case kEventType::MouseScroll: m_zoom_canvas += me->m_scroll_delta * 0.1f; break; + case kEventType::MouseCancel: + m_dragging = false; + mouse_release(); + break; case kEventType::KeyDown: if (ke->m_key == kKey::KeyE) m_canvas->m_erase = true; @@ -1993,6 +1999,15 @@ public: case kEventType::KeyUp: if (ke->m_key == kKey::KeyE) m_canvas->m_erase = false; + break; + case kEventType::GestureStart: + m_pan_start = m_pan; + m_zoom_start = m_zoom_canvas; + break; + case kEventType::GestureMove: + m_pan = m_pan_start + ge->m_pos_delta * glm::vec2(1, -1); + //m_zoom_canvas = m_zoom_start + ge->m_distance; + break; default: break; }