DEADSOFTWARE

Added touchscreen controls
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Sat, 24 Feb 2018 19:11:16 +0000 (22:11 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Sat, 17 Mar 2018 00:04:27 +0000 (02:04 +0200)
src/engine/e_graphics.pas
src/engine/e_log.pas
src/game/g_console.pas
src/game/g_game.pas
src/game/g_main.pas
src/game/g_options.pas
src/game/g_touch.pas [new file with mode: 0644]
src/game/g_window.pas
src/lib/sdl2/sdlvideo.inc

index 891c65861f35d410caa42643337953059278cb23..bfef6d2e7e73f0f8f4476bbdcb49dd2cfc12b951 100644 (file)
@@ -958,8 +958,10 @@ end;
 procedure e_DrawQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue: Byte; Alpha: Byte = 0);
 var
   nX1, nY1, nX2, nY2: Integer;
+{$IFDEF USE_NANOGL}
+  v: array [0..15] of GLfloat;
+{$ENDIF}
 begin
-{$IFNDEF USE_NANOGL} // FIXIT: nanoGL doesn't support glBegin(GL_LINES)
   if e_NoGraphics then Exit;
   // Only top-left/bottom-right quad
   if X1 > X2 then
@@ -985,7 +987,34 @@ begin
   glDisable(GL_TEXTURE_2D);
   glColor4ub(Red, Green, Blue, 255-Alpha);
   glLineWidth(1);
+{$IFDEF USE_NANOGL}
+  nX1 := X1; nY1 := Y1;
+  nX2 := X2; nY2 := Y1;
+  e_LineCorrection(nX1, nY1, nX2, nY2);
+  v[0] := nX1; v[1] := nY1; v[2] := nX2; v[3] := nY2;
+
+  nX1 := X2; nY1 := Y1;
+  nX2 := X2; nY2 := Y2;
+  e_LineCorrection(nX1, nY1, nX2, nY2);
+  v[4] := nX1; v[5] := nY1; v[6] := nX2; v[7] := nY2;
+
+  nX1 := X2; nY1 := Y2;
+  nX2 := X1; nY2 := Y2;
+  e_LineCorrection(nX1, nY1, nX2, nY2);
+  v[8] := nX1; v[9] := nY1; v[10] := nX2; v[11] := nY2;
+
+  nX1 := X1; nY1 := Y2;
+  nX2 := X1; nY2 := Y1;
+  e_LineCorrection(nX1, nY1, nX2, nY2);
+  v[12] := nX1; v[13] := nY1; v[14] := nX2; v[15] := nY2;
 
+  glVertexPointer(2, GL_FLOAT, 0, @v[0]);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glDisableClientState(GL_COLOR_ARRAY);
+  glDisableClientState(GL_NORMAL_ARRAY);
+  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+  glDrawArrays(GL_LINES, 0, 16);
+{$ELSE}
   glBegin(GL_LINES);
     nX1 := X1; nY1 := Y1;
     nX2 := X2; nY2 := Y1;
@@ -1011,11 +1040,11 @@ begin
     glVertex2i(nX1, nY1);
     glVertex2i(nX2, nY2);
   glEnd();
+{$ENDIF}
 
   glColor4ub(e_Colors.R, e_Colors.G, e_Colors.B, 255);
 
   glDisable(GL_BLEND);
