LCOV - code coverage report
Current view: top level - source/ps - TouchInput.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 15 94 16.0 %
Date: 2022-06-14 00:41:00 Functions: 3 9 33.3 %

          Line data    Source code
       1             : /* Copyright (C) 2019 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "TouchInput.h"
      21             : 
      22             : #include <cinttypes>
      23             : 
      24             : #include "graphics/Camera.h"
      25             : #include "graphics/GameView.h"
      26             : #include "lib/timer.h"
      27             : #include "lib/external_libraries/libsdl.h"
      28             : #include "ps/Game.h"
      29             : 
      30             : // When emulation is enabled:
      31             : // Left-click to put finger 0 down.
      32             : // Then left-click-and-drag to move finger 0.
      33             : // Then left-click to put finger 0 up.
      34             : // Same with right-click for finger 1.
      35             : #define EMULATE_FINGERS_WITH_MOUSE 0
      36             : 
      37             : extern int g_xres, g_yres;
      38             : 
      39             : // NOTE: All this code is currently just a basic prototype for testing;
      40             : // it might need significant redesigning for proper usage.
      41             : 
      42           1 : CTouchInput::CTouchInput() :
      43           7 :     m_State(STATE_INACTIVE)
      44             : {
      45           3 :     for (size_t i = 0; i < MAX_FINGERS; ++i)
      46           2 :         m_Down[i] = false;
      47             : 
      48           3 :     for (size_t i = 0; i < MAX_MOUSE; ++i)
      49           2 :         m_MouseEmulateState[i] = MOUSE_INACTIVE;
      50           1 : }
      51             : 
      52           1 : CTouchInput::~CTouchInput()
      53             : {
      54           1 : }
      55             : 
      56           0 : bool CTouchInput::IsEnabled()
      57             : {
      58             : #if OS_ANDROID || EMULATE_FINGERS_WITH_MOUSE
      59             :     return true;
      60             : #else
      61           7 :     return false;
      62             : #endif
      63             : }
      64             : 
      65           0 : void CTouchInput::OnFingerDown(int id, int x, int y)
      66             : {
      67           0 :     debug_printf("finger down %d %d %d; state %d\n", id, x, y, m_State);
      68           0 :     m_Down[id] = true;
      69           0 :     m_Prev[id] = m_Pos[id] = CVector2D(x, y);
      70             : 
      71           0 :     if (m_State == STATE_INACTIVE && id == 0)
      72             :     {
      73           0 :         m_State = STATE_FIRST_TOUCH;
      74           0 :         m_FirstTouchTime = timer_Time();
      75           0 :         m_FirstTouchPos = CVector2D(x, y);
      76             :     }
      77           0 :     else if ((m_State == STATE_FIRST_TOUCH || m_State == STATE_PANNING) && id == 1)
      78             :     {
      79           0 :         m_State = STATE_ZOOMING;
      80             :     }
      81           0 : }
      82             : 
      83           0 : void CTouchInput::OnFingerUp(int id, int x, int y)
      84             : {
      85           0 :     debug_printf("finger up %d %d %d; state %d\n", id, x, y, m_State);
      86           0 :     m_Down[id] = false;
      87           0 :     m_Pos[id] = CVector2D(x, y);
      88             : 
      89           0 :     if (m_State == STATE_FIRST_TOUCH && id == 0 && timer_Time() < m_FirstTouchTime + 0.5)
      90             :     {
      91           0 :         m_State = STATE_INACTIVE;
      92             : 
      93           0 :         SDL_Event_ ev;
      94           0 :         ev.ev.button.button = SDL_BUTTON_LEFT;
      95           0 :         ev.ev.button.x = m_Pos[0].X;
      96           0 :         ev.ev.button.y = m_Pos[0].Y;
      97             : 
      98           0 :         ev.ev.type = SDL_MOUSEBUTTONDOWN;
      99           0 :         ev.ev.button.state = SDL_PRESSED;
     100           0 :         SDL_PushEvent(&ev.ev);
     101             : 
     102           0 :         ev.ev.type = SDL_MOUSEBUTTONUP;
     103           0 :         ev.ev.button.state = SDL_RELEASED;
     104           0 :         SDL_PushEvent(&ev.ev);
     105             :     }
     106           0 :     else if (m_State == STATE_ZOOMING && id == 1)
     107             :     {
     108           0 :         m_State = STATE_PANNING;
     109             :     }
     110             :     else
     111             :     {
     112           0 :         m_State = STATE_INACTIVE;
     113             :     }
     114           0 : }
     115             : 
     116           0 : void CTouchInput::OnFingerMotion(int id, int x, int y)
     117             : {
     118           0 :     debug_printf("finger motion %d %d %d; state %d\n", id, x, y, m_State);
     119             : 
     120           0 :     CVector2D pos(x, y);
     121             : 
     122           0 :     m_Prev[id] = m_Pos[id];
     123           0 :     m_Pos[id] = pos;
     124             : 
     125           0 :     if (m_State == STATE_FIRST_TOUCH && id == 0)
     126             :     {
     127           0 :         if ((pos - m_FirstTouchPos).Length() > 16)
     128             :         {
     129           0 :             m_State = STATE_PANNING;
     130             : 
     131           0 :             const CCamera& camera = *(g_Game->GetView()->GetCamera());
     132           0 :             m_PanFocus = camera.GetWorldCoordinates(m_FirstTouchPos.X, m_FirstTouchPos.Y, true);
     133           0 :             m_PanDist = (m_PanFocus - camera.GetOrientation().GetTranslation()).Y;
     134             :         }
     135             :     }
     136             : 
     137           0 :     if (m_State == STATE_PANNING && id == 0)
     138             :     {
     139           0 :         CCamera& camera = *(g_Game->GetView()->GetCamera());
     140           0 :         CVector3D origin, dir;
     141           0 :         camera.BuildCameraRay(x, y, origin, dir);
     142           0 :         dir *= m_PanDist / dir.Y;
     143           0 :         camera.GetOrientation().Translate(m_PanFocus - dir - origin);
     144           0 :         camera.UpdateFrustum();
     145             :     }
     146             : 
     147           0 :     if (m_State == STATE_ZOOMING && id == 1)
     148             :     {
     149           0 :         float oldDist = (m_Prev[id] - m_Pos[1 - id]).Length();
     150           0 :         float newDist = (m_Pos[id] - m_Pos[1 - id]).Length();
     151           0 :         float zoomDist = (newDist - oldDist) * -0.005f * m_PanDist;
     152             : 
     153           0 :         CCamera& camera = *(g_Game->GetView()->GetCamera());
     154           0 :         CVector3D origin, dir;
     155           0 :         camera.BuildCameraRay(m_Pos[0].X, m_Pos[0].Y, origin, dir);
     156           0 :         dir *= zoomDist;
     157           0 :         camera.GetOrientation().Translate(dir);
     158           0 :         camera.UpdateFrustum();
     159             : 
     160           0 :         m_PanFocus = camera.GetWorldCoordinates(m_Pos[0].X, m_Pos[0].Y, true);
     161           0 :         m_PanDist = (m_PanFocus - camera.GetOrientation().GetTranslation()).Y;
     162             :     }
     163           0 : }
     164             : 
     165           0 : void CTouchInput::Frame()
     166             : {
     167           0 :     double t = timer_Time();
     168           0 :     if (m_State == STATE_FIRST_TOUCH && t > m_FirstTouchTime + 1.0)
     169             :     {
     170           0 :         m_State = STATE_INACTIVE;
     171             : 
     172           0 :         SDL_Event_ ev;
     173           0 :         ev.ev.button.button = SDL_BUTTON_RIGHT;
     174           0 :         ev.ev.button.x = m_Pos[0].X;
     175           0 :         ev.ev.button.y = m_Pos[0].Y;
     176             : 
     177           0 :         ev.ev.type = SDL_MOUSEBUTTONDOWN;
     178           0 :         ev.ev.button.state = SDL_PRESSED;
     179           0 :         SDL_PushEvent(&ev.ev);
     180             : 
     181           0 :         ev.ev.type = SDL_MOUSEBUTTONUP;
     182           0 :         ev.ev.button.state = SDL_RELEASED;
     183           0 :         SDL_PushEvent(&ev.ev);
     184             :     }
     185           0 : }
     186             : 
     187           0 : InReaction CTouchInput::HandleEvent(const SDL_Event_* ev)
     188             : {
     189           7 :     UNUSED2(ev); // may be unused depending on #ifs
     190             : 
     191          14 :     if (!IsEnabled())
     192           7 :         return IN_PASS;
     193             : 
     194             : #if EMULATE_FINGERS_WITH_MOUSE
     195             :     switch(ev->ev.type)
     196             :     {
     197             :     case SDL_MOUSEBUTTONDOWN:
     198             :     {
     199             :         int button;
     200             :         if (ev->ev.button.button == SDL_BUTTON_LEFT)
     201             :             button = 0;
     202             :         else if (ev->ev.button.button == SDL_BUTTON_RIGHT)
     203             :             button = 1;
     204             :         else
     205             :             return IN_PASS;
     206             : 
     207             :         m_MouseEmulateDownPos[button] = CVector2D(ev->ev.button.x, ev->ev.button.y);
     208             :         if (m_MouseEmulateState[button] == MOUSE_INACTIVE)
     209             :         {
     210             :             m_MouseEmulateState[button] = MOUSE_ACTIVATING;
     211             :             OnFingerDown(button, ev->ev.button.x, ev->ev.button.y);
     212             :         }
     213             :         else if (m_MouseEmulateState[button] == MOUSE_ACTIVE_UP)
     214             :         {
     215             :             m_MouseEmulateState[button] = MOUSE_ACTIVE_DOWN;
     216             :         }
     217             :         return IN_HANDLED;
     218             :     }
     219             : 
     220             :     case SDL_MOUSEBUTTONUP:
     221             :     {
     222             :         int button;
     223             :         if (ev->ev.button.button == SDL_BUTTON_LEFT)
     224             :             button = 0;
     225             :         else if (ev->ev.button.button == SDL_BUTTON_RIGHT)
     226             :             button = 1;
     227             :         else
     228             :             return IN_PASS;
     229             : 
     230             :         if (m_MouseEmulateState[button] == MOUSE_ACTIVATING)
     231             :         {
     232             :             m_MouseEmulateState[button] = MOUSE_ACTIVE_UP;
     233             :         }
     234             :         else if (m_MouseEmulateState[button] == MOUSE_ACTIVE_DOWN)
     235             :         {
     236             :             float dist = (m_MouseEmulateDownPos[button] - CVector2D(ev->ev.button.x, ev->ev.button.y)).Length();
     237             :             if (dist <= 2)
     238             :             {
     239             :                 m_MouseEmulateState[button] = MOUSE_INACTIVE;
     240             :                 OnFingerUp(button, ev->ev.button.x, ev->ev.button.y);
     241             :             }
     242             :             else
     243             :             {
     244             :                 m_MouseEmulateState[button] = MOUSE_ACTIVE_UP;
     245             :             }
     246             :         }
     247             :         return IN_HANDLED;
     248             :     }
     249             : 
     250             :     case SDL_MOUSEMOTION:
     251             :     {
     252             :         for (size_t i = 0; i < MAX_MOUSE; ++i)
     253             :         {
     254             :             if (m_MouseEmulateState[i] == MOUSE_ACTIVE_DOWN)
     255             :             {
     256             :                 OnFingerMotion(i, ev->ev.motion.x, ev->ev.motion.y);
     257             :             }
     258             :         }
     259             :         return IN_HANDLED;
     260             :     }
     261             :     }
     262             : #endif
     263             : 
     264             :     switch(ev->ev.type)
     265             :     {
     266             :     case SDL_FINGERDOWN:
     267             :     case SDL_FINGERUP:
     268             :     case SDL_FINGERMOTION:
     269             :     {
     270             :         // Map finger events onto the mouse, for basic testing
     271             :         debug_printf("finger %s tid=%" PRId64 " fid=%" PRId64 " x=%f y=%f dx=%f dy=%f p=%f\n",
     272             :             ev->ev.type == SDL_FINGERDOWN ? "down" :
     273             :             ev->ev.type == SDL_FINGERUP ? "up" :
     274             :             ev->ev.type == SDL_FINGERMOTION ? "motion" : "?",
     275             :             ev->ev.tfinger.touchId, ev->ev.tfinger.fingerId,
     276             :             ev->ev.tfinger.x, ev->ev.tfinger.y, ev->ev.tfinger.dx, ev->ev.tfinger.dy, ev->ev.tfinger.pressure);
     277             : 
     278             :         if (ev->ev.type == SDL_FINGERDOWN)
     279             :             OnFingerDown(ev->ev.tfinger.fingerId, g_xres * ev->ev.tfinger.x, g_yres * ev->ev.tfinger.y);
     280             :         else if (ev->ev.type == SDL_FINGERUP)
     281             :             OnFingerUp(ev->ev.tfinger.fingerId, g_xres * ev->ev.tfinger.x, g_yres * ev->ev.tfinger.y);
     282             :         else if (ev->ev.type == SDL_FINGERMOTION)
     283             :             OnFingerMotion(ev->ev.tfinger.fingerId, g_xres * ev->ev.tfinger.x, g_yres * ev->ev.tfinger.y);
     284             :         return IN_HANDLED;
     285             :     }
     286             :     }
     287             : 
     288             :     return IN_PASS;
     289             : }
     290             : 
     291             : CTouchInput g_TouchInput;
     292             : 
     293           7 : InReaction touch_input_handler(const SDL_Event_* ev)
     294             : {
     295          14 :     return g_TouchInput.HandleEvent(ev);
     296             : }

Generated by: LCOV version 1.13