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"
24 #include "graphics/Camera.h"
25 #include "graphics/GameView.h"
26 #include "lib/timer.h"
27 #include "lib/external_libraries/libsdl.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
)
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
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
);
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
);
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
;
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
;
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
);
122 m_Prev
[id
] = m_Pos
[id
];
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
);
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
;
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
194 #if EMULATE_FINGERS_WITH_MOUSE
197 case SDL_MOUSEBUTTONDOWN
:
200 if (ev
->ev
.button
.button
== SDL_BUTTON_LEFT
)
202 else if (ev
->ev
.button
.button
== SDL_BUTTON_RIGHT
)
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
;
220 case SDL_MOUSEBUTTONUP
:
223 if (ev
->ev
.button
.button
== SDL_BUTTON_LEFT
)
225 else if (ev
->ev
.button
.button
== SDL_BUTTON_RIGHT
)
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();
239 m_MouseEmulateState
[button
] = MOUSE_INACTIVE
;
240 OnFingerUp(button
, ev
->ev
.button
.x
, ev
->ev
.button
.y
);
244 m_MouseEmulateState
[button
] = MOUSE_ACTIVE_UP
;
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
);
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
);
291 CTouchInput g_TouchInput
;
293 InReaction
touch_input_handler(const SDL_Event_
* ev
)
295 return g_TouchInput
.HandleEvent(ev
);