-{$ENDIF}
 end;
 
 procedure e_DrawFillQuad(X1, Y1, X2, Y2: Integer; Red, Green, Blue, Alpha: Byte;
index e2a88e08b66305dfebdc895eab2bfc17a40c9cdf..22db6527781c00ec9d8301d13e2b705a5365c7e4 100644 (file)
@@ -99,8 +99,8 @@ begin
 {$IFDEF ANDROID}
   cstr := GetMem(len + 1);
   for slen := 0 to len - 1 do
-    cstr[slen] := Char(b[slen]);
-  cstr[slen + 1] := #0;
+    cstr[slen] := Chr(b[slen]);
+  cstr[len] := #0;
   SDL_Log(cstr, []);
   Dispose(cstr);
 {$ENDIF}
index 3ed1d138818daa0cdb64e42251613634afc6ec5e..230e5b6e8cf4234d88c3a020fe854b79e8aaeb6d 100644 (file)
@@ -60,7 +60,7 @@ implementation
 
 uses
   g_textures, g_main, e_graphics, e_input, g_game,
-  SysUtils, g_basic, g_options, Math,
+  SysUtils, g_basic, g_options, Math, g_touch,
   g_menu, g_language, g_net, g_netmsg, e_log, conbuf;
 
 
@@ -926,6 +926,7 @@ begin
   if gChatShow then Exit;
   gConsoleShow := not gConsoleShow;
   Cons_Shown := True;
+  g_Touch_ShowKeyboard(gConsoleShow or gChatShow);
 end;
 
 procedure g_Console_Chat_Switch(Team: Boolean = False);
@@ -938,6 +939,7 @@ begin
     gChatEnter := False;
   Line := '';
   CPos := 1;
+  g_Touch_ShowKeyboard(gConsoleShow or gChatShow);
 end;
 
 procedure g_Console_Char(C: AnsiChar);
@@ -1114,6 +1116,7 @@ begin
           CPos := 1;
           gChatShow := False;
           gJustChatted := True;
+          g_Touch_ShowKeyboard(gConsoleShow or gChatShow);
         end;
     end;
     IK_TAB:
index 09618966963e2bbe2cc06dd55eedf42e0ad0127d..5bceb41af2105b7821b43663e12a8930b1cbe518 100644 (file)
@@ -22,7 +22,8 @@ uses
   SysUtils, Classes,
   MAPDEF,
   g_basic, g_player, e_graphics, g_res_downloader,
-  g_sound, g_gui, utils, md5, mempool, xprofiler;
+  g_sound, g_gui, utils, md5, mempool, xprofiler,
+  g_touch;
 
 type
   TGameSettings = record
@@ -3759,6 +3760,8 @@ begin
   if gGameOn then drawProfilers();
 
   g_Holmes_DrawUI();
+
+  g_Touch_Draw;
 end;
 
 procedure g_Game_Quit();
index 9a7250f9fc28a21b9933dfaa61123c4587f70fe7..93655f66f8a7fe939e1338b31b9d517b2ca632da 100644 (file)
@@ -116,8 +116,10 @@ begin
     raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
 
 {$IFNDEF HEADLESS}
+{$IFNDEF ANDROID}
   SDL_StartTextInput();
 {$ENDIF}
+{$ENDIF}
 
 {$IFNDEF HEADLESS}
   flexloaded := true;
index d05ed835f86d43d5edd808f7db4a0ff6d17f217f..ee8518a7c8983419dc22c3972284353901e3a2f0 100644 (file)
@@ -190,7 +190,10 @@ begin
     KeyPrevWeapon := 71;
     KeyOpen := 54;
     KeyStrafe := 0;
-    for i := 0 to High(KeyWeapon) do
+    for i := 0 to 9 do
+      KeyWeapon[i] := 30 + i;
+    KeyWeapon[10] := 45;
+    for i := 10 to High(KeyWeapon) do
       KeyWeapon[i] := 0;
 
     KeyRight2 := 0;
diff --git a/src/game/g_touch.pas b/src/game/g_touch.pas
new file mode 100644 (file)
index 0000000..0a02e57
--- /dev/null
@@ -0,0 +1,299 @@
+(* Copyright (C)  Doom 2D: Forever Developers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *)
+{$INCLUDE ../shared/a_modes.inc}
+unit g_touch;
+
+interface
+
+  uses
+    SDL2;
+
+  procedure g_Touch_ShowKeyboard(yes: Boolean);
+  procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
+  procedure g_Touch_Draw;
+
+implementation
+
+  uses
+    SysUtils,
+    e_log, e_graphics, e_input, g_options, g_game, g_main, g_weapons, g_console;
+
+  const
+    CTL_NONE  = 0;
+    CTL_LEFT  = 1;
+    CTL_RIGHT = 2;
+    CTL_UP    = 3;
+    CTL_DOWN  = 4;
+    CTL_FIRE  = 5;
+    CTL_OPEN  = 6;
+    CTL_JUMP  = 7;
+    CTL_CHAT  = 8;
+    CTL_ESC   = 9;
+    CTL_W0    = 10;
+    CTL_W1    = 11;
+    CTL_W2    = 12;
+    CTL_W3    = 13;
+    CTL_W4    = 14;
+    CTL_W5    = 15;
+    CTL_W6    = 16;
+    CTL_W7    = 17;
+    CTL_W8    = 18;
+    CTL_W9    = 19;
+    CTL_W10   = 20;
+    CTL_CON   = 21;
+    CTL_STAT  = 22;
+    CTL_TCHAT = 23;
+    CTL_LAST  = 23;
+
+  var
+    size: Single;
+    enabled: Boolean;
+    keyFinger: array [1..CTL_LAST] of Integer;
+
+  procedure GetControlRect(control: Integer; out x, y, w, h: Integer; out founded: Boolean);
+     var
+       sw, sh, sz: Integer;
+       dpi: Single;
+  begin
+    if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
+      dpi := 96;
+
+    founded := true;
+    sz := Trunc(size * dpi);
+    x := 0; y := 0; w := sz; h := sz;
+    sw := gScreenWidth; sh := gScreenHeight;
+    case control of
+      CTL_LEFT:  begin x := 0;            y := sh div 2 - h div 2; end;
+      CTL_RIGHT: begin x := w;            y := sh div 2 - h div 2; end;
+      CTL_UP:    begin x := sw - w - 1;   y := sh div 2 - h div 2 - h; end;
+      CTL_DOWN:  begin x := sw - w - 1;   y := sh div 2 - h div 2 + h; end;
+      CTL_FIRE:  begin x := sw - 1*w - 1; y := sh div 2 - h div 2; end;
+      CTL_OPEN:  begin x := sw - 3*w - 1; y := sh div 2 - h div 2; end;
+      CTL_JUMP:  begin x := sw - 2*w - 1; y := sh div 2 - h div 2; end;
+    else
+      w := sz div 2; h := sz div 2;
+      case control of
+        CTL_W0:    begin x := sw div 2 - w div 2 - 5*w - 1; y := sh - 1*h - 1; end;
+        CTL_W1:    begin x := sw div 2 - w div 2 - 4*w - 1; y := sh - 1*h - 1; end;
+        CTL_W2:    begin x := sw div 2 - w div 2 - 3*w - 1; y := sh - 1*h - 1; end;
+        CTL_W3:    begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 1*h - 1; end;
+        CTL_W4:    begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 1*h - 1; end;
+        CTL_W5:    begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 1*h - 1; end;
+        CTL_W6:    begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 1*h - 1; end;
+        CTL_W7:    begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 1*h - 1; end;
+        CTL_W8:    begin x := sw div 2 - w div 2 + 3*w - 1; y := sh - 1*h - 1; end;
+        CTL_W9:    begin x := sw div 2 - w div 2 + 4*w - 1; y := sh - 1*h - 1; end;
+        CTL_W10:   begin x := sw div 2 - w div 2 + 5*w - 1; y := sh - 1*h - 1; end;
+        CTL_CHAT:  begin x := sw div 2 - w div 2 - 2*w - 1; y := sh - 2*h - 1; end;
+        CTL_ESC:   begin x := sw div 2 - w div 2 - 1*w - 1; y := sh - 2*h - 1; end;
+        CTL_CON:   begin x := sw div 2 - w div 2 + 0*w - 1; y := sh - 2*h - 1; end;
+        CTL_STAT:  begin x := sw div 2 - w div 2 + 1*w - 1; y := sh - 2*h - 1; end;
+        CTL_TCHAT: begin x := sw div 2 - w div 2 + 2*w - 1; y := sh - 2*h - 1; end;
+      else
+        founded := false
+      end
+    end
+  end;
+
+  function GetMenuKey(control: Integer): Word;
+  begin
+    case control of
+      CTL_LEFT:  result := IK_LEFT;
+      CTL_RIGHT: result := IK_RIGHT;
+      CTL_UP:    result := IK_UP;
+      CTL_DOWN:  result := IK_DOWN;
+      CTL_OPEN:  result := IK_ENTER;
+      CTL_FIRE:  result := IK_ENTER;
+      CTL_JUMP:  result := IK_SPACE;
+      CTL_ESC:   result := IK_ESCAPE;
+      CTL_W0:    result := SDL_SCANCODE_0;
+      CTL_W1:    result := SDL_SCANCODE_1;
+      CTL_W2:    result := SDL_SCANCODE_2;
+      CTL_W3:    result := SDL_SCANCODE_3;
+      CTL_W4:    result := SDL_SCANCODE_4;
+      CTL_W5:    result := SDL_SCANCODE_5;
+      CTL_W6:    result := SDL_SCANCODE_6;
+      CTL_W7:    result := SDL_SCANCODE_7;
+      CTL_W8:    result := SDL_SCANCODE_8;
+      CTL_W9:    result := SDL_SCANCODE_9;
+      CTL_CON:   result := IK_GRAVE;
+    else
+      result := IK_INVALID;
+    end
+  end;
+
+  function GetPlayerKey(control: Integer): Word;
+  begin
+    case control of
+      CTL_LEFT:  result := gGameControls.P1Control.KeyLeft;
+      CTL_RIGHT: result := gGameControls.P1Control.KeyRight;
+      CTL_UP:    result := gGameControls.P1Control.KeyUp;
+      CTL_DOWN:  result := gGameControls.P1Control.KeyDown;
+      CTL_OPEN:  result := gGameControls.P1Control.KeyOpen;
+      CTL_FIRE:  result := gGameControls.P1Control.KeyFire;
+      CTL_JUMP:  result := gGameControls.P1Control.KeyJump;
+      CTL_CHAT:  result := gGameControls.GameControls.Chat;
+      CTL_ESC:   result := IK_ESCAPE;
+      CTL_W0:    result := gGameControls.P1Control.KeyWeapon[WEAPON_KASTET];
+      CTL_W1:    result := gGameControls.P1Control.KeyWeapon[WEAPON_SAW];
+      CTL_W2:    result := gGameControls.P1Control.KeyWeapon[WEAPON_PISTOL];
+      CTL_W3:    result := gGameControls.P1Control.KeyWeapon[WEAPON_SHOTGUN1];
+      CTL_W4:    result := gGameControls.P1Control.KeyWeapon[WEAPON_SHOTGUN2];
+      CTL_W5:    result := gGameControls.P1Control.KeyWeapon[WEAPON_CHAINGUN];
+      CTL_W6:    result := gGameControls.P1Control.KeyWeapon[WEAPON_ROCKETLAUNCHER];
+      CTL_W7:    result := gGameControls.P1Control.KeyWeapon[WEAPON_PLASMA];
+      CTL_W8:    result := gGameControls.P1Control.KeyWeapon[WEAPON_BFG];
+      CTL_W9:    result := gGameControls.P1Control.KeyWeapon[WEAPON_SUPERPULEMET];
+      CTL_W10:   result := gGameControls.P1Control.KeyWeapon[WEAPON_FLAMETHROWER];
+      CTL_CON:   result := IK_GRAVE;
+      CTL_STAT:  result := gGameControls.GameControls.Stat;
+      CTL_TCHAT: result := gGameControls.GameControls.TeamChat;
+    else
+      result := IK_INVALID
+    end
+  end;
+
+  function GetControlName(control: Integer): String;
+  begin
+    case control of
+      CTL_LEFT:  result := 'LEFT';
+      CTL_RIGHT: result := 'RIGHT';
+      CTL_UP:    result := 'UP';
+      CTL_DOWN:  result := 'DOWN';
+      CTL_OPEN:  result := 'OPEN';
+      CTL_FIRE:  result := 'FIRE';
+      CTL_JUMP:  result := 'JUMP';
+      CTL_CHAT:  result := 'CHAT';
+      CTL_ESC:   result := 'ESC';
+      CTL_W0:    result := '0';
+      CTL_W1:    result := '1';
+      CTL_W2:    result := '2';
+      CTL_W3:    result := '3';
+      CTL_W4:    result := '4';
+      CTL_W5:    result := '5';
+      CTL_W6:    result := '6';
+      CTL_W7:    result := '7';
+      CTL_W8:    result := '8';
+      CTL_W9:    result := '9';
+      CTL_W10:   result := '10';
+      CTL_CON:   result := 'CON';
+      CTL_STAT:  result := 'STAT';
+      CTL_TCHAT: result := 'TEAM';
+    else
+      result := '(WAT?)'
+    end
+  end;
+
+  procedure DrawRect(x, y, w, h: Integer);
+  begin
+    e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 127);
+  end;
+
+  function IntersectControl(ctl, xx, yy: Integer): Boolean;
+    var
+      x, y, w, h: Integer;
+      founded: Boolean;
+  begin
+    GetControlRect(ctl, x, y, w, h, founded);
+    result := founded and (xx >= x) and (yy >= y) and (xx <= x + w) and (yy <= y + h);
+  end;
+
+  procedure g_Touch_ShowKeyboard(yes: Boolean);
+  begin
+{$IFNDEF HEADLESS}
+    if not enabled then
+      Exit;
+
+    if yes then
+      SDL_StartTextInput
+    else
+      SDL_StopTextInput
+{$ENDIF}
+  end;
+
+  procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
+    var
+      x, y, i, finger: Integer;
+  begin
+    if not enabled then
+      Exit;
+    if SDL_IsTextInputActive() = SDL_True then
+      Exit;
+
+    finger := ev.fingerId + 2;
+    x := Trunc(ev.x * gScreenWidth);
+    y := Trunc(ev.y * gScreenHeight);
+
+    for i := 1 to CTL_LAST do
+    begin
+      if IntersectControl(i, x, y) then
+      begin
+        if ev.type_ = SDL_FINGERUP then
+          keyFinger[i] := 0
+        else if ev.type_ = SDL_FINGERMOTION then
+          keyFinger[i] := finger
+        else if ev.type_ = SDL_FINGERDOWN then
+          begin
+            KeyPress(GetMenuKey(i));
+            keyFinger[i] := finger;
+          end
+      end
+      else if keyFinger[i] = finger then
+      begin
+        if ev.type_ = SDL_FINGERUP then
+          keyFinger[i] := 0
+        else if ev.type_ = SDL_FINGERMOTION then
+          keyFinger[i] := 0
+      end;
+
+      e_KeyUpDown(GetPlayerKey(i), keyFinger[i] <> 0);
+      e_KeyUpDown(GetMenuKey(i), keyFinger[i] <> 0);
+    end;
+  end;
+
+  procedure g_Touch_Draw;
+    var
+      i, x, y, w, h: Integer;
+      founded: Boolean;
+  begin
+{$IFNDEF HEADLESS}
+    if not enabled then
+      Exit;
+    if SDL_IsTextInputActive() = SDL_True then
+      Exit;
+
+    for i := 1 to CTL_LAST do
+    begin
+      GetControlRect(i, x, y, w, h, founded);
+      if founded then
+      begin
+        DrawRect(x, y, w, h);
+        e_TextureFontPrint(x, y, GetControlName(i), gStdFont)
+      end;
+    end;
+{$ENDIF}
+  end;
+
+initialization
+{$IFDEF ANDROID}
+  enabled := true;
+{$ENDIF}
+  size := 1;
+  conRegVar('touch_enable', @enabled, 'enable/disable virtual buttons', 'draw buttons');
+  conRegVar('touch_size', @size, 0.1, 10, 'size of virtual buttons', 'button size');
+end.
+
+
index 395f44e415144e1a9aefedc2fee5355f3383389a..3a29d0803081a585868b03fdd87b0bd01b7e8748 100644 (file)
@@ -1,4 +1,4 @@
- (* Copyright (C)  Doom 2D: Forever Developers
+(* Copyright (C)  Doom 2D: Forever Developers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -61,7 +61,8 @@ uses
   g_console, e_input, g_options, g_game,
   g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net,
   g_map, g_gfx, g_monsters, g_holmes, xprofiler,
-  sdlcarcass, fui_ctls;
+  sdlcarcass, fui_ctls,
+  g_touch;
 
 
 const
@@ -471,6 +472,8 @@ begin
     SDL_KEYDOWN, SDL_KEYUP:
       begin
         key := ev.key.keysym.scancode;
+        if key = SDL_SCANCODE_AC_BACK then
+          key := SDL_SCANCODE_ESCAPE;
         down := (ev.type_ = SDL_KEYDOWN);
         {$IF not DEFINED(HEADLESS)}
         if fuiOnSDLEvent(ev) then
@@ -497,6 +500,9 @@ begin
         if (keychr > 0) and (keychr <= 255) then CharPress(AnsiChar(keychr));
       end;
 
+    SDL_FINGERMOTION, SDL_FINGERDOWN, SDL_FINGERUP:
+      g_Touch_HandleEvent(ev.tfinger);
+
     // other key presses and joysticks are handled in e_input
   end;
 end;
index 2ec24e8ce2600ab5a8ec2c744b89a8248a2c1b88..6c4c42c4e1f3e1724559d8c8d6a160eb4660962f 100644 (file)
@@ -389,6 +389,12 @@ function SDL_GetDisplayBounds(displayIndex: SInt32; rect: PSDL_Rect): SInt32 cde
 
 function SDL_GetNumDisplayModes(displayIndex: SInt32): SInt32 cdecl; external SDL_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDL_GetNumDisplayModes' {$ENDIF} {$ENDIF};
 
+  {**
+   *  Get the dots/pixels-per-inch for a display.
+   *}
+
+function SDL_GetDisplayDPI(displayIndex: SInt32; ddpi, hdpi, vdpi: PFloat): SInt32 cdecl; external SDL_LibName {$IFDEF DELPHI} {$IFDEF MACOS} name '_SDL_GetDisplayDPI' {$ENDIF} {$ENDIF};
+
   {**
    *  Fill in information about a specific display mode.
    *