DEADSOFTWARE

revive sdl2 system driver
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Tue, 8 Oct 2019 19:59:52 +0000 (22:59 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Sun, 13 Oct 2019 14:19:20 +0000 (17:19 +0300)
src/engine/e_sound_sdl.inc
src/game/g_main.pas
src/game/sdl/g_system.pas
src/game/sdl2/g_system.pas [new file with mode: 0644]
src/game/sdl2/g_touch.pas [new file with mode: 0644]
src/game/stub/g_system.pas

index 4d9eaba5d983da5fc644b7255be1923dfcce928f..ccfd9c4bc2715732e3d746db9f45e1f02065ff9d 100644 (file)
@@ -178,6 +178,11 @@ begin
   Result := False;
   SoundInitialized := False;
 
+  {$IFDEF HEADLESS}
+    // HACK: shit this into env and hope for the best
+    SetEnvVar('SDL_AUDIODRIVER', 'dummy');
+  {$ELSEIF}
+
   if NoOutput then begin Result := true; Exit end;
 
   // wow, this is actually MIDI player!
index 92c0ff5aa2a35d009fec83e43c69a688f6655cd5..222002baa53a1a312be411a51bcc1a3f6253431a 100644 (file)
@@ -39,9 +39,6 @@ uses
 {$INCLUDE ../nogl/noGLuses.inc}
 {$IFDEF ENABLE_HOLMES}
   g_holmes, fui_wadread, fui_style, fui_gfx_gl,
-{$ENDIF}
-{$IFDEF USE_SDL2}
-  SDL2,
 {$ENDIF}
   wadreader, e_log, g_window,
   e_graphics, e_input, g_game, g_console, g_gui,
@@ -87,30 +84,6 @@ begin
 {$ENDIF}
   e_WriteToStdOut := False; //{$IFDEF HEADLESS}True;{$ELSE}False;{$ENDIF}
 
-{$IFDEF USE_SDL2}
-{$IFDEF HEADLESS}
- {$IFDEF USE_SDLMIXER}
-  sdlflags := SDL_INIT_TIMER or SDL_INIT_AUDIO or $00004000;
-  // HACK: shit this into env and hope for the best
-  SetEnvVar('SDL_AUDIODRIVER', 'dummy');
- {$ELSE}
-  sdlflags := SDL_INIT_TIMER or $00004000;
- {$ENDIF}
-{$ELSE}
- {$IFDEF USE_SDLMIXER}
-  {*sdlflags := SDL_INIT_EVERYTHING;*}
-  sdlflags := SDL_INIT_JOYSTICK or SDL_INIT_TIMER or SDL_INIT_VIDEO;
- {$ELSE}
-  sdlflags := SDL_INIT_JOYSTICK or SDL_INIT_TIMER or SDL_INIT_VIDEO;
- {$ENDIF}
-{$ENDIF}
-
-  SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, '0');
-
-  if SDL_Init(sdlflags) < 0 then
-    raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
-{$ENDIF}
-
   e_WriteLog('Init Input', TMsgType.Notify);
   e_InitInput;
 
@@ -125,9 +98,7 @@ begin
   e_WriteLog(gLanguage, TMsgType.Notify);
   g_Language_Set(gLanguage);
 
-{$IFNDEF USE_SDL2}
   sys_Init;
-{$ENDIF}
 
 {$IF not DEFINED(HEADLESS) and DEFINED(ENABLE_HOLMES)}
   flexloaded := true;
@@ -182,12 +153,7 @@ begin
   SDLMain();
 {$WARNINGS ON}
 
-{$IFDEF USE_SDL2}
-  e_WriteLog('Releasing SDL', TMsgType.Notify);
-  SDL_Quit();
-{$ELSE}
   sys_Final;
-{$ENDIF}
 end;
 
 procedure Init();
index 5caa9c9e5788a94044266a26f7ea8e8d6b692d70..5fe730283d1c6384f36ba8d46abcabca7a1a1abe 100644 (file)
@@ -48,6 +48,9 @@ implementation
     e_log, e_graphics, e_input,
     g_options, g_window, g_console, g_game, g_menu, g_gui, g_main;
 
+  const
+    GameTitle = 'Doom 2D: Forever (SDL 1.2)';
+
   var
     userResize: Boolean;
     modeResize: Integer;
@@ -57,7 +60,7 @@ implementation
 
   function sys_GetTicks (): Int64;
   begin
-    Result := SDL_GetTicks()
+    result := SDL_GetTicks()
   end;
 
   procedure sys_Delay (ms: Integer);
@@ -89,8 +92,8 @@ implementation
   function InitWindow (w, h, bpp: Integer; fullScreen: Boolean): Boolean;
     var flags: Uint32;
   begin
