Fix infinite loop detection when placing players randomly on the newer random map...
[0ad.git] / source / ps / TouchInput.cpp
blob33b05bbf49c2345095692b12e1f5efd49f0e5c29
1 /* Copyright (C) 2015 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
20 #include "TouchInput.h"
22 #include <cinttypes>
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"
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
37 extern int g_xres, g_yres;
39 // NOTE: All this code is currently just a basic prototype for testing;
40 // it might need significant redesigning for proper usage.
42 CTouchInput::CTouchInput() :
43 m_State(STATE_INACTIVE)
45 for (size_t i = 0; i < MAX_FINGERS; ++i)
46 m_Down[i] = false;
48 for (size_t i = 0; i < MAX_MOUSE; ++i)
49 m_MouseEmulateState[i] = MOUSE_INACTIVE;
52 CTouchInput::~CTouchInput()
56 bool CTouchInput::IsEnabled()
58 #if OS_ANDROID || EMULATE_FINGERS_WITH_MOUSE
59 return true;
60 #else
61 return false;
62 #endif
65 void CTouchInput::OnFingerDown(int id, int x, int y)
67 debug_printf("finger down %d %d %d; state %d\n", id, x, y, m_State);
68 m_Down[id] = true;
69 m_Prev[id] = m_Pos[id] = CVector2D(x, y);
71 if (m_State == STATE_INACTIVE && id == 0)
73 m_State = STATE_FIRST_TOUCH;
74 m_FirstTouchTime = timer_Time();
75 m_FirstTouchPos = CVector2D(x, y);
77 else if ((m_State == STATE_FIRST_TOUCH || m_State == STATE_PANNING) && id == 1)
79 m_State = STATE_ZOOMING;
83 void CTouchInput::OnFingerUp(int id, int x, int y)
85 debug_printf("finger up %d %d %d; state %d\n", id, x, y, m_State);
86 m_Down[id] = false;
87 m_Pos[id] = CVector2D(x, y);
89 if (m_State == STATE_FIRST_TOUCH && id == 0 && timer_Time() < m_FirstTouchTime + 0.5)
91 m_State = STATE_INACTIVE;
93 SDL_Event_ ev;
94 ev.ev.button.button = SDL_BUTTON_LEFT;
95 ev.ev.button.x = m_Pos[0].X;
96 ev.ev.button.y = m_Pos[0].Y;
98 ev.ev.type = SDL_MOUSEBUTTONDOWN;
99 ev.ev.button.state = SDL_PRESSED;
100 SDL_PushEvent(&ev.ev);
102 ev.ev.type = SDL_MOUSEBUTTONUP;
103 ev.ev.button.state = SDL_RELEASED;
104 SDL_PushEvent(&ev.ev);
106 else if (m_State == STATE_ZOOMING && id == 1)
108 m_State = STATE_PANNING;
110 else
112 m_State = STATE_INACTIVE;
116 void CTouchInput::OnFingerMotion(int id, int x, int y)
118 debug_printf("finger motion %d %d %d; state %d\n", id, x, y, m_State);
120 CVector2D pos(x, y);
122 m_Prev[id] = m_Pos[id];
123 m_Pos[id] = pos;
125 if (m_State == STATE_FIRST_TOUCH && id == 0)
127 if ((pos - m_FirstTouchPos).Length() > 16)
129 m_State = STATE_PANNING;
131 CCamera& camera = *(g_Game->GetView()->GetCamera());
132 m_PanFocus = camera.GetWorldCoordinates(m_FirstTouchPos.X, m_FirstTouchPos.Y, true);
133 m_PanDist = (m_PanFocus - camera.GetOrientation().GetTranslation()).Y;
137 if (m_State == STATE_PANNING && id == 0)
139 CCamera& camera = *(g_Game->GetView()->GetCamera());
140 CVector3D origin, dir;
141 camera.BuildCameraRay(x, y, origin, dir);
142 dir *= m_PanDist / dir.Y;
143 camera.GetOrientation().Translate(m_PanFocus - dir - origin);
144 camera.UpdateFrustum();
147 if (m_State == STATE_ZOOMING && id == 1)
149 float oldDist = (m_Prev[id] - m_Pos[1 - id]).Length();
150 float newDist = (m_Pos[id] - m_Pos[1 - id]).Length();
151 float zoomDist = (newDist - oldDist) * -0.005f * m_PanDist;
153 CCamera& camera = *(g_Game->GetView()->GetCamera());
154 CVector3D origin, dir;
155 camera.BuildCameraRay(m_Pos[0].X, m_Pos[0].Y, origin, dir);
156 dir *= zoomDist;
157 camera.GetOrientation().Translate(dir);
158 camera.UpdateFrustum();
160 m_PanFocus = camera.GetWorldCoordinates(m_Pos[0].X, m_Pos[0].Y, true);
161 m_PanDist = (m_PanFocus - camera.GetOrientation().GetTranslation()).Y;
165 void CTouchInput::Frame()
167 double t = timer_Time();
168 if (m_State == STATE_FIRST_TOUCH && t > m_FirstTouchTime + 1.0)
170 m_State = STATE_INACTIVE;
172 SDL_Event_ ev;
173 ev.ev.button.button = SDL_BUTTON_RIGHT;
174 ev.ev.button.x = m_Pos[0].X;
175 ev.ev.button.y = m_Pos[0].Y;
177 ev.ev.type = SDL_MOUSEBUTTONDOWN;
178 ev.ev.button.state = SDL_PRESSED;
179 SDL_PushEvent(&ev.ev);
181 ev.ev.type = SDL_MOUSEBUTTONUP;
182 ev.ev.button.state = SDL_RELEASED;
183 SDL_PushEvent(&ev.ev);
187 InReaction CTouchInput::HandleEvent(const SDL_Event_* ev)
189 UNUSED2(ev); // may be unused depending on #ifs
191 if (!IsEnabled())
192 return IN_PASS;
194 #if EMULATE_FINGERS_WITH_MOUSE
195 switch(ev->ev.type)
197 case SDL_MOUSEBUTTONDOWN:
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;
207 m_MouseEmulateDownPos[button] = CVector2D(ev->ev.button.x, ev->ev.button.y);
208 if (m_MouseEmulateState[button] == MOUSE_INACTIVE)
210 m_MouseEmulateState[button] = MOUSE_ACTIVATING;
211 OnFingerDown(button, ev->ev.button.x, ev->ev.button.y);
213 else if (m_MouseEmulateState[button] == MOUSE_ACTIVE_UP)
215 m_MouseEmulateState[button] = MOUSE_ACTIVE_DOWN;
217 return IN_HANDLED;
220 case SDL_MOUSEBUTTONUP:
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;
230 if (m_MouseEmulateState[button] == MOUSE_ACTIVATING)
232 m_MouseEmulateState[button] = MOUSE_ACTIVE_UP;
234 else if (m_MouseEmulateState[button] == MOUSE_ACTIVE_DOWN)
236 float dist = (m_MouseEmulateDownPos[button] - CVector2D(ev->ev.button.x, ev->ev.button.y)).Length();
237 if (dist <= 2)
239 m_MouseEmulateState[button] = MOUSE_INACTIVE;
240 OnFingerUp(button, ev->ev.button.x, ev->ev.button.y);
242 else
244 m_MouseEmulateState[button] = MOUSE_ACTIVE_UP;
247 return IN_HANDLED;
250 case SDL_MOUSEMOTION:
252 for (size_t i = 0; i < MAX_MOUSE; ++i)
254 if (m_MouseEmulateState[i] == MOUSE_ACTIVE_DOWN)
256 OnFingerMotion(i, ev->ev.motion.x, ev->ev.motion.y);
259 return IN_HANDLED;
262 #endif
264 switch(ev->ev.type)
266 case SDL_FINGERDOWN:
267 case SDL_FINGERUP:
268 case SDL_FINGERMOTION:
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);
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;
288 return IN_PASS;
291 CTouchInput g_TouchInput;
293 InReaction touch_input_handler(const SDL_Event_* ev)
295 return g_TouchInput.HandleEvent(ev);