1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
25 //**************************************************************************
26 #if defined(ANDROID) || 0
27 #ifdef VAVOOM_CUSTOM_SPECIAL_SDL
30 # include <SDL2/SDL.h>
39 #define ID_UNDEF (-666)
41 #define X_ROT_SENSITIVITY (1.0f)
42 #define Y_ROT_SENSITIVITY (1.0f)
43 #define X_ROT_THRESHOLD (0.01f)
44 #define Y_ROT_THRESHOLD (0.01f)
46 #define X_STEP_THRESHOLD (0.05f)
47 #define Y_STEP_THRESHOLD (0.05f)
49 #define STEP_FINGER (0)
50 #define ROT_FINGER (1)
51 #define MAX_FINGERS (2)
54 static VCvarB
touch_enable("touch_enable", true, "Show and handle touch screen controls (when available).", CVAR_Archive
|CVAR_NoShadow
);
57 static struct vfinger
{
58 int id
; // system finger id
60 float dx
, dy
; // [-1..+1]
61 float start_x
, start_y
; // [0..1]
62 float vx
, vy
; // [-1..+1]
63 } fingers
[MAX_FINGERS
] = {
64 { ID_UNDEF
, 0.0f
, 0.0f
},
65 { ID_UNDEF
, 0.0f
, 0.0f
},
68 #define MAX_BUTTONS (9)
70 static struct vbutton
{
76 } buttons
[MAX_BUTTONS
] = {
77 { 0.85f
, 0.5f
, 0.08f
, "+Attack", "-Attack", K_ENTER
, ID_UNDEF
},
78 { 1.0f
, 1.0f
, 0.1f
, "+Use", "-Use", 0, ID_UNDEF
},
79 { 0.8f
, 1.0f
, 0.1f
, "+Crouch", "-Crouch", 0, ID_UNDEF
},
80 { 0.6f
, 1.0f
, 0.1f
, "+Jump", "-Jump", 0, ID_UNDEF
},
81 { 0.6f
, 0.0f
, 0.1f
, "impulse 17", "", 0, ID_UNDEF
}, // prev weapon
82 { 0.8f
, 0.0f
, 0.1f
, "impulse 18", "", 0, ID_UNDEF
}, // next weapon
83 { 1.0f
, 0.0f
, 0.1f
, "ToggleAlwaysRun", "", 0, ID_UNDEF
},
84 { 0.0f
, 1.0f
, 0.1f
, "SetMenu Main", "", K_ESCAPE
, ID_UNDEF
},
85 { 0.0f
, 0.0f
, 0.1f
, "ToggleConsole", "", 0, ID_UNDEF
},
89 //==========================================================================
93 // k8: this can be made faster, but who cares?
95 //==========================================================================
96 static inline float fsgn (const float x
) noexcept
{
97 return (x
< 0.0f
? -1.0f
: x
> 0.0f
? +1.0f
: 0.0f
);
101 //==========================================================================
105 //==========================================================================
106 static inline bool point_in_circle (const float x
, const float y
, const float cx
, const float cy
, const float cr
) noexcept
{
107 //return (powf(x-cx, 2)+powf(y-cy, 2) < powf(cr, 2));
108 // no, don't use `powf()`, you silly horse! it's freakin' slow.
109 const float dx
= x
-cx
;
110 const float dy
= y
-cy
;
111 return (dx
*dx
+dy
*dy
< cr
*cr
);
115 //==========================================================================
119 // TODO: make colors and opacities configurable via cvars
121 //==========================================================================
122 static void draw_pad (int f
, float x_threshold
, float y_threshold
) {
123 if (fingers
[f
].id
!= ID_UNDEF
) {
124 const int scr_w
= Drawer
->getWidth();
125 const int scr_h
= Drawer
->getHeight();
126 const float sx
= fingers
[f
].start_x
*scr_w
;
127 const float sy
= fingers
[f
].start_y
*scr_h
;
128 float tx
= x_threshold
*scr_w
;
129 float ty
= y_threshold
*scr_h
;
130 Drawer
->DrawRect(sx
-tx
, sy
-ty
, sx
+tx
, sy
+ty
, 0xff8f0f00, 1.0f
);
133 const float x
= fingers
[f
].x
*scr_w
;
134 const float y
= fingers
[f
].y
*scr_h
;
135 Drawer
->FillRect(sx
-tx
, sy
-ty
, sx
+tx
, sy
+ty
, 0xffff0f00, 0.5f
);
136 Drawer
->FillRect(x
-tx
, y
-ty
, x
+tx
, y
+ty
, 0xffff0f3f, 0.5f
);
141 //==========================================================================
145 // TODO: make colors and opacities configurable via cvars
147 //==========================================================================
149 if (!touch_enable
|| SDL_GetNumTouchDevices() <= 0 || SDL_IsTextInputActive()) {
153 const int scr_w
= Drawer
->getWidth();
154 const int scr_h
= Drawer
->getHeight();
155 for (int i
= 0; i
< MAX_BUTTONS
; ++i
) {
156 const int x
= buttons
[i
].x
*scr_w
;
157 const int y
= buttons
[i
].y
*scr_h
;
158 const int tx
= buttons
[i
].r
*scr_w
;
159 const int ty
= buttons
[i
].r
*scr_h
;
160 Drawer
->DrawRect(x
-tx
, y
-ty
, x
+tx
, y
+ty
, 0xff00ff00, 0.8f
);
163 draw_pad(STEP_FINGER
, X_STEP_THRESHOLD
, Y_STEP_THRESHOLD
);
164 draw_pad(ROT_FINGER
, X_ROT_THRESHOLD
, Y_ROT_THRESHOLD
);
168 //==========================================================================
172 //==========================================================================
173 static void press_pad (int key
, bool down
) {
175 GInput
->PostKeyEvent(key
, down
? 1 : 0, 0);
177 const char *c
= (down
? "+" : "-");
178 //if (pad == STEP_FINGER) {
180 case K_UPARROW
: GCmdBuf
<< c
<< "Forward\n"; break;
181 case K_DOWNARROW
: GCmdBuf
<< c
<< "Backward\n"; break;
182 case K_LEFTARROW
: GCmdBuf
<< c
<< "MoveLeft\n"; break;
183 case K_RIGHTARROW
: GCmdBuf
<< c
<< "MoveRight\n"; break;
185 //} else if (pad == ROT_FINGER) {
187 // case K_UPARROW: GCmdBuf << c << "LookUp\n"; break;
188 // case K_DOWNARROW: GCmdBuf << c << "LookDown\n"; break;
189 // case K_LEFTARROW: GCmdBuf << c << "LookLeft\n"; break;
190 // case K_RIGHTARROW: GCmdBuf << c << "LookRight\n"; break;
197 //==========================================================================
201 //==========================================================================
202 static void PostMouseEvent (const float dx
, const float dy
) {
208 ev
.dx
= X_ROT_SENSITIVITY
*Drawer
->getWidth()*dx
;
209 ev
.dy
= Y_ROT_SENSITIVITY
*Drawer
->getHeight()*(-dy
);
210 VObject::PostEvent(ev
);
215 //==========================================================================
219 //==========================================================================
220 void Touch_Update () {
221 if (!touch_enable
|| SDL_GetNumTouchDevices() <= 0 || SDL_IsTextInputActive()) {
225 if (fingers
[ROT_FINGER
].id
!= ID_UNDEF
) {
226 float dx
= fingers
[ROT_FINGER
].x
-fingers
[ROT_FINGER
].start_x
;
227 float dy
= fingers
[ROT_FINGER
].y
-fingers
[ROT_FINGER
].start_y
;
228 dx
= (fabsf(dx
) >= X_ROT_THRESHOLD
? dx
-fsgn(dx
)*X_ROT_THRESHOLD
: 0.0f
);
229 dy
= (fabsf(dy
) >= X_ROT_THRESHOLD
? dy
-fsgn(dy
)*X_ROT_THRESHOLD
: 0.0f
);
230 if (dx
!= 0.0f
|| dy
!= 0.0f
) {
231 PostMouseEvent(dx
, dy
);
235 if (fingers
[STEP_FINGER
].id
!= ID_UNDEF
) {
236 float vx
= fingers
[STEP_FINGER
].x
-fingers
[STEP_FINGER
].start_x
;
237 float vy
= fingers
[STEP_FINGER
].y
-fingers
[STEP_FINGER
].start_y
;
238 vx
= (fabsf(vx
) >= X_STEP_THRESHOLD
? vx
-fsgn(vx
)*X_STEP_THRESHOLD
: 0.0f
);
239 vy
= (fabsf(vy
) >= X_STEP_THRESHOLD
? vy
-fsgn(vy
)*X_STEP_THRESHOLD
: 0.0f
);
242 if (vx
!= fingers
[STEP_FINGER
].vx
) {
243 if (fingers
[STEP_FINGER
].vx
< 0.0f
) press_pad(K_LEFTARROW
, false);
244 else if (fingers
[STEP_FINGER
].vx
> 0.0f
) press_pad(K_RIGHTARROW
, false);
245 if (vx
< 0.0f
) press_pad(K_LEFTARROW
, true);
246 else if (vx
> 0.0f
) press_pad(K_RIGHTARROW
, true);
248 if (vy
!= fingers
[STEP_FINGER
].vy
) {
249 if (fingers
[STEP_FINGER
].vy
< 0.0f
) press_pad(K_UPARROW
, false);
250 else if (fingers
[STEP_FINGER
].vy
> 0.0f
) press_pad(K_DOWNARROW
, false);
251 if (vy
< 0.0f
) press_pad(K_UPARROW
, true);
252 else if (vy
> 0.0f
) press_pad(K_DOWNARROW
, true);
254 fingers
[STEP_FINGER
].vx
= vx
;
255 fingers
[STEP_FINGER
].vy
= vy
;
260 //==========================================================================
264 //==========================================================================
265 static int find_finger (int id
) noexcept
{
266 for (unsigned i
= 0; i
< MAX_FINGERS
; ++i
) if (fingers
[i
].id
== id
) return (int)i
;
271 //==========================================================================
275 //==========================================================================
276 static void press_button (int finger
, float x
, float y
, bool down
) {
277 for (unsigned i
= 0; i
< MAX_BUTTONS
; ++i
) {
278 if (!point_in_circle(x
, y
, buttons
[i
].x
, buttons
[i
].y
, buttons
[i
].r
)) continue;
280 if (buttons
[i
].finger
== ID_UNDEF
) {
282 if (buttons
[i
].key
!= 0) {
283 GInput
->PostKeyEvent(buttons
[i
].key
, 1, 0);
286 GCmdBuf
<< buttons
[i
].press
<< "\n";
288 buttons
[i
].finger
= finger
;
291 if (buttons
[i
].finger
== finger
) {
293 if (buttons
[i
].key
!= 0) {
294 GInput
->PostKeyEvent(buttons
[i
].key
, 0, 0);
297 GCmdBuf
<< buttons
[i
].release
<< "\n";
299 buttons
[i
].finger
= ID_UNDEF
;
306 //==========================================================================
310 // x, y IN [0.0..1.0]
311 // dx, dy IN [-1.0..1.0]
312 // pressure IN [0.0..1.0]
314 //==========================================================================
315 void Touch_Event (int type
, int id
, float x
, float y
, float dx
, float dy
, float pressure
) {
316 if (!touch_enable
|| SDL_GetNumTouchDevices() <= 0 || SDL_IsTextInputActive()) {
323 press_button(id
, x
, y
, true);
324 f
= (x
< 0.5f
? STEP_FINGER
: ROT_FINGER
);
325 if (fingers
[f
].id
== ID_UNDEF
) {
331 fingers
[f
].start_x
= x
;
332 fingers
[f
].start_y
= y
;
345 press_button(id
, x
, y
, false);
348 press_button(id
, fingers
[f
].start_x
, fingers
[f
].start_y
, false);
349 fingers
[f
].id
= ID_UNDEF
;
350 if (f
== STEP_FINGER
) {
351 if (fingers
[STEP_FINGER
].vx
< 0.0f
) press_pad(K_LEFTARROW
, false);
352 else if (fingers
[STEP_FINGER
].vx
> 0.0f
) press_pad(K_RIGHTARROW
, false);
353 if (fingers
[STEP_FINGER
].vy
< 0.0f
) press_pad(K_UPARROW
, false);
354 else if (fingers
[STEP_FINGER
].vy
> 0.0f
) press_pad(K_DOWNARROW
, false);
355 } else if (f
== ROT_FINGER
) {