-    e_LogWritefln('InitWindow %s %s %s %s', [w, h, bpp, fullscreen]);
-    Result := False;
+    e_LogWritefln('InitWindow %s %s %s %s', [w, h, bpp, fullScreen]);
+    result := False;
     SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
     SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
     SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
@@ -106,9 +109,9 @@ implementation
       screen := SDL_SetVideoMode(w, h, bpp, flags);
       if screen <> nil then
       begin
-        SDL_WM_SetCaption('Doom 2D: Forever (SDL 1.2)', nil);
+        SDL_WM_SetCaption(GameTitle, nil);
         UpdateSize(w, h);
-        Result := True
+        result := True
       end
     end
     else
@@ -260,7 +263,7 @@ implementation
     end
     else if gConsoleShow or gChatShow or (g_ActiveWindow <> nil) then
     begin
-      KeyPress(key)
+      KeyPress(key) // key repeat in menus and shit
     end;
     if down and IsValid1251(ev.keysym.unicode) and IsPrintable1251(ch) then
       CharPress(ch)
@@ -284,6 +287,7 @@ implementation
               InitWindow(ev.resize.w, ev.resize.h, gBPP, gFullscreen)
           end;
         SDL_KEYUP, SDL_KEYDOWN: HandleKeyboard(ev.key);
+        SDL_VIDEOEXPOSE: sys_Repaint;
       end
     end
   end;
@@ -300,14 +304,15 @@ implementation
   procedure sys_Init;
     var flags: Uint32; ok: Boolean;
   begin
+    e_WriteLog('Init SDL', TMsgType.Notify);
     flags := SDL_INIT_VIDEO or SDL_INIT_AUDIO or
              SDL_INIT_TIMER or SDL_INIT_JOYSTICK
              (*or SDL_INIT_NOPARACHUTE*);
     if SDL_Init(flags) <> 0 then
-      raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
+      raise Exception.Create('SDL: Init failed: ' + SDL_GetError);
     ok := InitWindow(gScreenWidth, gScreenHeight, gBPP, gFullScreen);
     if not ok then
-      raise Exception.Create('SDL: failed to set videomode: ' + SDL_GetError);
+      raise Exception.Create('SDL: Failed to set videomode: ' + SDL_GetError);
     SDL_EnableUNICODE(1);
     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
   end;
diff --git a/src/game/sdl2/g_system.pas b/src/game/sdl2/g_system.pas
new file mode 100644 (file)
index 0000000..5a24a48
--- /dev/null
@@ -0,0 +1,449 @@
+(* 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, version 3 of the License ONLY.
+ *
+ * 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_system;
+
+interface
+
+  uses Utils;
+
+  (* --- Utils --- *)
+  function sys_GetTicks (): Int64;
+  procedure sys_Delay (ms: Integer);
+
+  (* --- Graphics --- *)
+  function sys_GetDispalyModes (bpp: Integer): SSArray;
+  function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
+  procedure sys_EnableVSync (yes: Boolean);
+  procedure sys_Repaint;
+
+  (* --- Input --- *)
+  function sys_HandleInput (): Boolean;
+  procedure sys_RequestQuit;
+
+  (* --- Init --- *)
+  procedure sys_Init;
+  procedure sys_Final;
+
+implementation
+
+  uses
+    SysUtils, SDL2, GL, Math,
+    e_log, e_graphics, e_input,
+    g_touch,
+    g_options, g_window, g_console, g_game, g_menu, g_gui, g_main;
+
+  const
+    GameTitle = 'Doom 2D: Forever (SDL 2)';
+
+  var
+    window: PSDL_Window;
+    context: TSDL_GLContext;
+    display: Integer;
+    JoystickHandle: array [0..e_MaxJoys - 1] of PSDL_Joystick;
+    JoystickHatState: array [0..e_MaxJoys - 1, 0..e_MaxJoyHats - 1, HAT_LEFT..HAT_DOWN] of Boolean;
+    JoystickZeroAxes: array [0..e_MaxJoys - 1, 0..e_MaxJoyAxes - 1] of Integer;
+
+  (* --------- Utils --------- *)
+
+  function sys_GetTicks (): Int64;
+  begin
+    result := SDL_GetTicks()
+  end;
+
+  procedure sys_Delay (ms: Integer);
+  begin
+    SDL_Delay(ms)
+  end;
+
+  (* --------- Graphics --------- *)
+
+  procedure UpdateSize (w, h: Integer);
+  begin
+    gWinSizeX := w;
+    gWinSizeY := h;
+    gWinRealPosX := 0;
+    gWinRealPosY := 0;
+    gScreenWidth := w;
+    gScreenHeight := h;
+    {$IFDEF ENABLE_HOLMES}
+      fuiScrWdt := w;
+      fuiScrHgt := h;
+    {$ENDIF}
+    e_ResizeWindow(w, h);
+    e_InitGL;
+    g_Game_SetupScreenSize;
+    g_Menu_Reset;
+    g_Game_ClearLoading;
+  end;
+
+  function InitWindow (w, h, bpp: Integer; fullScreen: Boolean): Boolean;
+    var flags: UInt32;
+  begin
+    e_LogWritefln('InitWindow %s %s %s %s', [w, h, bpp, fullScreen]);
+    result := false;
+    if window = nil then
+    begin
+      {$IFDEF USE_GLES1}
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
+      {$ELSE}
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+        SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
+        SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
+        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
+        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); // lights; it is enough to have 1-bit stencil buffer for lighting, but...
+      {$ENDIF}
+      flags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
+      if fullScreen then flags := flags or SDL_WINDOW_FULLSCREEN;
+      window := SDL_CreateWindow(GameTitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, flags);
+      if window <> nil then
+      begin
+        context := SDL_GL_CreateContext(window);
+        if context <> nil then
+        begin
+          UpdateSize(w, h);
+          result := true
+        end
+        else
+        begin
+          e_LogWritefln('SDL: unable to create OpenGL context: %s', [SDL_GetError])
+        end
+      end
+      else
+      begin
+        e_LogWritefln('SDL: unable to create window: %s', [SDL_GetError])
+      end
+    end
+    else
+    begin
+      if fullScreen then flags := SDL_WINDOW_FULLSCREEN else flags := 0;
+      SDL_SetWindowSize(window, w, h);
+      SDL_SetWindowFullscreen(window, flags);
+      UpdateSize(w, h);
+      result := true
+    end
+  end;
+
+  procedure sys_Repaint;
+  begin
+    SDL_GL_SwapWindow(window)
+  end;
+
+  procedure sys_EnableVSync (yes: Boolean);
+  begin
+    if yes then
+      SDL_GL_SetSwapInterval(1)
+    else
+      SDL_GL_SetSwapInterval(0)
+  end;
+
+  function sys_GetDispalyModes (bpp: Integer): SSArray;
+    var i, count, num, pw, ph: Integer; m: TSDL_DisplayMode;
+  begin
+    result := nil;
+    num := SDL_GetNumDisplayModes(display);
+    if num < 0 then
+      e_LogWritefln('SDL: unable to get numer of available display modes: %s', [SDL_GetError]);
+    if num > 0 then
+    begin
+      e_LogWritefln('Video modes for display %s:', [display]);
+      SetLength(result, num);
+      i := 0; count := 0; pw := 0; ph := 0;
+      while i < num do
+      begin
+        SDL_GetDisplayMode(display, i, @m);
+        if ((pw <> m.w) or (ph <> m.h)) then
+        begin
+          e_LogWritefln('* %sx%sx%s@%s', [m.w, m.h, SDL_BITSPERPIXEL(m.format), m.refresh_rate]);
+          pw := m.w; ph := m.h;
+          result[count] := IntToStr(m.w) + 'x' + IntToStr(m.h);
+          Inc(count);
+        end
+        else
+        begin
+          e_LogWritefln('- %sx%sx%s@%s', [m.w, m.h, SDL_BITSPERPIXEL(m.format), m.refresh_rate]);
+        end;
+        Inc(i)
+      end;
+      SetLength(result, count)
+    end
+  end;
+
+  function sys_SetDisplayMode (w, h, bpp: Integer; fullScreen: Boolean): Boolean;
+  begin
+    result := InitWindow(w, h, bpp, fullScreen)
+  end;
+
+  (* --------- Joystick --------- *)
+
+  procedure HandleJoyButton (var ev: TSDL_JoyButtonEvent);
+    var down: Boolean; key: Integer;
+  begin
+    if (ev.which < e_MaxJoys) and (ev.button < e_MaxJoyBtns) then
+    begin
+      key := e_JoyButtonToKey(ev.which, ev.button);
+      down := ev.type_ = SDL_JOYBUTTONDOWN;
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: jbutton, joy=%s, button=%s, keycode=%s, press=%s', [ev.which, ev.button, key, down]);
+      e_KeyUpDown(key, down);
+      g_Console_ProcessBind(key, down)
+    end
+    else
+    begin
+      if g_dbg_input then
+      begin
+        down := ev.type_ = SDL_JOYBUTTONDOWN;
+        e_LogWritefln('Input Debug: NOT IN RANGE! jbutton, joy=%s, button=%s, press=%s', [ev.which, ev.button, down])
+      end
+    end
+  end;
+
+  procedure HandleJoyAxis (var ev: TSDL_JoyAxisEvent);
+    var key, minuskey: Integer;
+  begin
+    if (ev.which < e_MaxJoys) and (ev.axis < e_MaxJoyAxes) then
+    begin
+      key := e_JoyAxisToKey(ev.which, ev.axis, AX_PLUS);
+      minuskey := e_JoyAxisToKey(ev.which, ev.axis, AX_MINUS);
+
+      if g_dbg_input then
+          e_LogWritefln('Input Debug: jaxis, joy=%s, axis=%s, value=%s, zeroaxes=%s, deadzone=%s', [ev.which, ev.axis, ev.value, JoystickZeroAxes[ev.which, ev.axis], e_JoystickDeadzones[ev.which]]);
+
+      if ev.value < JoystickZeroAxes[ev.which, ev.axis] - e_JoystickDeadzones[ev.which] then
+      begin
+        if (e_KeyPressed(key)) then
+        begin
+          e_KeyUpDown(key, False);
+          g_Console_ProcessBind(key, False)
+        end;
+        e_KeyUpDown(minuskey, True);
+        g_Console_ProcessBind(minuskey, True)
+      end
+      else if ev.value > JoystickZeroAxes[ev.which, ev.axis] + e_JoystickDeadzones[ev.which] then
+      begin
+        if (e_KeyPressed(minuskey)) then
+        begin
+          e_KeyUpDown(minuskey, False);
+          g_Console_ProcessBind(minuskey, False)
+        end;
+        e_KeyUpDown(key, True);
+        g_Console_ProcessBind(key, True)
+      end
+      else
+      begin
+        if (e_KeyPressed(minuskey)) then
+        begin
+          e_KeyUpDown(minuskey, False);
+          g_Console_ProcessBind(minuskey, False)
+        end;
+        if (e_KeyPressed(key)) then
+        begin
+          e_KeyUpDown(key, False);
+          g_Console_ProcessBind(key, False)
+        end
+      end
+    end
+    else
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: NOT IN RANGE! jaxis, joy=%s, axis=%s, value=%s, zeroaxes=%s, deadzone=%s', [ev.which, ev.axis, ev.value, JoystickZeroAxes[ev.which, ev.axis], e_JoystickDeadzones[ev.which]])
+    end
+  end;
+
+  procedure HandleJoyHat (var ev: TSDL_JoyHatEvent);
+    var
+      down: Boolean;
+      i, key: Integer;
+      hat: array [HAT_LEFT..HAT_DOWN] of Boolean;
+  begin
+    if (ev.which < e_MaxJoys) and (ev.hat < e_MaxJoyHats) then
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: jhat, joy=%s, hat=%s, value=%s', [ev.which, ev.hat, ev.value]);
+      hat[HAT_UP] := LongBool(ev.value and SDL_HAT_UP);
+      hat[HAT_DOWN] := LongBool(ev.value and SDL_HAT_DOWN);
+      hat[HAT_LEFT] := LongBool(ev.value and SDL_HAT_LEFT);
+      hat[HAT_RIGHT] := LongBool(ev.value and SDL_HAT_RIGHT);
+      for i := HAT_LEFT to HAT_DOWN do
+      begin
+        if JoystickHatState[ev.which, ev.hat, i] <> hat[i] then
+        begin
+          down := hat[i];
+          key := e_JoyHatToKey(ev.which, ev.hat, i);
+          e_KeyUpDown(key, down);
+          g_Console_ProcessBind(key, down)
+        end
+      end;
+      JoystickHatState[ev.which, ev.hat] := hat
+    end
+    else
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: NOT IN RANGE! jhat, joy=%s, hat=%s, value=%s', [ev.which, ev.hat, ev.value])
+    end;
+  end;
+
+  procedure HandleJoyAdd (var ev: TSDL_JoyDeviceEvent);
+    var i: Integer;
+  begin
+    if (ev.which < e_MaxJoys) then
+    begin
+      JoystickHandle[ev.which] := SDL_JoystickOpen(ev.which);
+      if JoystickHandle[ev.which] <> nil then
+      begin
+        e_LogWritefln('Added Joystick %s', [ev.which]);
+        e_JoystickAvailable[ev.which] := True;
+        for i := 0 to Min(SDL_JoystickNumAxes(JoystickHandle[ev.which]), e_MaxJoyAxes) - 1 do
+          JoystickZeroAxes[ev.which, i] := SDL_JoystickGetAxis(JoystickHandle[ev.which], i)
+      end
+      else
+      begin
+        e_LogWritefln('Warning! Failed to open Joystick %s', [ev.which])
+      end
+    end
+    else
+    begin
+      e_LogWritefln('Warning! Added Joystick %s, but we support only <= %s', [ev.which, e_MaxJoys])
+    end
+  end;
+
+  procedure HandleJoyRemove (var ev: TSDL_JoyDeviceEvent);
+  begin
+    e_LogWritefln('Removed Joystick %s', [ev.which]);
+    if (ev.which < e_MaxJoys) then
+    begin
+      e_JoystickAvailable[ev.which] := False;
+      if JoystickHandle[ev.which] <> nil then
+        SDL_JoystickClose(JoystickHandle[ev.which]);
+      JoystickHandle[ev.which] := nil
+    end
+  end;
+
+  (* --------- Input --------- *)
+
+  function HandleWindow (var ev: TSDL_WindowEvent): Boolean;
+  begin
+    result := false;
+    case ev.event of
+      SDL_WINDOWEVENT_RESIZED: UpdateSize(ev.data1, ev.data2);
+      SDL_WINDOWEVENT_EXPOSED: sys_Repaint;
+      SDL_WINDOWEVENT_CLOSE: result := true;
+    end
+  end;
+
+  procedure HandleKeyboard (var ev: TSDL_KeyboardEvent);
+    var down: Boolean; key: Integer;
+  begin
+    key := ev.keysym.scancode;
+    down := (ev.type_ = SDL_KEYDOWN);
+    if key = SDL_SCANCODE_AC_BACK then
+      key := SDL_SCANCODE_ESCAPE;
+    if ev._repeat = 0 then
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: keysym, press=%s, scancode=%s', [down, key]);
+      e_KeyUpDown(key, down);
+      g_Console_ProcessBind(key, down);
+    end
+    else if gConsoleShow or gChatShow or (g_ActiveWindow <> nil) then
+    begin
+      KeyPress(key) // key repeat in menus and shit
+    end
+  end;
+
+  procedure HandleTextInput (var ev: TSDL_TextInputEvent);
+    var ch: UnicodeChar; sch: AnsiChar;
+  begin
+    if g_dbg_input then
+      e_LogWritefln('Input Debug: text, text=%s', [ev.text]);
+    Utf8ToUnicode(@ch, PChar(ev.text), 1);
+    if IsValid1251(Word(ch)) then
+    begin
+      sch := AnsiChar(wchar2win(ch));
+      CharPress(sch);
+    end;
+  end;
+
+  function sys_HandleInput (): Boolean;
+    var ev: TSDL_Event;
+  begin
+    result := false;
+    while SDL_PollEvent(@ev) <> 0 do
+    begin
+      case ev.type_ of
+        SDL_QUITEV: result := true;
+        SDL_WINDOWEVENT: result := HandleWindow(ev.window);
+        SDL_KEYUP, SDL_KEYDOWN: HandleKeyboard(ev.key);
+        SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP: HandleJoyButton(ev.jbutton);
+        SDL_JOYAXISMOTION: HandleJoyAxis(ev.jaxis);
+        SDL_JOYHATMOTION: HandleJoyHat(ev.jhat);
+        SDL_JOYDEVICEADDED: HandleJoyAdd(ev.jdevice);
+        SDL_JOYDEVICEREMOVED: HandleJoyRemove(ev.jdevice);
+        SDL_TEXTINPUT: HandleTextInput(ev.text);
+        SDL_FINGERMOTION, SDL_FINGERDOWN, SDL_FINGERUP: g_Touch_HandleEvent(ev.tfinger);
+      end
+    end
+  end;
+
+  procedure sys_RequestQuit;
+    var ev: TSDL_Event;
+  begin
+    ev.type_ := SDL_QUITEV;
+    SDL_PushEvent(@ev)
+  end;
+
+  (* --------- Init --------- *)
+
+  procedure sys_Init;
+    var flags: UInt32; ok: Boolean;
+  begin
+    e_WriteLog('Init SDL2', TMsgType.Notify);
+    {$IFDEF HEADLESS}
+      {$IFDEF USE_SDLMIXER}
+        flags := SDL_INIT_TIMER or SDL_INIT_AUDIO or $00004000;
+      {$ELSE}
+        flags := SDL_INIT_TIMER or $00004000;
+      {$ENDIF}
+    {$ELSE}
+      flags := SDL_INIT_JOYSTICK or SDL_INIT_TIMER or SDL_INIT_VIDEO;
+    {$ENDIF}
+    SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, '0');
+    if SDL_Init(flags) <> 0 then
+      raise Exception.Create('SDL: Init failed: ' + SDL_GetError);
+    ok := InitWindow(gScreenWidth, gScreenHeight, gBPP, gFullscreen);
+    if not ok then
+      raise Exception.Create('SDL: Failed to set videomode: ' + SDL_GetError);
+  end;
+
+  procedure sys_Final;
+  begin
+    e_WriteLog('Releasing SDL2', TMsgType.Notify);
+    if context <> nil then
+      SDL_GL_DeleteContext(context);
+    if window <> nil then
+      SDL_DestroyWindow(window);
+    window := nil;
+    context := nil;
+    SDL_Quit
+  end;
+
+initialization
+  conRegVar('sdl2_display_index', @display, 'use display index as base', '');
+end.
diff --git a/src/game/sdl2/g_touch.pas b/src/game/sdl2/g_touch.pas
new file mode 100644 (file)
index 0000000..6971879
--- /dev/null
@@ -0,0 +1,322 @@
+(* 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, version 3 of the License ONLY.
+ *
+ * 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;
+
+  var
+    g_touch_enabled: Boolean = False;
+    g_touch_size: Single = 1.0;
+    g_touch_offset: Single = 50.0;
+    g_touch_fire: Boolean = True;
+    g_touch_alt: Boolean = False;
+
+  procedure g_Touch_Init;
+  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_gui, g_weapons, g_console, g_window;
+
+  var
+    angleFire: Boolean;
+    keyFinger: array [VK_FIRSTKEY..VK_LASTKEY] of Integer;
+
+  procedure GetKeyRect(key: Integer; out x, y, w, h: Integer; out founded: Boolean);
+    var
+      sw, sh, sz: Integer;
+      dpi: Single;
+
+    procedure S (xx, yy, ww, hh: Single);
+    begin
+      x := Trunc(xx);
+      y := Trunc(yy);
+      w := Trunc(ww);
+      h := Trunc(hh);
+      founded := true;
+    end;
+
+  begin
+    founded := false;
+    if SDL_GetDisplayDPI(0, @dpi, nil, nil) <> 0 then
+      dpi := 96;
+
+    sz := Trunc(g_touch_size * dpi); sw := gScreenWidth; sh := gScreenHeight;
+    x := 0; y := Round(sh * g_touch_offset / 100);
+    w := sz; h := sz;
+
+    if SDL_IsTextInputActive() = SDL_True then
+      case key of
+        VK_HIDEKBD: S(sw - (sz/2), 0, sz / 2, sz / 2);
+      end
+    else if g_touch_alt then
+      case key of
+        (* top ------- x ------------------------------- y  w ----- h -- *)
+        VK_CONSOLE:  S(0,                                0, sz / 2, sz / 2);
+        VK_ESCAPE:   S(sw - 1*(sz/2) - 1,                0, sz / 2, sz / 2);
+        VK_SHOWKBD:  S(sw - 2*(sz/2) - 1,                0, sz / 2, sz / 2);
+        VK_CHAT:     S(sw / 2 - (sz/2) / 2 - (sz/2) - 1, 0, sz / 2, sz / 2);
+        VK_STATUS:   S(sw / 2 - (sz/2) / 2 - 1,          0, sz / 2, sz / 2);
+        VK_TEAM:     S(sw / 2 - (sz/2) / 2 + (sz/2) - 1, 0, sz / 2, sz / 2);
+        (* left --- x - y -------------- w - h --- *)
+        VK_PREV:  S(0,  sh - 3.0*sz - 1, sz, sz / 2);
+        VK_LEFT:  S(0,  sh - 2.0*sz - 1, sz, sz * 2);
+        VK_RIGHT: S(sz, sh - 2.0*sz - 1, sz, sz * 2);
+        (* right - x ------------ y -------------- w - h -- *)
+        VK_NEXT: S(sw - 1*sz - 1, sh - 3.0*sz - 1, sz, sz / 2);
+        VK_UP:   S(sw - 2*sz - 1, sh - 2.0*sz - 1, sz, sz / 2);
+        VK_FIRE: S(sw - 2*sz - 1, sh - 1.5*sz - 1, sz, sz);
+        VK_DOWN: S(sw - 2*sz - 1, sh - 0.5*sz - 1, sz, sz / 2);
+        VK_JUMP: S(sw - 1*sz - 1, sh - 2.0*sz - 1, sz, sz);
+        VK_OPEN: S(sw - 1*sz - 1, sh - 1.0*sz - 1, sz, sz);
+      end
+    else
+      case key of
+        (* left ----- x ----- y -------------- w ----- h -- *)
+        VK_ESCAPE:  S(0.0*sz, y - 1*sz - sz/2, sz,     sz / 2);
+        VK_LSTRAFE: S(0.0*sz, y - 0*sz - sz/2, sz / 2, sz);
+        VK_LEFT:    S(0.5*sz, y - 0*sz - sz/2, sz,     sz);
+        VK_RIGHT:   S(1.5*sz, y - 0*sz - sz/2, sz,     sz);
+        VK_RSTRAFE: S(2.5*sz, y - 0*sz - sz/2, sz / 2, sz);
+        (* right - x ------------ y --------------- w - h *)
+        VK_UP:   S(sw - 1*sz - 1, y -  1*sz - sz/2, sz, sz);
+        VK_FIRE: S(sw - 1*sz - 1, y -  0*sz - sz/2, sz, sz);
+        VK_DOWN: S(sw - 1*sz - 1, y - -1*sz - sz/2, sz, sz);
+        VK_NEXT: S(sw - 2*sz - 1, y -  1*sz - sz/2, sz, sz);
+        VK_JUMP: S(sw - 2*sz - 1, y -  0*sz - sz/2, sz, sz);
+        VK_PREV: S(sw - 3*sz - 1, y -  1*sz - sz/2, sz, sz);
+        VK_OPEN: S(sw - 3*sz - 1, y -  0*sz - sz/2, sz, sz);
+        (* bottom ---- x -------------------------- y ---------------- w ----- h -- *)
+        VK_CHAT:     S(sw/2 - sz/4 -  2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
+        VK_CONSOLE:  S(sw/2 - sz/4 -  1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
+        VK_STATUS:   S(sw/2 - sz/4 -  0*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
+        VK_TEAM:     S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
+        VK_SHOWKBD:  S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 2*(sz/2) - 1, sz / 2, sz / 2);
+        VK_0:        S(sw/2 - sz/4 -  5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_1:        S(sw/2 - sz/4 -  4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_2:        S(sw/2 - sz/4 -  3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_3:        S(sw/2 - sz/4 -  2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_4:        S(sw/2 - sz/4 -  1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_5:        S(sw/2 - sz/4 -  0*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_6:        S(sw/2 - sz/4 - -1*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_7:        S(sw/2 - sz/4 - -2*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_8:        S(sw/2 - sz/4 - -3*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_9:        S(sw/2 - sz/4 - -4*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+        VK_A:        S(sw/2 - sz/4 - -5*(sz/2) - 1, sh - 1*(sz/2) - 1, sz / 2, sz / 2);
+      end
+  end;
+
+  function GetKeyName(key: Integer): String;
+  begin
+    case key of
+      VK_SHOWKBD: result := 'KBD';
+      VK_HIDEKBD: result := 'KBD';
+      VK_LEFT:    result := 'LEFT';
+      VK_RIGHT:   result := 'RIGHT';
+      VK_UP:      result := 'UP';
+      VK_DOWN:    result := 'DOWN';
+      VK_FIRE:    result := 'FIRE';
+      VK_OPEN:    result := 'OPEN';
+      VK_JUMP:    result := 'JUMP';
+      VK_CHAT:    result := 'CHAT';
+      VK_ESCAPE:  result := 'ESC';
+      VK_0:       result := '0';
+      VK_1:       result := '1';
+      VK_2:       result := '2';
+      VK_3:       result := '3';
+      VK_4:       result := '4';
+      VK_5:       result := '5';
+      VK_6:       result := '6';
+      VK_7:       result := '7';
+      VK_8:       result := '8';
+      VK_9:       result := '9';
+      VK_A:       result := '10';
+      VK_B:       result := '11';
+      VK_C:       result := '12';
+      VK_D:       result := '13';
+      VK_E:       result := '14';
+      VK_F:       result := '15';
+      VK_CONSOLE: result := 'CON';
+      VK_STATUS:  result := 'STAT';
+      VK_TEAM:    result := 'TEAM';
+      VK_PREV:    result := '<PREW';
+      VK_NEXT:    result := 'NEXT>';
+      VK_LSTRAFE: result := '<';
+      VK_RSTRAFE: result := '>';
+    else
+      if (key > 0) and (key < e_MaxInputKeys) then
+        result := e_KeyNames[key]
+      else
+       result := '<' + IntToStr(key) + '>'
+    end
+  end;
+
+  function IntersectControl(ctl, xx, yy: Integer): Boolean;
+    var
+      x, y, w, h: Integer;
+      founded: Boolean;
+  begin
+    GetKeyRect(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_Init;
+  begin
+{$IFNDEF HEADLESS}
+    g_Touch_ShowKeyboard(FALSE);
+    g_touch_enabled := SDL_GetNumTouchDevices() > 0
+{$ENDIF}
+  end;
+
+  procedure g_Touch_ShowKeyboard(yes: Boolean);
+  begin
+{$IFNDEF HEADLESS}
+    if g_dbg_input then
+      e_LogWritefln('g_Touch_ShowKeyboard(%s)', [yes]);
+    (* on desktop we always receive text (needed for cheats) *)
+    if yes or (SDL_HasScreenKeyboardSupport() = SDL_FALSE) then
+      SDL_StartTextInput
+    else
+      SDL_StopTextInput
+{$ENDIF}
+  end;
+
+  procedure g_Touch_HandleEvent(const ev: TSDL_TouchFingerEvent);
+    var
+      x, y, i, finger: Integer;
+
+    procedure KeyUp (finger, i: Integer);
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: g_touch.KeyUp, finger=%s, key=%s', [finger, i]);
+
+      keyFinger[i] := 0;
+      e_KeyUpDown(i, False);
+      g_Console_ProcessBind(i, False);
+
+      (* up/down + fire hack *)
+      if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) and angleFire then
+      begin
+        if (i = VK_UP) or (i = VK_DOWN) then
+        begin
+          angleFire := False;
+          keyFinger[VK_FIRE] := 0;
+          e_KeyUpDown(VK_FIRE, False);
+          g_Console_ProcessBind(VK_FIRE, False)
+        end
+      end
+    end;
+
+    procedure KeyDown (finger, i: Integer);
+    begin
+      if g_dbg_input then
+        e_LogWritefln('Input Debug: g_touch.KeyDown, finger=%s, key=%s', [finger, i]);
+
+      keyFinger[i] := finger;
+      e_KeyUpDown(i, True);
+      g_Console_ProcessBind(i, True);
+
+      (* up/down + fire hack *)
+      if g_touch_fire and (gGameSettings.GameType <> GT_NONE) and (g_ActiveWindow = nil) then
+      begin
+        if i = VK_UP then
+        begin
+          angleFire := True;
+          keyFinger[VK_FIRE] := -1;
+          e_KeyUpDown(VK_FIRE, True);
+          g_Console_ProcessBind(VK_FIRE, True)
+        end
+        else if i = VK_DOWN then
+        begin
+          angleFire := True;
+          keyFinger[VK_FIRE] := -1;
+          e_KeyUpDown(VK_FIRE, True);
+          g_Console_ProcessBind(VK_FIRE, True)
+        end
+      end
+    end;
+
+    procedure KeyMotion (finger, i: Integer);
+    begin
+      if keyFinger[i] <> finger then
+      begin
+        KeyUp(finger, i);
+        KeyDown(finger, i)
+      end
+    end;
+
+  begin
+    if not g_touch_enabled then
+      Exit;
+
+    finger := ev.fingerId + 2;
+    x := Trunc(ev.x * gScreenWidth);
+    y := Trunc(ev.y * gScreenHeight);
+
+    for i := VK_FIRSTKEY to VK_LASTKEY do
+    begin
+      if IntersectControl(i, x, y) then
+      begin
+        if ev.type_ = SDL_FINGERUP then
+          KeyUp(finger, i)
+        else if ev.type_ = SDL_FINGERMOTION then
+          KeyMotion(finger, i)
+        else if ev.type_ = SDL_FINGERDOWN then
+          keyDown(finger, i)
+      end
+      else if keyFinger[i] = finger then
+      begin
+        if ev.type_ = SDL_FINGERUP then
+          KeyUp(finger, i)
+        else if ev.type_ = SDL_FINGERMOTION then
+          KeyUp(finger, i)
+      end
+    end
+  end;
+
+  procedure g_Touch_Draw;
+    var i, x, y, w, h: Integer; founded: Boolean;
+  begin
+{$IFNDEF HEADLESS}
+    if not g_touch_enabled then
+      Exit;
+
+    for i := VK_FIRSTKEY to VK_LASTKEY do
+    begin
+      GetKeyRect(i, x, y, w, h, founded);
+      if founded then
+      begin
+        e_DrawQuad(x, y, x + w, y + h, 0, 255, 0, 31);
+        e_TextureFontPrintEx(x, y, GetKeyName(i), gStdFont, 255, 255, 255, 1, True)
+      end
+    end
+{$ENDIF}
+  end;
+
+initialization
+  conRegVar('touch_enable', @g_touch_enabled, 'enable/disable virtual buttons', 'draw buttons');
+  conRegVar('touch_fire', @g_touch_fire, 'enable/disable fire when press virtual up/down', 'fire when press up/down');
+  conRegVar('touch_size', @g_touch_size, 0.1, 10, 'size of virtual buttons', 'button size');
+  conRegVar('touch_offset', @g_touch_offset, 0, 100, '', '');
+  conRegVar('touch_alt', @g_touch_alt, 'althernative virtual buttons layout', 'althernative layout');
+end.
index 84ae12138b5de86079efd98c67a04f8056169049..4e9fcedc40989b2414655f8572f1881a5daeacbf 100644 (file)
@@ -62,12 +62,12 @@ implementation
 
   function sys_GetDispalyModes (bpp: Integer): SSArray;
   begin
-    SetLength(result, 0);
+    result := nil
   end;
 
   function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
   begin
-    result := True
+    result := true
   end;
 
   (* --------- Input --------- *)