DEADSOFTWARE

implement SDL1.2 system driver
authorDeaDDooMER <deaddoomer@deadsoftware.ru>
Sat, 5 Oct 2019 22:43:33 +0000 (01:43 +0300)
committerDeaDDooMER <deaddoomer@deadsoftware.ru>
Sun, 13 Oct 2019 14:19:20 +0000 (17:19 +0300)
23 files changed:
src/engine/e_graphics.pas
src/engine/e_input.pas
src/engine/e_input_sdl2.inc [new file with mode: 0644]
src/engine/e_input_stub.inc [new file with mode: 0644]
src/engine/e_sound_al.inc
src/engine/e_sound_sdl.inc
src/engine/e_soundfile_wav.pas
src/game/Doom2DF.lpr
src/game/g_basic.pas
src/game/g_console.pas
src/game/g_game.pas
src/game/g_main.pas
src/game/g_menu.pas
src/game/g_net.pas
src/game/g_netmaster.pas
src/game/g_options.pas
src/game/g_touch.pas [deleted file]
src/game/g_window.pas
src/game/sdl/g_system.pas [new file with mode: 0644]
src/game/sdl/g_touch.pas [new file with mode: 0644]
src/game/stub/g_system.pas [new file with mode: 0644]
src/game/stub/g_touch.pas [new file with mode: 0644]
src/shared/xprofiler.pas

index c46e8ec4600bfd8729fc1f75e06740507aed10bb..6f1df29b44ae447aaf587fcf4bf8f4362aa86dd3 100644 (file)
@@ -19,7 +19,11 @@ interface
 
 uses
   {$INCLUDE ../nogl/noGLuses.inc}
-  SysUtils, Classes, Math, e_log, e_texture, SDL2, MAPDEF, ImagingTypes, Imaging, ImagingUtility;
+  {$IFDEF USE_SDL2}
+    SDL2,
+  {$ENDIF}
+  SysUtils, Classes, Math, e_log, e_texture,
+  MAPDEF, ImagingTypes, Imaging, ImagingUtility;
 
 type
   TMirrorType=(None, Horizontal, Vertical);
@@ -128,8 +132,10 @@ procedure e_Clear(Mask: TGLbitfield; Red, Green, Blue: Single); overload;
 procedure e_Clear(); overload;
 procedure e_EndRender();
 
+{$IFDEF USE_SDL2}
 function e_GetGamma(win: PSDL_Window): Byte;
 procedure e_SetGamma(win: PSDL_Window;Gamma: Byte);
+{$ENDIF}
 
 procedure e_MakeScreenshot(st: TStream; Width, Height: Word);
 
@@ -1113,6 +1119,7 @@ begin
   glPopMatrix();
 end;
 
+{$IFDEF USE_SDL2}
 function e_GetGamma(win: PSDL_Window): Byte;
 var
   ramp: array [0..256*3-1] of Word;
@@ -1175,6 +1182,7 @@ begin
 
  SDL_SetWindowGammaRamp(win, @ramp[0], @ramp[256], @ramp[512]);
 end;
+{$ENDIF}
 
 function e_CharFont_Create(sp: ShortInt=0): DWORD;
 var
index 1bfd7f33407db727a8dd87c4848a392f09c64e74..e7fa6cb0df5bc9091c818170377dbd1470cb7287 100644 (file)
 {$INCLUDE ../shared/a_modes.inc}
 unit e_input;
 
-interface
-
-uses SysUtils, SDL2;
-
-const
-  e_MaxKbdKeys  = SDL_NUM_SCANCODES;
-  e_MaxJoys     = 4;
-  e_MaxJoyBtns  = 32;
-  e_MaxJoyAxes  = 8;
-  e_MaxJoyHats  = 8;
-  e_MaxVirtKeys = 48;
-
-  e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
-
-  e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
-  // $$$..$$$ -  321 Keyboard buttons/keys
-  // $$$..$$$ - 4*32 Joystick buttons
-  // $$$..$$$ -  8*2 Joystick axes (- and +)
-  // $$$..$$$ -  4*4 Joystick hats (L U R D)
-  // $$$..$$$ -   48 Virtual buttons/keys
-
-  KBRD_END = e_MaxKbdKeys;
-  JOYK_BEG = KBRD_END;
-  JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
-  JOYA_BEG = JOYK_END;
-  JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
-  JOYH_BEG = JOYA_END;
-  JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
-  VIRT_BEG = JOYH_END;
-  VIRT_END = VIRT_BEG + e_MaxVirtKeys;
-
-  // these are apparently used in g_gui and g_game and elsewhere
-  IK_INVALID = 0;
-  IK_ESCAPE  = SDL_SCANCODE_ESCAPE;
-  IK_RETURN  = SDL_SCANCODE_RETURN;
-  IK_KPRETURN= SDL_SCANCODE_KP_ENTER;
-  IK_ENTER   = SDL_SCANCODE_RETURN;
-  IK_KPINSERT = SDL_SCANCODE_KP_0;
-  IK_UP      = SDL_SCANCODE_UP;
-  IK_KPUP    = SDL_SCANCODE_KP_8;
-  IK_DOWN    = SDL_SCANCODE_DOWN;
-  IK_KPDOWN  = SDL_SCANCODE_KP_2;
-  IK_LEFT    = SDL_SCANCODE_LEFT;
-  IK_KPLEFT  = SDL_SCANCODE_KP_4;
-  IK_RIGHT   = SDL_SCANCODE_RIGHT;
-  IK_KPRIGHT = SDL_SCANCODE_KP_6;
-  IK_DELETE  = SDL_SCANCODE_DELETE;
-  IK_HOME    = SDL_SCANCODE_HOME;
-  IK_KPHOME  = SDL_SCANCODE_KP_7;
-  IK_INSERT  = SDL_SCANCODE_INSERT;
-  IK_SPACE   = SDL_SCANCODE_SPACE;
-  IK_CONTROL = SDL_SCANCODE_LCTRL;
-  IK_SHIFT   = SDL_SCANCODE_LSHIFT;
-  IK_ALT     = SDL_SCANCODE_LALT;
-  IK_TAB     = SDL_SCANCODE_TAB;
-  IK_PAGEUP  = SDL_SCANCODE_PAGEUP;
-  IK_KPPAGEUP= SDL_SCANCODE_KP_9;
-  IK_PAGEDN  = SDL_SCANCODE_PAGEDOWN;
-  IK_KPPAGEDN= SDL_SCANCODE_KP_3;
-  IK_KP5     = SDL_SCANCODE_KP_5;
-  IK_NUMLOCK = SDL_SCANCODE_NUMLOCKCLEAR;
-  IK_KPDIVIDE= SDL_SCANCODE_KP_DIVIDE;
-  IK_KPMULTIPLE= SDL_SCANCODE_KP_MULTIPLY;
-  IK_KPMINUS = SDL_SCANCODE_KP_MINUS;
-  IK_KPPLUS  = SDL_SCANCODE_KP_PLUS;
-  IK_KPENTER = SDL_SCANCODE_KP_ENTER;
-  IK_KPDOT   = SDL_SCANCODE_KP_PERIOD;
-  IK_CAPSLOCK= SDL_SCANCODE_CAPSLOCK;
-  IK_RSHIFT  = SDL_SCANCODE_RSHIFT;
-  IK_CTRL    = SDL_SCANCODE_LCTRL;
-  IK_RCTRL   = SDL_SCANCODE_RCTRL;
-  IK_RALT    = SDL_SCANCODE_RALT;
-  IK_WIN     = SDL_SCANCODE_LGUI;
-  IK_RWIN    = SDL_SCANCODE_RGUI;
-  IK_MENU    = SDL_SCANCODE_MENU;
-  IK_PRINTSCR= SDL_SCANCODE_PRINTSCREEN;
-  IK_SCROLLLOCK= SDL_SCANCODE_SCROLLLOCK;
-  IK_LBRACKET= SDL_SCANCODE_LEFTBRACKET;
-  IK_RBRACKET= SDL_SCANCODE_RIGHTBRACKET;
-  IK_SEMICOLON= SDL_SCANCODE_SEMICOLON;
-  IK_QUOTE   = SDL_SCANCODE_APOSTROPHE;
-  IK_BACKSLASH= SDL_SCANCODE_BACKSLASH;
-  IK_SLASH   = SDL_SCANCODE_SLASH;
-  IK_COMMA   = SDL_SCANCODE_COMMA;
-  IK_DOT     = SDL_SCANCODE_PERIOD;
-  IK_EQUALS  = SDL_SCANCODE_EQUALS;
-  IK_0      = SDL_SCANCODE_0;
-  IK_1      = SDL_SCANCODE_1;
-  IK_2      = SDL_SCANCODE_2;
-  IK_3      = SDL_SCANCODE_3;
-  IK_4      = SDL_SCANCODE_4;
-  IK_5      = SDL_SCANCODE_5;
-  IK_6      = SDL_SCANCODE_6;
-  IK_7      = SDL_SCANCODE_7;
-  IK_8      = SDL_SCANCODE_8;
-  IK_9      = SDL_SCANCODE_9;
-  IK_F1      = SDL_SCANCODE_F1;
-  IK_F2      = SDL_SCANCODE_F2;
-  IK_F3      = SDL_SCANCODE_F3;
-  IK_F4      = SDL_SCANCODE_F4;
-  IK_F5      = SDL_SCANCODE_F5;
-  IK_F6      = SDL_SCANCODE_F6;
-  IK_F7      = SDL_SCANCODE_F7;
-  IK_F8      = SDL_SCANCODE_F8;
-  IK_F9      = SDL_SCANCODE_F9;
-  IK_F10     = SDL_SCANCODE_F10;
-  IK_F11     = SDL_SCANCODE_F11;
-  IK_F12     = SDL_SCANCODE_F12;
-  IK_END     = SDL_SCANCODE_END;
-  IK_KPEND   = SDL_SCANCODE_KP_1;
-  IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
-  IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
-  IK_GRAVE     = SDL_SCANCODE_GRAVE;
-  IK_PAUSE   = SDL_SCANCODE_PAUSE;
-  IK_Y       = SDL_SCANCODE_Y;
-  IK_N       = SDL_SCANCODE_N;
-  IK_W       = SDL_SCANCODE_W;
-  IK_A       = SDL_SCANCODE_A;
-  IK_S       = SDL_SCANCODE_S;
-  IK_D       = SDL_SCANCODE_D;
-  IK_Q       = SDL_SCANCODE_Q;
-  IK_E       = SDL_SCANCODE_E;
-  IK_H       = SDL_SCANCODE_H;
-  IK_J       = SDL_SCANCODE_J;
-  IK_T       = SDL_SCANCODE_T;
-  IK_Z       = SDL_SCANCODE_Z;
-  IK_MINUS   = SDL_SCANCODE_MINUS;
-  // TODO: think of something better than this shit
-  IK_LASTKEY = SDL_NUM_SCANCODES-1;
-
-  VK_FIRSTKEY = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys;
-  VK_LEFT     = VK_FIRSTKEY + 0;
-  VK_RIGHT    = VK_FIRSTKEY + 1;
-  VK_UP       = VK_FIRSTKEY + 2;
-  VK_DOWN     = VK_FIRSTKEY + 3;
-  VK_FIRE     = VK_FIRSTKEY + 4;
-  VK_OPEN     = VK_FIRSTKEY + 5;
-  VK_JUMP     = VK_FIRSTKEY + 6;
-  VK_CHAT     = VK_FIRSTKEY + 7;
-  VK_ESCAPE   = VK_FIRSTKEY + 8;
-  VK_0        = VK_FIRSTKEY + 9;
-  VK_1        = VK_FIRSTKEY + 10;
-  VK_2        = VK_FIRSTKEY + 11;
-  VK_3        = VK_FIRSTKEY + 12;
-  VK_4        = VK_FIRSTKEY + 13;
-  VK_5        = VK_FIRSTKEY + 14;
-  VK_6        = VK_FIRSTKEY + 15;
-  VK_7        = VK_FIRSTKEY + 16;
-  VK_8        = VK_FIRSTKEY + 17;
-  VK_9        = VK_FIRSTKEY + 18;
-  VK_A        = VK_FIRSTKEY + 19;
-  VK_B        = VK_FIRSTKEY + 20;
-  VK_C        = VK_FIRSTKEY + 21;
-  VK_D        = VK_FIRSTKEY + 22;
-  VK_E        = VK_FIRSTKEY + 23;
-  VK_F        = VK_FIRSTKEY + 24;
-  VK_CONSOLE  = VK_FIRSTKEY + 25;
-  VK_STATUS   = VK_FIRSTKEY + 26;
-  VK_TEAM     = VK_FIRSTKEY + 27;
-  VK_PREV     = VK_FIRSTKEY + 28;
-  VK_NEXT     = VK_FIRSTKEY + 29;
-  VK_STRAFE   = VK_FIRSTKEY + 30;
-  VK_LSTRAFE  = VK_FIRSTKEY + 31;
-  VK_RSTRAFE  = VK_FIRSTKEY + 32;
-  VK_PRINTSCR = VK_FIRSTKEY + 33;
-  VK_SHOWKBD  = VK_FIRSTKEY + 34;
-  VK_HIDEKBD  = VK_FIRSTKEY + 35;
-  VK_LASTKEY  = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
-
-  AX_MINUS  = 0;
-  AX_PLUS   = 1;
-  HAT_LEFT  = 0;
-  HAT_UP    = 1;
-  HAT_RIGHT = 2;
-  HAT_DOWN  = 3;
-
-  JOY0_ATTACK = JOYK_BEG + 0*e_MaxJoyBtns + 0;
-  JOY1_ATTACK = JOYK_BEG + 1*e_MaxJoyBtns + 0;
-  JOY2_ATTACK = JOYK_BEG + 2*e_MaxJoyBtns + 0;
-  JOY3_ATTACK = JOYK_BEG + 3*e_MaxJoyBtns + 0;
-  JOY0_NEXT = JOYK_BEG + 0*e_MaxJoyBtns + 1;
-  JOY1_NEXT = JOYK_BEG + 1*e_MaxJoyBtns + 1;
-  JOY2_NEXT = JOYK_BEG + 2*e_MaxJoyBtns + 1;
-  JOY3_NEXT = JOYK_BEG + 3*e_MaxJoyBtns + 1;
-  JOY0_JUMP = JOYK_BEG + 0*e_MaxJoyBtns + 2;
-  JOY1_JUMP = JOYK_BEG + 1*e_MaxJoyBtns + 2;
-  JOY2_JUMP = JOYK_BEG + 2*e_MaxJoyBtns + 2;
-  JOY3_JUMP = JOYK_BEG + 3*e_MaxJoyBtns + 2;
-  JOY0_ACTIVATE = JOYK_BEG + 0*e_MaxJoyBtns + 3;
-  JOY1_ACTIVATE = JOYK_BEG + 1*e_MaxJoyBtns + 3;
-  JOY2_ACTIVATE = JOYK_BEG + 2*e_MaxJoyBtns + 3;
-  JOY3_ACTIVATE = JOYK_BEG + 3*e_MaxJoyBtns + 3;
-  JOY0_PREV = JOYK_BEG + 0*e_MaxJoyBtns + 4;
-  JOY1_PREV = JOYK_BEG + 1*e_MaxJoyBtns + 4;
-  JOY2_PREV = JOYK_BEG + 2*e_MaxJoyBtns + 4;
-  JOY3_PREV = JOYK_BEG + 3*e_MaxJoyBtns + 4;
-
-  JOY0_LEFT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
-  JOY1_LEFT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
-  JOY2_LEFT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
-  JOY3_LEFT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
-  JOY0_RIGHT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
-  JOY1_RIGHT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
-  JOY2_RIGHT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
-  JOY3_RIGHT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
-  JOY0_UP = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_UP;
-  JOY1_UP = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_UP;
-  JOY2_UP = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_UP;
-  JOY3_UP = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_UP;
-  JOY0_DOWN = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
-  JOY1_DOWN = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
-  JOY2_DOWN = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
-  JOY3_DOWN = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
-
-function  e_InitInput: Boolean;
-procedure e_ReleaseInput;
-procedure e_UnpressAllKeys;
-procedure e_KeyUpDown (key: Integer; down: Boolean);
-
-function  e_KeyPressed (key: Integer): Boolean;
-function  e_AnyKeyPressed: Boolean;
-function  e_GetFirstKeyPressed: Integer;
-function  e_HasJoysticks: Boolean;
-
-function  e_JoyButtonToKey (id, btn: Integer): Integer;
-function  e_JoyAxisToKey (id, ax, dir: Integer): Integer;
-function  e_JoyHatToKey (id, hat, dir: Integer): Integer;
-
-var
-  e_JoystickAvailable: array [0..e_MaxJoys - 1] of Boolean;
-  e_JoystickDeadzones: array [0..e_MaxJoys - 1] of Integer = (8192, 8192, 8192, 8192);
-  e_KeyNames: array [0..e_MaxInputKeys] of String;
-
-implementation
-
-var
-  InputBuffer: array [0..e_MaxInputKeys - 1] of Boolean;
-
-procedure e_UnpressAllKeys;
-  var i: Integer;
-begin
-  for i := 0 to High(InputBuffer) do
-    InputBuffer[i] := False
-end;
-
-procedure e_KeyUpDown (key: Integer; down: Boolean);
-begin
-  ASSERT(key >= 0);
-  ASSERT(key < e_MaxInputKeys);
-  if key > 0 then
-    InputBuffer[key] := down
-end;
-
-procedure GenerateKeyNames;
-  var i, j, k: Integer;
-begin
-  // keyboard key names
-  e_KeyNames[IK_0] := '0';
-  e_KeyNames[IK_1] := '1';
-  e_KeyNames[IK_2] := '2';
-  e_KeyNames[IK_3] := '3';
-  e_KeyNames[IK_4] := '4';
-  e_KeyNames[IK_5] := '5';
-  e_KeyNames[IK_6] := '6';
-  e_KeyNames[IK_7] := '7';
-  e_KeyNames[IK_8] := '8';
-  e_KeyNames[IK_9] := '9';
-
-  for i := IK_A to IK_Z do
-    e_KeyNames[i] := '' + chr(ord('a') + (i - IK_a));
-
-  e_KeyNames[IK_ESCAPE] := 'ESCAPE';
-  e_KeyNames[IK_ENTER] := 'ENTER';
-  e_KeyNames[IK_TAB] := 'TAB';
-  e_KeyNames[IK_BACKSPACE] := 'BACKSPACE';
-  e_KeyNames[IK_SPACE] := 'SPACE';
-  e_KeyNames[IK_UP] := 'UP';
-  e_KeyNames[IK_LEFT] := 'LEFT';
-  e_KeyNames[IK_RIGHT] := 'RIGHT';
-  e_KeyNames[IK_DOWN] := 'DOWN';
-  e_KeyNames[IK_INSERT] := 'INSERT';
-  e_KeyNames[IK_DELETE] := 'DELETE';
-  e_KeyNames[IK_HOME] := 'HOME';
-  e_KeyNames[IK_END] := 'END';
-  e_KeyNames[IK_PAGEUP] := 'PGUP';
-  e_KeyNames[IK_PAGEDN] := 'PGDOWN';
-  e_KeyNames[IK_KPINSERT] := 'PAD0';
-  e_KeyNames[IK_KPEND] := 'PAD1';
-  e_KeyNames[IK_KPDOWN] := 'PAD2';
-  e_KeyNames[IK_KPPAGEDN] := 'PAD3';
-  e_KeyNames[IK_KPLEFT] := 'PAD4';
-  e_KeyNames[IK_KP5] := 'PAD5';
-  e_KeyNames[IK_KPRIGHT] := 'PAD6';
-  e_KeyNames[IK_KPHOME] := 'PAD7';
-  e_KeyNames[IK_KPUP] := 'PAD8';
-  e_KeyNames[IK_KPPAGEUP] := 'PAD9';
-  e_KeyNames[IK_NUMLOCK] := 'NUM';
-  e_KeyNames[IK_KPDIVIDE] := 'PAD/';
-  e_KeyNames[IK_KPMULTIPLE] := 'PAD*';
-  e_KeyNames[IK_KPMINUS] := 'PAD-';
-  e_KeyNames[IK_KPPLUS] := 'PAD+';
-  e_KeyNames[IK_KPENTER] := 'PADENTER';
-  e_KeyNames[IK_KPDOT] := 'PAD.';
-  e_KeyNames[IK_CAPSLOCK] := 'CAPS';
-  e_KeyNames[IK_BACKQUOTE] := 'BACKQUOTE';
-  e_KeyNames[IK_F1] := 'F1';
-  e_KeyNames[IK_F2] := 'F2';
-  e_KeyNames[IK_F3] := 'F3';
-  e_KeyNames[IK_F4] := 'F4';
-  e_KeyNames[IK_F5] := 'F5';
-  e_KeyNames[IK_F6] := 'F6';
-  e_KeyNames[IK_F7] := 'F7';
-  e_KeyNames[IK_F8] := 'F8';
-  e_KeyNames[IK_F9] := 'F9';
-  e_KeyNames[IK_F10] := 'F10';
-  e_KeyNames[IK_F11] := 'F11';
-  e_KeyNames[IK_F12] := 'F12';
-  e_KeyNames[IK_SHIFT] := 'LSHIFT';
-  e_KeyNames[IK_RSHIFT] := 'RSHIFT';
-  e_KeyNames[IK_CTRL] := 'LCTRL';
-  e_KeyNames[IK_RCTRL] := 'RCTRL';
-  e_KeyNames[IK_ALT] := 'LALT';
-  e_KeyNames[IK_RALT] := 'RALT';
-  e_KeyNames[IK_WIN] := 'LWIN';
-  e_KeyNames[IK_RWIN] := 'RWIN';
-  e_KeyNames[IK_MENU] := 'MENU';
-  e_KeyNames[IK_PRINTSCR] := 'PSCRN';
-  e_KeyNames[IK_SCROLLLOCK] := 'SCROLL';
-  e_KeyNames[IK_PAUSE] := 'PAUSE';
-  e_KeyNames[IK_LBRACKET] := '[';
-  e_KeyNames[IK_RBRACKET] := ']';
-  e_KeyNames[IK_SEMICOLON] := ';';
-  e_KeyNames[IK_QUOTE] := '''';
-  e_KeyNames[IK_BACKSLASH] := '\';
-  e_KeyNames[IK_SLASH] := '/';
-  e_KeyNames[IK_COMMA] := ',';
-  e_KeyNames[IK_DOT] := '.';
-  e_KeyNames[IK_MINUS] := '-';
-  e_KeyNames[IK_EQUALS] := '=';
-
-  // joysticks
-  for j := 0 to e_MaxJoys-1 do
-  begin
-    k := JOYK_BEG + j * e_MaxJoyBtns;
-    // buttons
-    for i := 0 to e_MaxJoyBtns-1 do
-      e_KeyNames[k + i] := Format('JOY%dB%d', [j, i]);
-    k := JOYA_BEG + j * e_MaxJoyAxes * 2;
-    // axes
-    for i := 0 to e_MaxJoyAxes-1 do
-    begin
-      e_KeyNames[k + i*2    ] := Format('JOY%dA%d+', [j, i]);
-      e_KeyNames[k + i*2 + 1] := Format('JOY%dA%d-', [j, i]);
-    end;
-    k := JOYH_BEG + j * e_MaxJoyHats * 4;
-    // hats
-    for i := 0 to e_MaxJoyHats-1 do
-    begin
-      e_KeyNames[k + i*4    ] := Format('JOY%dD%dL', [j, i]);
-      e_KeyNames[k + i*4 + 1] := Format('JOY%dD%dU', [j, i]);
-      e_KeyNames[k + i*4 + 2] := Format('JOY%dD%dR', [j, i]);
-      e_KeyNames[k + i*4 + 3] := Format('JOY%dD%dD', [j, i]);
-    end;
-  end;
-
-  // vitrual keys
-  for i := 0 to e_MaxVirtKeys-1 do
-    e_KeyNames[VIRT_BEG + i] := 'VIRTUAL' + IntToStr(i);
-end;
-
-function e_HasJoysticks: Boolean;
-  var i: Integer;
-begin
-  i := 0;
-  while (i < e_MaxJoys) and (e_JoystickAvailable[i] = False) do inc(i);
-  result := i < e_MaxJoys
-end;
-
-function e_InitInput: Boolean;
-  var i: Integer;
-begin
-  for i := 0 to e_MaxJoys - 1 do
-    e_JoystickAvailable[i] := False;
-  GenerateKeyNames;
-  result := True
-end;
-
-procedure e_ReleaseInput;
-  var i: Integer;
-begin
-  for i := 0 to e_MaxJoys - 1 do
-    e_JoystickAvailable[i] := False
-end;
-
-function e_KeyPressed (key: Integer): Boolean;
-begin
-  ASSERT(key >= 0);
-  ASSERT(key < e_MaxInputKeys);
-  result := InputBuffer[key]
-end;
-
-function e_AnyKeyPressed: Boolean;
-begin
-  result := e_GetFirstKeyPressed <> IK_INVALID;
-end;
-
-function e_GetFirstKeyPressed: Integer;
-  var i: Integer;
-begin
-  i := 1;
-  while (i < e_MaxInputKeys) and (InputBuffer[i] = False) do inc(i);
-  if i < e_MaxInputKeys then
-    result := i
-  else
-    result := IK_INVALID
-end;
-
-function e_JoyButtonToKey (id, btn: Integer): Integer;
-begin
-  ASSERT(id >= 0);
-  ASSERT(id < e_MaxJoys);
-  ASSERT(btn >= 0);
-  ASSERT(btn < e_MaxJoyBtns);
-  result := JOYK_BEG + id*e_MaxJoyBtns + btn
-end;
-
-function e_JoyAxisToKey (id, ax, dir: Integer): Integer;
-begin
-  ASSERT(id >= 0);
-  ASSERT(id < e_MaxJoys);
-  ASSERT(ax >= 0);
-  ASSERT(ax < e_MaxJoyAxes);
-  ASSERT(dir in [AX_MINUS, AX_PLUS]);
-  result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir
-end;
-
-function e_JoyHatToKey (id, hat, dir: Integer): Integer;
-begin
-  ASSERT(id >= 0);
-  ASSERT(id < e_MaxJoys);
-  ASSERT(hat >= 0);
-  ASSERT(hat < e_MaxJoyHats);
-  ASSERT(dir in [HAT_LEFT, HAT_UP, HAT_RIGHT, HAT_DOWN]);
-  result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir
-end;
+{$IF DEFINED(USE_SYSSTUB) OR DEFINED(USE_SDL)}
+  {$I e_input_stub.inc}
+{$ELSEIF DEFINED(USE_SDL2)}
+  {$I e_input_sdl2.inc}
+{$ELSE}
+  {$ERROR e_input driver not implemented?}
+{$ENDIF}
 
 end.
diff --git a/src/engine/e_input_sdl2.inc b/src/engine/e_input_sdl2.inc
new file mode 100644 (file)
index 0000000..d619c51
--- /dev/null
@@ -0,0 +1,446 @@
+interface
+
+uses
+  SDL2, SysUtils;
+
+const
+  e_MaxKbdKeys  = SDL_NUM_SCANCODES;
+  e_MaxJoys     = 4;
+  e_MaxJoyBtns  = 32;
+  e_MaxJoyAxes  = 8;
+  e_MaxJoyHats  = 8;
+  e_MaxVirtKeys = 48;
+
+  e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
+
+  e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
+  // $$$..$$$ -  321 Keyboard buttons/keys
+  // $$$..$$$ - 4*32 Joystick buttons
+  // $$$..$$$ -  8*2 Joystick axes (- and +)
+  // $$$..$$$ -  4*4 Joystick hats (L U R D)
+  // $$$..$$$ -   48 Virtual buttons/keys
+
+  KBRD_END = e_MaxKbdKeys;
+  JOYK_BEG = KBRD_END;
+  JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
+  JOYA_BEG = JOYK_END;
+  JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
+  JOYH_BEG = JOYA_END;
+  JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
+  VIRT_BEG = JOYH_END;
+  VIRT_END = VIRT_BEG + e_MaxVirtKeys;
+
+  // these are apparently used in g_gui and g_game and elsewhere
+  IK_INVALID = 0;
+  IK_ESCAPE  = SDL_SCANCODE_ESCAPE;
+  IK_RETURN  = SDL_SCANCODE_RETURN;
+  IK_KPRETURN= SDL_SCANCODE_KP_ENTER;
+  IK_ENTER   = SDL_SCANCODE_RETURN;
+  IK_KPINSERT = SDL_SCANCODE_KP_0;
+  IK_UP      = SDL_SCANCODE_UP;
+  IK_KPUP    = SDL_SCANCODE_KP_8;
+  IK_DOWN    = SDL_SCANCODE_DOWN;
+  IK_KPDOWN  = SDL_SCANCODE_KP_2;
+  IK_LEFT    = SDL_SCANCODE_LEFT;
+  IK_KPLEFT  = SDL_SCANCODE_KP_4;
+  IK_RIGHT   = SDL_SCANCODE_RIGHT;
+  IK_KPRIGHT = SDL_SCANCODE_KP_6;
+  IK_DELETE  = SDL_SCANCODE_DELETE;
+  IK_HOME    = SDL_SCANCODE_HOME;
+  IK_KPHOME  = SDL_SCANCODE_KP_7;
+  IK_INSERT  = SDL_SCANCODE_INSERT;
+  IK_SPACE   = SDL_SCANCODE_SPACE;
+  IK_CONTROL = SDL_SCANCODE_LCTRL;
+  IK_SHIFT   = SDL_SCANCODE_LSHIFT;
+  IK_ALT     = SDL_SCANCODE_LALT;
+  IK_TAB     = SDL_SCANCODE_TAB;
+  IK_PAGEUP  = SDL_SCANCODE_PAGEUP;
+  IK_KPPAGEUP= SDL_SCANCODE_KP_9;
+  IK_PAGEDN  = SDL_SCANCODE_PAGEDOWN;
+  IK_KPPAGEDN= SDL_SCANCODE_KP_3;
+  IK_KP5     = SDL_SCANCODE_KP_5;
+  IK_NUMLOCK = SDL_SCANCODE_NUMLOCKCLEAR;
+  IK_KPDIVIDE= SDL_SCANCODE_KP_DIVIDE;
+  IK_KPMULTIPLE= SDL_SCANCODE_KP_MULTIPLY;
+  IK_KPMINUS = SDL_SCANCODE_KP_MINUS;
+  IK_KPPLUS  = SDL_SCANCODE_KP_PLUS;
+  IK_KPENTER = SDL_SCANCODE_KP_ENTER;
+  IK_KPDOT   = SDL_SCANCODE_KP_PERIOD;
+  IK_CAPSLOCK= SDL_SCANCODE_CAPSLOCK;
+  IK_RSHIFT  = SDL_SCANCODE_RSHIFT;
+  IK_CTRL    = SDL_SCANCODE_LCTRL;
+  IK_RCTRL   = SDL_SCANCODE_RCTRL;
+  IK_RALT    = SDL_SCANCODE_RALT;
+  IK_WIN     = SDL_SCANCODE_LGUI;
+  IK_RWIN    = SDL_SCANCODE_RGUI;
+  IK_MENU    = SDL_SCANCODE_MENU;
+  IK_PRINTSCR= SDL_SCANCODE_PRINTSCREEN;
+  IK_SCROLLLOCK= SDL_SCANCODE_SCROLLLOCK;
+  IK_LBRACKET= SDL_SCANCODE_LEFTBRACKET;
+  IK_RBRACKET= SDL_SCANCODE_RIGHTBRACKET;
+  IK_SEMICOLON= SDL_SCANCODE_SEMICOLON;
+  IK_QUOTE   = SDL_SCANCODE_APOSTROPHE;
+  IK_BACKSLASH= SDL_SCANCODE_BACKSLASH;
+  IK_SLASH   = SDL_SCANCODE_SLASH;
+  IK_COMMA   = SDL_SCANCODE_COMMA;
+  IK_DOT     = SDL_SCANCODE_PERIOD;
+  IK_EQUALS  = SDL_SCANCODE_EQUALS;
+  IK_0      = SDL_SCANCODE_0;
+  IK_1      = SDL_SCANCODE_1;
+  IK_2      = SDL_SCANCODE_2;
+  IK_3      = SDL_SCANCODE_3;
+  IK_4      = SDL_SCANCODE_4;
+  IK_5      = SDL_SCANCODE_5;
+  IK_6      = SDL_SCANCODE_6;
+  IK_7      = SDL_SCANCODE_7;
+  IK_8      = SDL_SCANCODE_8;
+  IK_9      = SDL_SCANCODE_9;
+  IK_F1      = SDL_SCANCODE_F1;
+  IK_F2      = SDL_SCANCODE_F2;
+  IK_F3      = SDL_SCANCODE_F3;
+  IK_F4      = SDL_SCANCODE_F4;
+  IK_F5      = SDL_SCANCODE_F5;
+  IK_F6      = SDL_SCANCODE_F6;
+  IK_F7      = SDL_SCANCODE_F7;
+  IK_F8      = SDL_SCANCODE_F8;
+  IK_F9      = SDL_SCANCODE_F9;
+  IK_F10     = SDL_SCANCODE_F10;
+  IK_F11     = SDL_SCANCODE_F11;
+  IK_F12     = SDL_SCANCODE_F12;
+  IK_END     = SDL_SCANCODE_END;
+  IK_KPEND   = SDL_SCANCODE_KP_1;
+  IK_BACKSPACE = SDL_SCANCODE_BACKSPACE;
+  IK_BACKQUOTE = SDL_SCANCODE_GRAVE;
+  IK_GRAVE     = SDL_SCANCODE_GRAVE;
+  IK_PAUSE   = SDL_SCANCODE_PAUSE;
+  IK_Y       = SDL_SCANCODE_Y;
+  IK_N       = SDL_SCANCODE_N;
+  IK_W       = SDL_SCANCODE_W;
+  IK_A       = SDL_SCANCODE_A;
+  IK_S       = SDL_SCANCODE_S;
+  IK_D       = SDL_SCANCODE_D;
+  IK_Q       = SDL_SCANCODE_Q;
+  IK_E       = SDL_SCANCODE_E;
+  IK_H       = SDL_SCANCODE_H;
+  IK_J       = SDL_SCANCODE_J;
+  IK_T       = SDL_SCANCODE_T;
+  IK_Z       = SDL_SCANCODE_Z;
+  IK_MINUS   = SDL_SCANCODE_MINUS;
+  // TODO: think of something better than this shit
+  IK_LASTKEY = SDL_NUM_SCANCODES-1;
+
+  VK_FIRSTKEY = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys;
+  VK_LEFT     = VK_FIRSTKEY + 0;
+  VK_RIGHT    = VK_FIRSTKEY + 1;
+  VK_UP       = VK_FIRSTKEY + 2;
+  VK_DOWN     = VK_FIRSTKEY + 3;
+  VK_FIRE     = VK_FIRSTKEY + 4;
+  VK_OPEN     = VK_FIRSTKEY + 5;
+  VK_JUMP     = VK_FIRSTKEY + 6;
+  VK_CHAT     = VK_FIRSTKEY + 7;
+  VK_ESCAPE   = VK_FIRSTKEY + 8;
+  VK_0        = VK_FIRSTKEY + 9;
+  VK_1        = VK_FIRSTKEY + 10;
+  VK_2        = VK_FIRSTKEY + 11;
+  VK_3        = VK_FIRSTKEY + 12;
+  VK_4        = VK_FIRSTKEY + 13;
+  VK_5        = VK_FIRSTKEY + 14;
+  VK_6        = VK_FIRSTKEY + 15;
+  VK_7        = VK_FIRSTKEY + 16;
+  VK_8        = VK_FIRSTKEY + 17;
+  VK_9        = VK_FIRSTKEY + 18;
+  VK_A        = VK_FIRSTKEY + 19;
+  VK_B        = VK_FIRSTKEY + 20;
+  VK_C        = VK_FIRSTKEY + 21;
+  VK_D        = VK_FIRSTKEY + 22;
+  VK_E        = VK_FIRSTKEY + 23;
+  VK_F        = VK_FIRSTKEY + 24;
+  VK_CONSOLE  = VK_FIRSTKEY + 25;
+  VK_STATUS   = VK_FIRSTKEY + 26;
+  VK_TEAM     = VK_FIRSTKEY + 27;
+  VK_PREV     = VK_FIRSTKEY + 28;
+  VK_NEXT     = VK_FIRSTKEY + 29;
+  VK_STRAFE   = VK_FIRSTKEY + 30;
+  VK_LSTRAFE  = VK_FIRSTKEY + 31;
+  VK_RSTRAFE  = VK_FIRSTKEY + 32;
+  VK_PRINTSCR = VK_FIRSTKEY + 33;
+  VK_SHOWKBD  = VK_FIRSTKEY + 34;
+  VK_HIDEKBD  = VK_FIRSTKEY + 35;
+  VK_LASTKEY  = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
+
+  AX_MINUS  = 0;
+  AX_PLUS   = 1;
+  HAT_LEFT  = 0;
+  HAT_UP    = 1;
+  HAT_RIGHT = 2;
+  HAT_DOWN  = 3;
+
+  JOY0_ATTACK = JOYK_BEG + 0*e_MaxJoyBtns + 0;
+  JOY1_ATTACK = JOYK_BEG + 1*e_MaxJoyBtns + 0;
+  JOY2_ATTACK = JOYK_BEG + 2*e_MaxJoyBtns + 0;
+  JOY3_ATTACK = JOYK_BEG + 3*e_MaxJoyBtns + 0;
+  JOY0_NEXT = JOYK_BEG + 0*e_MaxJoyBtns + 1;
+  JOY1_NEXT = JOYK_BEG + 1*e_MaxJoyBtns + 1;
+  JOY2_NEXT = JOYK_BEG + 2*e_MaxJoyBtns + 1;
+  JOY3_NEXT = JOYK_BEG + 3*e_MaxJoyBtns + 1;
+  JOY0_JUMP = JOYK_BEG + 0*e_MaxJoyBtns + 2;
+  JOY1_JUMP = JOYK_BEG + 1*e_MaxJoyBtns + 2;
+  JOY2_JUMP = JOYK_BEG + 2*e_MaxJoyBtns + 2;
+  JOY3_JUMP = JOYK_BEG + 3*e_MaxJoyBtns + 2;
+  JOY0_ACTIVATE = JOYK_BEG + 0*e_MaxJoyBtns + 3;
+  JOY1_ACTIVATE = JOYK_BEG + 1*e_MaxJoyBtns + 3;
+  JOY2_ACTIVATE = JOYK_BEG + 2*e_MaxJoyBtns + 3;
+  JOY3_ACTIVATE = JOYK_BEG + 3*e_MaxJoyBtns + 3;
+  JOY0_PREV = JOYK_BEG + 0*e_MaxJoyBtns + 4;
+  JOY1_PREV = JOYK_BEG + 1*e_MaxJoyBtns + 4;
+  JOY2_PREV = JOYK_BEG + 2*e_MaxJoyBtns + 4;
+  JOY3_PREV = JOYK_BEG + 3*e_MaxJoyBtns + 4;
+
+  JOY0_LEFT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY1_LEFT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY2_LEFT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY3_LEFT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY0_RIGHT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY1_RIGHT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY2_RIGHT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY3_RIGHT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY0_UP = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY1_UP = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY2_UP = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY3_UP = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY0_DOWN = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY1_DOWN = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY2_DOWN = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY3_DOWN = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+
+function  e_InitInput: Boolean;
+procedure e_ReleaseInput;
+procedure e_UnpressAllKeys;
+procedure e_KeyUpDown (key: Integer; down: Boolean);
+
+function  e_KeyPressed (key: Integer): Boolean;
+function  e_AnyKeyPressed: Boolean;
+function  e_GetFirstKeyPressed: Integer;
+function  e_HasJoysticks: Boolean;
+
+function  e_JoyButtonToKey (id, btn: Integer): Integer;
+function  e_JoyAxisToKey (id, ax, dir: Integer): Integer;
+function  e_JoyHatToKey (id, hat, dir: Integer): Integer;
+
+var
+  e_JoystickAvailable: array [0..e_MaxJoys - 1] of Boolean;
+  e_JoystickDeadzones: array [0..e_MaxJoys - 1] of Integer = (8192, 8192, 8192, 8192);
+  e_KeyNames: array [0..e_MaxInputKeys] of String;
+
+implementation
+
+var
+  InputBuffer: array [0..e_MaxInputKeys - 1] of Boolean;
+
+procedure e_UnpressAllKeys;
+  var i: Integer;
+begin
+  for i := 0 to High(InputBuffer) do
+    InputBuffer[i] := False
+end;
+
+procedure e_KeyUpDown (key: Integer; down: Boolean);
+begin
+  ASSERT(key >= 0);
+  ASSERT(key < e_MaxInputKeys);
+  if key > 0 then
+    InputBuffer[key] := down
+end;
+
+procedure GenerateKeyNames;
+  var i, j, k: Integer;
+begin
+  // keyboard key names
+  e_KeyNames[IK_0] := '0';
+  e_KeyNames[IK_1] := '1';
+  e_KeyNames[IK_2] := '2';
+  e_KeyNames[IK_3] := '3';
+  e_KeyNames[IK_4] := '4';
+  e_KeyNames[IK_5] := '5';
+  e_KeyNames[IK_6] := '6';
+  e_KeyNames[IK_7] := '7';
+  e_KeyNames[IK_8] := '8';
+  e_KeyNames[IK_9] := '9';
+
+  for i := IK_A to IK_Z do
+    e_KeyNames[i] := '' + chr(ord('a') + (i - IK_a));
+
+  e_KeyNames[IK_ESCAPE] := 'ESCAPE';
+  e_KeyNames[IK_ENTER] := 'ENTER';
+  e_KeyNames[IK_TAB] := 'TAB';
+  e_KeyNames[IK_BACKSPACE] := 'BACKSPACE';
+  e_KeyNames[IK_SPACE] := 'SPACE';
+  e_KeyNames[IK_UP] := 'UP';
+  e_KeyNames[IK_LEFT] := 'LEFT';
+  e_KeyNames[IK_RIGHT] := 'RIGHT';
+  e_KeyNames[IK_DOWN] := 'DOWN';
+  e_KeyNames[IK_INSERT] := 'INSERT';
+  e_KeyNames[IK_DELETE] := 'DELETE';
+  e_KeyNames[IK_HOME] := 'HOME';
+  e_KeyNames[IK_END] := 'END';
+  e_KeyNames[IK_PAGEUP] := 'PGUP';
+  e_KeyNames[IK_PAGEDN] := 'PGDOWN';
+  e_KeyNames[IK_KPINSERT] := 'PAD0';
+  e_KeyNames[IK_KPEND] := 'PAD1';
+  e_KeyNames[IK_KPDOWN] := 'PAD2';
+  e_KeyNames[IK_KPPAGEDN] := 'PAD3';
+  e_KeyNames[IK_KPLEFT] := 'PAD4';
+  e_KeyNames[IK_KP5] := 'PAD5';
+  e_KeyNames[IK_KPRIGHT] := 'PAD6';
+  e_KeyNames[IK_KPHOME] := 'PAD7';
+  e_KeyNames[IK_KPUP] := 'PAD8';
+  e_KeyNames[IK_KPPAGEUP] := 'PAD9';
+  e_KeyNames[IK_NUMLOCK] := 'NUM';
+  e_KeyNames[IK_KPDIVIDE] := 'PAD/';
+  e_KeyNames[IK_KPMULTIPLE] := 'PAD*';
+  e_KeyNames[IK_KPMINUS] := 'PAD-';
+  e_KeyNames[IK_KPPLUS] := 'PAD+';
+  e_KeyNames[IK_KPENTER] := 'PADENTER';
+  e_KeyNames[IK_KPDOT] := 'PAD.';
+  e_KeyNames[IK_CAPSLOCK] := 'CAPS';
+  e_KeyNames[IK_BACKQUOTE] := 'BACKQUOTE';
+  e_KeyNames[IK_F1] := 'F1';
+  e_KeyNames[IK_F2] := 'F2';
+  e_KeyNames[IK_F3] := 'F3';
+  e_KeyNames[IK_F4] := 'F4';
+  e_KeyNames[IK_F5] := 'F5';
+  e_KeyNames[IK_F6] := 'F6';
+  e_KeyNames[IK_F7] := 'F7';
+  e_KeyNames[IK_F8] := 'F8';
+  e_KeyNames[IK_F9] := 'F9';
+  e_KeyNames[IK_F10] := 'F10';
+  e_KeyNames[IK_F11] := 'F11';
+  e_KeyNames[IK_F12] := 'F12';
+  e_KeyNames[IK_SHIFT] := 'LSHIFT';
+  e_KeyNames[IK_RSHIFT] := 'RSHIFT';
+  e_KeyNames[IK_CTRL] := 'LCTRL';
+  e_KeyNames[IK_RCTRL] := 'RCTRL';
+  e_KeyNames[IK_ALT] := 'LALT';
+  e_KeyNames[IK_RALT] := 'RALT';
+  e_KeyNames[IK_WIN] := 'LWIN';
+  e_KeyNames[IK_RWIN] := 'RWIN';
+  e_KeyNames[IK_MENU] := 'MENU';
+  e_KeyNames[IK_PRINTSCR] := 'PSCRN';
+  e_KeyNames[IK_SCROLLLOCK] := 'SCROLL';
+  e_KeyNames[IK_PAUSE] := 'PAUSE';
+  e_KeyNames[IK_LBRACKET] := '[';
+  e_KeyNames[IK_RBRACKET] := ']';
+  e_KeyNames[IK_SEMICOLON] := ';';
+  e_KeyNames[IK_QUOTE] := '''';
+  e_KeyNames[IK_BACKSLASH] := '\';
+  e_KeyNames[IK_SLASH] := '/';
+  e_KeyNames[IK_COMMA] := ',';
+  e_KeyNames[IK_DOT] := '.';
+  e_KeyNames[IK_MINUS] := '-';
+  e_KeyNames[IK_EQUALS] := '=';
+
+  // joysticks
+  for j := 0 to e_MaxJoys-1 do
+  begin
+    k := JOYK_BEG + j * e_MaxJoyBtns;
+    // buttons
+    for i := 0 to e_MaxJoyBtns-1 do
+      e_KeyNames[k + i] := Format('JOY%dB%d', [j, i]);
+    k := JOYA_BEG + j * e_MaxJoyAxes * 2;
+    // axes
+    for i := 0 to e_MaxJoyAxes-1 do
+    begin
+      e_KeyNames[k + i*2    ] := Format('JOY%dA%d+', [j, i]);
+      e_KeyNames[k + i*2 + 1] := Format('JOY%dA%d-', [j, i]);
+    end;
+    k := JOYH_BEG + j * e_MaxJoyHats * 4;
+    // hats
+    for i := 0 to e_MaxJoyHats-1 do
+    begin
+      e_KeyNames[k + i*4    ] := Format('JOY%dD%dL', [j, i]);
+      e_KeyNames[k + i*4 + 1] := Format('JOY%dD%dU', [j, i]);
+      e_KeyNames[k + i*4 + 2] := Format('JOY%dD%dR', [j, i]);
+      e_KeyNames[k + i*4 + 3] := Format('JOY%dD%dD', [j, i]);
+    end;
+  end;
+
+  // vitrual keys
+  for i := 0 to e_MaxVirtKeys-1 do
+    e_KeyNames[VIRT_BEG + i] := 'VIRTUAL' + IntToStr(i);
+end;
+
+function e_HasJoysticks: Boolean;
+  var i: Integer;
+begin
+  i := 0;
+  while (i < e_MaxJoys) and (e_JoystickAvailable[i] = False) do inc(i);
+  result := i < e_MaxJoys
+end;
+
+function e_InitInput: Boolean;
+  var i: Integer;
+begin
+  for i := 0 to e_MaxJoys - 1 do
+    e_JoystickAvailable[i] := False;
+  GenerateKeyNames;
+  result := True
+end;
+
+procedure e_ReleaseInput;
+  var i: Integer;
+begin
+  for i := 0 to e_MaxJoys - 1 do
+    e_JoystickAvailable[i] := False
+end;
+
+function e_KeyPressed (key: Integer): Boolean;
+begin
+  ASSERT(key >= 0);
+  ASSERT(key < e_MaxInputKeys);
+  result := InputBuffer[key]
+end;
+
+function e_AnyKeyPressed: Boolean;
+begin
+  result := e_GetFirstKeyPressed <> IK_INVALID;
+end;
+
+function e_GetFirstKeyPressed: Integer;
+  var i: Integer;
+begin
+  i := 1;
+  while (i < e_MaxInputKeys) and (InputBuffer[i] = False) do inc(i);
+  if i < e_MaxInputKeys then
+    result := i
+  else
+    result := IK_INVALID
+end;
+
+function e_JoyButtonToKey (id, btn: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(btn >= 0);
+  ASSERT(btn < e_MaxJoyBtns);
+  result := JOYK_BEG + id*e_MaxJoyBtns + btn
+end;
+
+function e_JoyAxisToKey (id, ax, dir: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(ax >= 0);
+  ASSERT(ax < e_MaxJoyAxes);
+  ASSERT(dir in [AX_MINUS, AX_PLUS]);
+  result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir
+end;
+
+function e_JoyHatToKey (id, hat, dir: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(hat >= 0);
+  ASSERT(hat < e_MaxJoyHats);
+  ASSERT(dir in [HAT_LEFT, HAT_UP, HAT_RIGHT, HAT_DOWN]);
+  result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir
+end;
diff --git a/src/engine/e_input_stub.inc b/src/engine/e_input_stub.inc
new file mode 100644 (file)
index 0000000..b2ca332
--- /dev/null
@@ -0,0 +1,458 @@
+interface
+
+  uses SysUtils;
+
+  const
+    e_MaxKbdKeys  = 256;
+    e_MaxJoys     = 4;
+    e_MaxJoyBtns  = 32;
+    e_MaxJoyAxes  = 8;
+    e_MaxJoyHats  = 8;
+    e_MaxVirtKeys = 48;
+
+    e_MaxJoyKeys = e_MaxJoyBtns + e_MaxJoyAxes*2 + e_MaxJoyHats*4;
+
+    e_MaxInputKeys = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
+    // $$$..$$$ -  321 Keyboard buttons/keys
+    // $$$..$$$ - 4*32 Joystick buttons
+    // $$$..$$$ -  8*2 Joystick axes (- and +)
+    // $$$..$$$ -  4*4 Joystick hats (L U R D)
+    // $$$..$$$ -   48 Virtual buttons/keys
+
+    KBRD_END = e_MaxKbdKeys;
+    JOYK_BEG = KBRD_END;
+    JOYK_END = JOYK_BEG + e_MaxJoyBtns*e_MaxJoys;
+    JOYA_BEG = JOYK_END;
+    JOYA_END = JOYA_BEG + e_MaxJoyAxes*2*e_MaxJoys;
+    JOYH_BEG = JOYA_END;
+    JOYH_END = JOYH_BEG + e_MaxJoyHats*4*e_MaxJoys;
+    VIRT_BEG = JOYH_END;
+    VIRT_END = VIRT_BEG + e_MaxVirtKeys;
+
+    // these are apparently used in g_gui and g_game and elsewhere
+    IK_INVALID = 0;
+    IK_ESCAPE  = 1;
+    IK_RETURN  = 2;
+    IK_KPRETURN= 3;
+    IK_ENTER   = IK_RETURN;
+    IK_KPINSERT = 5;
+    IK_UP      = 6;
+    IK_KPUP    = 7;
+    IK_DOWN    = 8;
+    IK_KPDOWN  = 9;
+    IK_LEFT    = 10;
+    IK_KPLEFT  = 11;
+    IK_RIGHT   = 12;
+    IK_KPRIGHT = 13;
+    IK_DELETE  = 14;
+    IK_HOME    = 15;
+    IK_KPHOME  = 16;
+    IK_INSERT  = 17;
+    IK_SPACE   = 18;
+    IK_SHIFT   = 20;
+    IK_ALT     = 21;
+    IK_TAB     = 22;
+    IK_PAGEUP  = 23;
+    IK_KPPAGEUP= 24;
+    IK_PAGEDN  = 25;
+    IK_KPPAGEDN= 26;
+    IK_KP5     = 27;
+    IK_NUMLOCK = 28;
+    IK_KPDIVIDE= 29;
+    IK_KPMULTIPLE= 30;
+    IK_KPMINUS = 31;
+    IK_KPPLUS  = 32;
+    IK_KPENTER = IK_KPRETURN;
+    IK_KPDOT   = 34;
+    IK_CAPSLOCK= 35;
+    IK_RSHIFT  = 36;
+    IK_CTRL    = 37;
+    IK_RCTRL   = 38;
+    IK_RALT    = 39;
+    IK_WIN     = 40;
+    IK_RWIN    = 41;
+    IK_MENU    = 42;
+    IK_PRINTSCR= 43;
+    IK_SCROLLLOCK= 44;
+    IK_LBRACKET= 45;
+    IK_RBRACKET= 46;
+    IK_SEMICOLON= 47;
+    IK_QUOTE   = 48;
+    IK_BACKSLASH= 49;
+    IK_SLASH   = 50;
+    IK_COMMA   = 51;
+    IK_DOT     = 52;
+    IK_EQUALS  = 53;
+    IK_0       = 54;
+    IK_1       = 55;
+    IK_2       = 56;
+    IK_3       = 57;
+    IK_4       = 58;
+    IK_5       = 59;
+    IK_6       = 60;
+    IK_7       = 61;
+    IK_8       = 62;
+    IK_9       = 63;
+    IK_F1      = 64;
+    IK_F2      = 65;
+    IK_F3      = 66;
+    IK_F4      = 67;
+    IK_F5      = 68;
+    IK_F6      = 69;
+    IK_F7      = 70;
+    IK_F8      = 71;
+    IK_F9      = 72;
+    IK_F10     = 73;
+    IK_F11     = 74;
+    IK_F12     = 75;
+    IK_END     = 76;
+    IK_KPEND   = 77;
+    IK_BACKSPACE = 78;
+    IK_BACKQUOTE = 79;
+    IK_GRAVE     = IK_BACKQUOTE;
+    IK_PAUSE   = 81;
+    IK_A       = 82;
+    IK_B       = 83;
+    IK_C       = 84;
+    IK_D       = 85;
+    IK_E       = 86;
+    IK_F       = 87;
+    IK_G       = 88;
+    IK_H       = 89;
+    IK_I       = 90;
+    IK_J       = 91;
+    IK_K       = 92;
+    IK_L       = 93;
+    IK_M       = 94;
+    IK_N       = 95;
+    IK_O       = 96;
+    IK_P       = 97;
+    IK_Q       = 98;
+    IK_R       = 99;
+    IK_S       = 100;
+    IK_T       = 101;
+    IK_U       = 102;
+    IK_V       = 103;
+    IK_W       = 104;
+    IK_X       = 105;
+    IK_Y       = 106;
+    IK_Z       = 107;
+    IK_MINUS   = 108;
+    // TODO: think of something better than this shit
+    IK_LASTKEY = e_MaxKbdKeys-1;
+
+  VK_FIRSTKEY = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys;
+  VK_LEFT     = VK_FIRSTKEY + 0;
+  VK_RIGHT    = VK_FIRSTKEY + 1;
+  VK_UP       = VK_FIRSTKEY + 2;
+  VK_DOWN     = VK_FIRSTKEY + 3;
+  VK_FIRE     = VK_FIRSTKEY + 4;
+  VK_OPEN     = VK_FIRSTKEY + 5;
+  VK_JUMP     = VK_FIRSTKEY + 6;
+  VK_CHAT     = VK_FIRSTKEY + 7;
+  VK_ESCAPE   = VK_FIRSTKEY + 8;
+  VK_0        = VK_FIRSTKEY + 9;
+  VK_1        = VK_FIRSTKEY + 10;
+  VK_2        = VK_FIRSTKEY + 11;
+  VK_3        = VK_FIRSTKEY + 12;
+  VK_4        = VK_FIRSTKEY + 13;
+  VK_5        = VK_FIRSTKEY + 14;
+  VK_6        = VK_FIRSTKEY + 15;
+  VK_7        = VK_FIRSTKEY + 16;
+  VK_8        = VK_FIRSTKEY + 17;
+  VK_9        = VK_FIRSTKEY + 18;
+  VK_A        = VK_FIRSTKEY + 19;
+  VK_B        = VK_FIRSTKEY + 20;
+  VK_C        = VK_FIRSTKEY + 21;
+  VK_D        = VK_FIRSTKEY + 22;
+  VK_E        = VK_FIRSTKEY + 23;
+  VK_F        = VK_FIRSTKEY + 24;
+  VK_CONSOLE  = VK_FIRSTKEY + 25;
+  VK_STATUS   = VK_FIRSTKEY + 26;
+  VK_TEAM     = VK_FIRSTKEY + 27;
+  VK_PREV     = VK_FIRSTKEY + 28;
+  VK_NEXT     = VK_FIRSTKEY + 29;
+  VK_STRAFE   = VK_FIRSTKEY + 30;
+  VK_LSTRAFE  = VK_FIRSTKEY + 31;
+  VK_RSTRAFE  = VK_FIRSTKEY + 32;
+  VK_PRINTSCR = VK_FIRSTKEY + 33;
+  VK_SHOWKBD  = VK_FIRSTKEY + 34;
+  VK_HIDEKBD  = VK_FIRSTKEY + 35;
+  VK_LASTKEY  = e_MaxKbdKeys + e_MaxJoys*e_MaxJoyKeys + e_MaxVirtKeys - 1;
+
+  AX_MINUS  = 0;
+  AX_PLUS   = 1;
+  HAT_LEFT  = 0;
+  HAT_UP    = 1;
+  HAT_RIGHT = 2;
+  HAT_DOWN  = 3;
+
+  JOY0_ATTACK = JOYK_BEG + 0*e_MaxJoyBtns + 0;
+  JOY1_ATTACK = JOYK_BEG + 1*e_MaxJoyBtns + 0;
+  JOY2_ATTACK = JOYK_BEG + 2*e_MaxJoyBtns + 0;
+  JOY3_ATTACK = JOYK_BEG + 3*e_MaxJoyBtns + 0;
+  JOY0_NEXT = JOYK_BEG + 0*e_MaxJoyBtns + 1;
+  JOY1_NEXT = JOYK_BEG + 1*e_MaxJoyBtns + 1;
+  JOY2_NEXT = JOYK_BEG + 2*e_MaxJoyBtns + 1;
+  JOY3_NEXT = JOYK_BEG + 3*e_MaxJoyBtns + 1;
+  JOY0_JUMP = JOYK_BEG + 0*e_MaxJoyBtns + 2;
+  JOY1_JUMP = JOYK_BEG + 1*e_MaxJoyBtns + 2;
+  JOY2_JUMP = JOYK_BEG + 2*e_MaxJoyBtns + 2;
+  JOY3_JUMP = JOYK_BEG + 3*e_MaxJoyBtns + 2;
+  JOY0_ACTIVATE = JOYK_BEG + 0*e_MaxJoyBtns + 3;
+  JOY1_ACTIVATE = JOYK_BEG + 1*e_MaxJoyBtns + 3;
+  JOY2_ACTIVATE = JOYK_BEG + 2*e_MaxJoyBtns + 3;
+  JOY3_ACTIVATE = JOYK_BEG + 3*e_MaxJoyBtns + 3;
+  JOY0_PREV = JOYK_BEG + 0*e_MaxJoyBtns + 4;
+  JOY1_PREV = JOYK_BEG + 1*e_MaxJoyBtns + 4;
+  JOY2_PREV = JOYK_BEG + 2*e_MaxJoyBtns + 4;
+  JOY3_PREV = JOYK_BEG + 3*e_MaxJoyBtns + 4;
+
+  JOY0_LEFT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY1_LEFT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY2_LEFT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY3_LEFT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_LEFT;
+  JOY0_RIGHT = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY1_RIGHT = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY2_RIGHT = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY3_RIGHT = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_RIGHT;
+  JOY0_UP = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY1_UP = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY2_UP = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY3_UP = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_UP;
+  JOY0_DOWN = JOYH_BEG + 0*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY1_DOWN = JOYH_BEG + 1*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY2_DOWN = JOYH_BEG + 2*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+  JOY3_DOWN = JOYH_BEG + 3*e_MaxJoyHats*4 + 0*4 + HAT_DOWN;
+
+function  e_InitInput: Boolean;
+procedure e_ReleaseInput;
+procedure e_UnpressAllKeys;
+procedure e_KeyUpDown (key: Integer; down: Boolean);
+
+function  e_KeyPressed (key: Integer): Boolean;
+function  e_AnyKeyPressed: Boolean;
+function  e_GetFirstKeyPressed: Integer;
+function  e_HasJoysticks: Boolean;
+
+function  e_JoyButtonToKey (id, btn: Integer): Integer;
+function  e_JoyAxisToKey (id, ax, dir: Integer): Integer;
+function  e_JoyHatToKey (id, hat, dir: Integer): Integer;
+
+var
+  e_JoystickAvailable: array [0..e_MaxJoys - 1] of Boolean;
+  e_JoystickDeadzones: array [0..e_MaxJoys - 1] of Integer = (8192, 8192, 8192, 8192);
+  e_KeyNames: array [0..e_MaxInputKeys] of String;
+
+implementation
+
+var
+  InputBuffer: array [0..e_MaxInputKeys - 1] of Boolean;
+
+procedure e_UnpressAllKeys;
+  var i: Integer;
+begin
+  for i := 0 to High(InputBuffer) do
+    InputBuffer[i] := False
+end;
+
+procedure e_KeyUpDown (key: Integer; down: Boolean);
+begin
+  ASSERT(key >= 0);
+  ASSERT(key < e_MaxInputKeys);
+  if key > 0 then
+    InputBuffer[key] := down
+end;
+
+procedure GenerateKeyNames;
+  var i, j, k: Integer;
+begin
+  // keyboard key names
+  e_KeyNames[IK_0] := '0';
+  e_KeyNames[IK_1] := '1';
+  e_KeyNames[IK_2] := '2';
+  e_KeyNames[IK_3] := '3';
+  e_KeyNames[IK_4] := '4';
+  e_KeyNames[IK_5] := '5';
+  e_KeyNames[IK_6] := '6';
+  e_KeyNames[IK_7] := '7';
+  e_KeyNames[IK_8] := '8';
+  e_KeyNames[IK_9] := '9';
+
+  for i := IK_A to IK_Z do
+    e_KeyNames[i] := '' + chr(ord('a') + (i - IK_a));
+
+  e_KeyNames[IK_ESCAPE] := 'ESCAPE';
+  e_KeyNames[IK_ENTER] := 'ENTER';
+  e_KeyNames[IK_TAB] := 'TAB';
+  e_KeyNames[IK_BACKSPACE] := 'BACKSPACE';
+  e_KeyNames[IK_SPACE] := 'SPACE';
+  e_KeyNames[IK_UP] := 'UP';
+  e_KeyNames[IK_LEFT] := 'LEFT';
+  e_KeyNames[IK_RIGHT] := 'RIGHT';
+  e_KeyNames[IK_DOWN] := 'DOWN';
+  e_KeyNames[IK_INSERT] := 'INSERT';
+  e_KeyNames[IK_DELETE] := 'DELETE';
+  e_KeyNames[IK_HOME] := 'HOME';
+  e_KeyNames[IK_END] := 'END';
+  e_KeyNames[IK_PAGEUP] := 'PGUP';
+  e_KeyNames[IK_PAGEDN] := 'PGDOWN';
+  e_KeyNames[IK_KPINSERT] := 'PAD0';
+  e_KeyNames[IK_KPEND] := 'PAD1';
+  e_KeyNames[IK_KPDOWN] := 'PAD2';
+  e_KeyNames[IK_KPPAGEDN] := 'PAD3';
+  e_KeyNames[IK_KPLEFT] := 'PAD4';
+  e_KeyNames[IK_KP5] := 'PAD5';
+  e_KeyNames[IK_KPRIGHT] := 'PAD6';
+  e_KeyNames[IK_KPHOME] := 'PAD7';
+  e_KeyNames[IK_KPUP] := 'PAD8';
+  e_KeyNames[IK_KPPAGEUP] := 'PAD9';
+  e_KeyNames[IK_NUMLOCK] := 'NUM';
+  e_KeyNames[IK_KPDIVIDE] := 'PAD/';
+  e_KeyNames[IK_KPMULTIPLE] := 'PAD*';
+  e_KeyNames[IK_KPMINUS] := 'PAD-';
+  e_KeyNames[IK_KPPLUS] := 'PAD+';
+  e_KeyNames[IK_KPENTER] := 'PADENTER';
+  e_KeyNames[IK_KPDOT] := 'PAD.';
+  e_KeyNames[IK_CAPSLOCK] := 'CAPS';
+  e_KeyNames[IK_BACKQUOTE] := 'BACKQUOTE';
+  e_KeyNames[IK_F1] := 'F1';
+  e_KeyNames[IK_F2] := 'F2';
+  e_KeyNames[IK_F3] := 'F3';
+  e_KeyNames[IK_F4] := 'F4';
+  e_KeyNames[IK_F5] := 'F5';
+  e_KeyNames[IK_F6] := 'F6';
+  e_KeyNames[IK_F7] := 'F7';
+  e_KeyNames[IK_F8] := 'F8';
+  e_KeyNames[IK_F9] := 'F9';
+  e_KeyNames[IK_F10] := 'F10';
+  e_KeyNames[IK_F11] := 'F11';
+  e_KeyNames[IK_F12] := 'F12';
+  e_KeyNames[IK_SHIFT] := 'LSHIFT';
+  e_KeyNames[IK_RSHIFT] := 'RSHIFT';
+  e_KeyNames[IK_CTRL] := 'LCTRL';
+  e_KeyNames[IK_RCTRL] := 'RCTRL';
+  e_KeyNames[IK_ALT] := 'LALT';
+  e_KeyNames[IK_RALT] := 'RALT';
+  e_KeyNames[IK_WIN] := 'LWIN';
+  e_KeyNames[IK_RWIN] := 'RWIN';
+  e_KeyNames[IK_MENU] := 'MENU';
+  e_KeyNames[IK_PRINTSCR] := 'PSCRN';
+  e_KeyNames[IK_SCROLLLOCK] := 'SCROLL';
+  e_KeyNames[IK_PAUSE] := 'PAUSE';
+  e_KeyNames[IK_LBRACKET] := '[';
+  e_KeyNames[IK_RBRACKET] := ']';
+  e_KeyNames[IK_SEMICOLON] := ';';
+  e_KeyNames[IK_QUOTE] := '''';
+  e_KeyNames[IK_BACKSLASH] := '\';
+  e_KeyNames[IK_SLASH] := '/';
+  e_KeyNames[IK_COMMA] := ',';
+  e_KeyNames[IK_DOT] := '.';
+  e_KeyNames[IK_MINUS] := '-';
+  e_KeyNames[IK_EQUALS] := '=';
+
+  // joysticks
+  for j := 0 to e_MaxJoys-1 do
+  begin
+    k := JOYK_BEG + j * e_MaxJoyBtns;
+    // buttons
+    for i := 0 to e_MaxJoyBtns-1 do
+      e_KeyNames[k + i] := Format('JOY%dB%d', [j, i]);
+    k := JOYA_BEG + j * e_MaxJoyAxes * 2;
+    // axes
+    for i := 0 to e_MaxJoyAxes-1 do
+    begin
+      e_KeyNames[k + i*2    ] := Format('JOY%dA%d+', [j, i]);
+      e_KeyNames[k + i*2 + 1] := Format('JOY%dA%d-', [j, i]);
+    end;
+    k := JOYH_BEG + j * e_MaxJoyHats * 4;
+    // hats
+    for i := 0 to e_MaxJoyHats-1 do
+    begin
+      e_KeyNames[k + i*4    ] := Format('JOY%dD%dL', [j, i]);
+      e_KeyNames[k + i*4 + 1] := Format('JOY%dD%dU', [j, i]);
+      e_KeyNames[k + i*4 + 2] := Format('JOY%dD%dR', [j, i]);
+      e_KeyNames[k + i*4 + 3] := Format('JOY%dD%dD', [j, i]);
+    end;
+  end;
+
+  // vitrual keys
+  for i := 0 to e_MaxVirtKeys-1 do
+    e_KeyNames[VIRT_BEG + i] := 'VIRTUAL' + IntToStr(i);
+end;
+
+function e_HasJoysticks: Boolean;
+  var i: Integer;
+begin
+  i := 0;
+  while (i < e_MaxJoys) and (e_JoystickAvailable[i] = False) do inc(i);
+  result := i < e_MaxJoys
+end;
+
+function e_InitInput: Boolean;
+  var i: Integer;
+begin
+  for i := 0 to e_MaxJoys - 1 do
+    e_JoystickAvailable[i] := False;
+  GenerateKeyNames;
+  result := True
+end;
+
+procedure e_ReleaseInput;
+  var i: Integer;
+begin
+  for i := 0 to e_MaxJoys - 1 do
+    e_JoystickAvailable[i] := False
+end;
+
+function e_KeyPressed (key: Integer): Boolean;
+begin
+  ASSERT(key >= 0);
+  ASSERT(key < e_MaxInputKeys);
+  result := InputBuffer[key]
+end;
+
+function e_AnyKeyPressed: Boolean;
+begin
+  result := e_GetFirstKeyPressed <> IK_INVALID;
+end;
+
+function e_GetFirstKeyPressed: Integer;
+  var i: Integer;
+begin
+  i := 1;
+  while (i < e_MaxInputKeys) and (InputBuffer[i] = False) do inc(i);
+  if i < e_MaxInputKeys then
+    result := i
+  else
+    result := IK_INVALID
+end;
+
+function e_JoyButtonToKey (id, btn: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(btn >= 0);
+  ASSERT(btn < e_MaxJoyBtns);
+  result := JOYK_BEG + id*e_MaxJoyBtns + btn
+end;
+
+function e_JoyAxisToKey (id, ax, dir: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(ax >= 0);
+  ASSERT(ax < e_MaxJoyAxes);
+  ASSERT(dir in [AX_MINUS, AX_PLUS]);
+  result := JOYA_BEG + id*e_MaxJoyAxes*2 + ax*2 + dir
+end;
+
+function e_JoyHatToKey (id, hat, dir: Integer): Integer;
+begin
+  ASSERT(id >= 0);
+  ASSERT(id < e_MaxJoys);
+  ASSERT(hat >= 0);
+  ASSERT(hat < e_MaxJoyHats);
+  ASSERT(dir in [HAT_LEFT, HAT_UP, HAT_RIGHT, HAT_DOWN]);
+  result := JOYH_BEG + id*e_MaxJoyHats*4 + hat*4 + dir
+end;
index c57e2a3c53f516deca4d04e9f58654f534a891cb..53ee47e63a9e351ffefbf73209d094305eddfdd3 100644 (file)
@@ -98,7 +98,7 @@ var
 implementation
 
 uses
-  g_window, g_options, utils;
+  g_options, utils;
 
 const
   NUM_SOURCES = 255; // + 1 stereo
index 35cd2c34430ed5db0aa0190b2276ee605c82a4f5..4d9eaba5d983da5fc644b7255be1923dfcce928f 100644 (file)
 interface
 
 uses
-  sdl2,
-  SDL2_mixer,
   {$IFDEF USE_MEMPOOL}mempool,{$ENDIF}
-  e_log,
-  SysUtils;
+  SDL2, SDL2_mixer,
+  e_log, SysUtils;
 
 type
   TSoundRec = record
index 0ebe256b9d9d818245067079d9fe22c99a5e252c..ba7bcdf67057a5d65f6e057b6ab4c755838f3b01 100644 (file)
@@ -44,7 +44,13 @@ type
 
 implementation
 
-uses sdl2, utils, e_log;
+uses
+  {$IFDEF USE_SDL}
+    SDL,
+  {$ELSE}
+    SDL2,
+  {$ENDIF}
+  utils, e_log;
 
 (* TWAVLoaderFactory *)
 
@@ -73,7 +79,6 @@ begin
 end;
 
 (* TWAVLoader *)
-
 function TWAVLoader.Load(Data: Pointer; Len: LongWord; SStreaming: Boolean): Boolean;
 var
   Spec: TSDL_AudioSpec;
@@ -85,14 +90,22 @@ begin
 
   RW := SDL_RWFromConstMem(Data, Len);
 
+{$IFDEF USE_SDL2}
   if SDL_LoadWAV_RW(RW, 0, @Spec, @TmpBuf, @TmpLen) = nil then
+{$ELSE}
+  if SDL_LoadWAV_RW(RW, 0, @Spec, PUInt8(@TmpBuf), @TmpLen) = nil then
+{$ENDIF}
   begin
     e_LogWriteln('Could not load WAV: ' + SDL_GetError());
   end
   else
   begin
     FFormat.SampleRate := Spec.freq;
-    FFormat.SampleBits := SDL_AUDIO_BITSIZE(Spec.format);
+    {$IFDEF USE_SDL2}
+      FFormat.SampleBits := SDL_AUDIO_BITSIZE(Spec.format);
+    {$ELSE}
+      FFormat.SampleBits := Spec.format and $FF;
+    {$ENDIF}
     FFormat.Channels := Spec.channels;
     FStreaming := False; // never stream wavs
     FDataLen := TmpLen;
@@ -120,14 +133,22 @@ begin
     exit;
   end;
 
+{$IFDEF USE_SDL2}
   if SDL_LoadWAV_RW(RW, 0, @Spec, @TmpBuf, @TmpLen) = nil then
+{$ELSE}
+  if SDL_LoadWAV_RW(RW, 0, @Spec, PUInt8(@TmpBuf), @TmpLen) = nil then
+{$ENDIF}
   begin
     e_LogWritefln('Could not load WAV file `%s`: %s', [FName, SDL_GetError()]);
   end
   else
   begin
     FFormat.SampleRate := Spec.freq;
-    FFormat.SampleBits := SDL_AUDIO_BITSIZE(Spec.format);
+    {$IFDEF USE_SDL2}
+      FFormat.SampleBits := SDL_AUDIO_BITSIZE(Spec.format);
+    {$ELSE}
+      FFormat.SampleBits := Spec.format and $FF;
+    {$ENDIF}
     FFormat.Channels := Spec.channels;
     FStreaming := False; // never stream wavs
     FDataLen := TmpLen;
index 875879fc19d5b70d820f22182822a253ce09373e..18f1f21ac854c050c2d928da10d4ebf4e874f437 100644 (file)
 {$ENDIF}
 {$HINTS OFF}
 
+{$IF DEFINED(USE_SYSSTUB)}
+  {$IF DEFINED(USE_SDL) OR DEFINED(USE_SDL2)}
+    {$ERROR Only one system driver must be selected!}
+  {$ENDIF}
+{$ELSEIF DEFINED(USE_SDL)}
+  {$IF DEFINED(USE_SYSSTUB) OR DEFINED(USE_SDL2)}
+    {$ERROR Only one system driver must be selected!}
+  {$ENDIF}
+{$ELSEIF DEFINED(USE_SDL2)}
+  {$IF DEFINED(USE_SYSSTUB) OR DEFINED(USE_SDL)}
+    {$ERROR Only one system driver must be selected!}
+  {$ENDIF}
+{$ELSE}
+  {$ERROR System driver not selected. Use -dUSE_SYSSTUB or -dUSE_SDL or -dUSE_SDL2}
+{$ENDIF}
+
 {$IF DEFINED(USE_SDLMIXER)}
   {$IF DEFINED(USE_FMOD) OR DEFINED(USE_OPENAL)}
     {$ERROR Only one sound driver must be selected!}
@@ -34,7 +50,7 @@
     {$ERROR Only one sound driver must be selected!}
   {$ENDIF}
 {$ELSE}
-  {$ERROR Sound driver not selected. Use -DUSE_SDLMIXER or -DUSE_FMOD or -DUSE_OPENAL}
+  {$ERROR Sound driver not selected. Use -dUSE_SDLMIXER or -dUSE_FMOD or -dUSE_OPENAL}
 {$ENDIF}
 
 uses
@@ -54,14 +70,23 @@ uses
 {$IFDEF USE_MINIUPNPC}
   miniupnpc in '../lib/miniupnpc/miniupnpc.pas',
 {$ENDIF}
+
+{$IFDEF USE_SDL}
+  SDL,
+{$ENDIF}
+{$IFDEF USE_SDL2}
   SDL2 in '../lib/sdl2/sdl2.pas',
-{$IFDEF USE_SDLMIXER}
-  SDL2_mixer in '../lib/sdl2/SDL2_mixer.pas',
+  {$IFDEF USE_SDLMIXER}
+    SDL2_mixer in '../lib/sdl2/SDL2_mixer.pas',
+  {$ENDIF}
 {$ENDIF}
+
 {$IFDEF USE_OPENAL}
   AL in '../lib/openal/al.pas',
   e_soundfile in '../engine/e_soundfile.pas',
-  e_soundfile_wav in '../engine/e_soundfile_wav.pas',
+  {$IF DEFINED(USE_SDL) OR DEFINED(USE_SDL2)}
+    e_soundfile_wav in '../engine/e_soundfile_wav.pas',
+  {$ENDIF}
   {$IFDEF USE_VORBIS}
     vorbis in '../lib/vorbis/vorbis.pas',
     e_soundfile_vorbis in '../engine/e_soundfile_vorbis.pas',
@@ -90,6 +115,7 @@ uses
     ogg in '../lib/vorbis/ogg.pas', // this has to come last because link order
   {$ENDIF}
 {$ENDIF}
+
   ENet in '../lib/enet/enet.pp',
   e_graphics in '../engine/e_graphics.pas',
   e_input in '../engine/e_input.pas',
@@ -131,6 +157,19 @@ uses
   g_triggers in 'g_triggers.pas',
   g_weapons in 'g_weapons.pas',
   g_window in 'g_window.pas',
+{$IFDEF USE_SYSSTUB}
+  g_system in 'stub/g_system.pas',
+  g_touch in 'stub/g_touch.pas',
+{$ENDIF}
+{$IFDEF USE_SDL}
+  g_system in 'sdl/g_system.pas',
+  g_touch in 'sdl/g_touch.pas',
+{$ENDIF}
+{$IFDEF USE_SDL2}
+  g_system in 'sdl2/g_system.pas',
+  g_touch in 'sdl2/g_touch.pas',
+{$ENDIF}
+
   SysUtils,
 {$IFDEF USE_FMOD}
   fmod in '../lib/FMOD/fmod.pas',
index 01a27b05ef21ccb9dcd247b8ce654884afce96c0..22e318ab4a442a24e36759d25e764053a2011e03 100644 (file)
@@ -689,6 +689,7 @@ var
   b: array of string;
   str: string;
 begin
+{
   SetLength(Result, 0);
   SetLength(b, 0);
 
@@ -715,7 +716,7 @@ begin
 
     if TextLen(str) > MaxWidth then
     begin // Òåêóùàÿ ñòðîêà ñëèøêîì äëèííàÿ => ðàçáèâàåì
-      while str <> '' do
+      while (str[0] <> #0) and (str <> '') do
       begin
         SetLength(Result, Length(Result)+1);
 
@@ -741,6 +742,8 @@ begin
       Result[High(Result)] := str;
     end;
   end;
+}
+  Result := nil
 end;
 
 procedure Sort(var a: SSArray);
index b7c30dea57f6bca2b12ac4df0f3ad21e2b5e2936..7caa3ba142386b5eac3b72d0a977f6d529218cc3 100644 (file)
@@ -1416,7 +1416,7 @@ begin
     IK_END, IK_KPEND:
       CPos := Length(Line) + 1;
     IK_A..IK_Z, IK_SPACE, IK_SHIFT, IK_RSHIFT, IK_CAPSLOCK, IK_LBRACKET, IK_RBRACKET,
-    IK_SEMICOLON, IK_QUOTE, IK_BACKSLASH, IK_SLASH, IK_COMMA, IK_DOT, IK_EQUALS,
+    IK_SEMICOLON, IK_QUOTE, IK_BACKSLASH, IK_SLASH, IK_COMMA, IK_DOT, (*IK_EQUALS,*)
     IK_0, IK_1, IK_2, IK_3, IK_4, IK_5, IK_6, IK_7, IK_8, IK_9, IK_MINUS, IK_EQUALS:
       (* see TEXTINPUT event *)
   end
index 963496aab5b49eddfb4779dda2ef1f7e9d14674b..aa4c189bc549556117f56d5eb802c14e04aaee8d 100644 (file)
@@ -383,7 +383,7 @@ uses
   g_triggers, g_monsters, e_sound, CONFIG,
   g_language, g_net,
   ENet, e_msg, g_netmsg, g_netmaster,
-  sfs, wadreader;
+  sfs, wadreader, g_system;
 
 
 var
@@ -894,7 +894,7 @@ begin
   gDelayedEvents[n].DENum := Num;
   gDelayedEvents[n].DEStr := Str;
   if DEType = DE_GLOBEVENT then
-    gDelayedEvents[n].Time := (GetTimer() {div 1000}) + Time
+    gDelayedEvents[n].Time := (sys_GetTicks() {div 1000}) + Time
   else
     gDelayedEvents[n].Time := gTime + Time;
   Result := n;
@@ -2187,7 +2187,7 @@ begin
     KeyPress(IK_F10);
   end;
 
-  Time := GetTimer() {div 1000};
+  Time := sys_GetTicks() {div 1000};
 
 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
   if gDelayedEvents <> nil then
@@ -2543,7 +2543,7 @@ var
 begin
   e_TextureFontGetSize(gStdFont, ww2, hh2);
 
-  g_ProcessMessages();
+  sys_HandleInput;
 
   if g_Console_Action(ACTION_SCORES) then
   begin
@@ -3732,7 +3732,7 @@ var
 begin
   if gExit = EXIT_QUIT then Exit;
 
-  Time := GetTimer() {div 1000};
+  Time := sys_GetTicks() {div 1000};
   FPSCounter := FPSCounter+1;
   if Time - FPSTime >= 1000 then
   begin
@@ -4098,7 +4098,7 @@ begin
     g_Game_DeleteTestMap();
 
   gExit := EXIT_QUIT;
-  PushExitEvent();
+  sys_RequestQuit;
 end;
 
 procedure g_FatalError(Text: String);
@@ -4156,7 +4156,7 @@ end;
 
 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
 begin
-  g_Window_SetSize(newWidth, newHeight, nowFull);
+  sys_SetDisplayMode(newWidth, newHeight, gBPP, nowFull);
 end;
 
 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
index 3b84f30eb820982eae315c8147e4eccdfdc9458a..d60f2ddaa6de5fbf4940eff6a8d95f0e473b4299 100644 (file)
@@ -40,11 +40,14 @@ uses
 {$IFDEF ENABLE_HOLMES}
   g_holmes, fui_wadread, fui_style, fui_gfx_gl,
 {$ENDIF}
-  SDL2, wadreader, e_log, g_window,
+{$IFDEF USE_SDL2}
+  SDL2,
+{$ENDIF}
+  wadreader, e_log, g_window,
   e_graphics, e_input, g_game, g_console, g_gui,
   e_sound, g_options, g_sound, g_player, g_basic,
   g_weapons, SysUtils, g_triggers, MAPDEF, g_map,
-  g_menu, g_language, g_net, g_touch, g_res_downloader,
+  g_menu, g_language, g_net, g_touch, g_system, g_res_downloader,
   utils, conbuf, envvars,
   xparser;
 
@@ -84,6 +87,7 @@ 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;
@@ -105,6 +109,7 @@ begin
 
   if SDL_Init(sdlflags) < 0 then
     raise Exception.Create('SDL: Init failed: ' + SDL_GetError());
+{$ENDIF}
 
   e_WriteLog('Read config file', TMsgType.Notify);
   g_Options_Read(GameDir + '/' + CONFIG_FILENAME);
@@ -116,6 +121,10 @@ 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;
   if not fuiAddWad('flexui.wad') then
@@ -169,8 +178,12 @@ begin
   SDLMain();
 {$WARNINGS ON}
 
+{$IFDEF USE_SDL2}
   e_WriteLog('Releasing SDL', TMsgType.Notify);
   SDL_Quit();
+{$ELSE}
+  sys_Final;
+{$ENDIF}
 end;
 
 procedure Init();
index 4d2da495216be1983b5f6e38ae4454fc3f7dc6a0..3ffef2697e07622dbaceb277f30d1c8036471315 100644 (file)
@@ -45,11 +45,11 @@ uses
   {$INCLUDE ../nogl/noGLuses.inc}
   g_gui, g_textures, e_graphics, g_main, g_window, g_game, g_map,
   g_basic, g_console, g_sound, g_gfx, g_player, g_options, g_weapons,
-  e_log, SysUtils, CONFIG, g_playermodel, DateUtils, sdl2,
+  e_log, SysUtils, CONFIG, g_playermodel, DateUtils,
   MAPDEF, Math, g_saveload,
   e_texture, g_language,
   g_net, g_netmsg, g_netmaster, g_items, e_input, g_touch,
-  utils, wadreader;
+  utils, wadreader, g_system;
 
 
 type TYNCallback = procedure (yes:Boolean);
@@ -118,7 +118,8 @@ begin
 
   ovs := gVSync;
   gVSync := TGUISwitch(menu.GetControl('swVSync')).ItemIndex = 0;
-  if (ovs <> gVSync) then g_SetVSync(gVSync);
+  if (ovs <> gVSync) then
+    sys_EnableVSync(gVSync);
 
   gTextureFilter := TGUISwitch(menu.GetControl('swTextureFilter')).ItemIndex = 0;
   glLegacyNPOT := not (TGUISwitch(menu.GetControl('swLegacyNPOT')).ItemIndex = 0);
@@ -818,7 +819,7 @@ begin
   slWaitStr := _lc[I_NET_SLIST_WAIT];
 
   g_Game_Draw;
-  ReDrawWindow;
+  sys_Repaint;
 
   slReturnPressed := True;
   if g_Net_Slist_Fetch(slCurrent) then
@@ -1824,7 +1825,6 @@ procedure ProcVideoOptionsRes();
 var
   menu: TGUIMenu;
   list: SSArray;
-  SR: DWORD;
 begin
   menu := TGUIMenu(g_GUI_GetWindow('OptionsVideoResMenu').GetControl('mOptionsVideoResMenu'));
 
@@ -1835,15 +1835,16 @@ begin
 
   with TGUIListBox(menu.GetControl('lsResolution')) do
   begin
-    list := GetDisplayModes(gBPP, SR);
-
+    list := sys_GetDispalyModes(gBPP);
     if list <> nil then
-      begin
-        Items := list;
-        ItemIndex := SR;
-      end
+    begin
+      Items := list;
+      ItemIndex := Length(list)
+    end
     else
-      Clear();
+    begin
+      Clear
+    end
   end;
 
   with TGUISwitch(menu.GetControl('swFullScreen')) do
index 63b1270d9653e1306b34b7249f38e3ee554a6f86..eaf35fad6aadc41d2be339ff12a22c1a9c06a0c1 100644 (file)
@@ -250,7 +250,7 @@ implementation
 uses
   SysUtils,
   e_input, g_nethandler, g_netmsg, g_netmaster, g_player, g_window, g_console,
-  g_main, g_game, g_language, g_weapons, utils, ctypes,
+  g_main, g_game, g_language, g_weapons, utils, ctypes, g_system,
   g_map;
 
 const
@@ -1899,7 +1899,7 @@ begin
   end;
 
   // предупредить что ждем слишком долго через N секунд
-  TimeoutTime := GetTimer() + NET_CONNECT_TIMEOUT;
+  TimeoutTime := sys_GetTicks() + NET_CONNECT_TIMEOUT;
 
   OuterLoop := True;
   while OuterLoop do
@@ -1920,7 +1920,7 @@ begin
       end;
     end;
 
-    T := GetTimer();
+    T := sys_GetTicks();
     if T > TimeoutTime then
     begin
       TimeoutTime := T + NET_CONNECT_TIMEOUT * 100; // одного предупреждения хватит
index 01d5d67ce153aec648034a1e37a373b8ad178d31..2ecad14c74378d27d7f666bf9c7dc01c39d792d8 100644 (file)
@@ -86,7 +86,7 @@ implementation
 uses
   SysUtils, e_msg, e_input, e_graphics, e_log, g_window, g_net, g_console,
   g_map, g_game, g_sound, g_gui, g_menu, g_options, g_language, g_basic,
-  wadreader;
+  wadreader, g_system;
 
 var
   NetMHost: pENetHost = nil;
@@ -105,7 +105,7 @@ var
 
 function GetTimerMS (): Int64;
 begin
-  Result := GetTimer() {div 1000};
+  Result := sys_GetTicks() {div 1000};
 end;
 
 
@@ -876,7 +876,7 @@ begin
   if gConsoleShow or gChatShow then
     Exit;
 
-  qm := g_ProcessMessages(); // this updates kbd
+  qm := sys_HandleInput(); // this updates kbd
 
   if qm or e_KeyPressed(IK_ESCAPE) or e_KeyPressed(VK_ESCAPE) or
      e_KeyPressed(JOY0_JUMP) or e_KeyPressed(JOY1_JUMP) or
@@ -909,7 +909,7 @@ begin
       slWaitStr := _lc[I_NET_SLIST_WAIT];
 
       g_Game_Draw;
-      g_window.ReDrawWindow;
+      sys_Repaint;
 
       if g_Net_Slist_Fetch(SL) then
       begin
index 979fe4510cd9d9144e8e3faff46a47a44cc6fe41..ac80a1b1f786cd8d11f7356510ca1c743b344b6a 100644 (file)
@@ -96,9 +96,12 @@ implementation
 
 uses
   {$INCLUDE ../nogl/noGLuses.inc}
+  {$IFDEF USE_SDL2}
+    SDL2,
+  {$ENDIF}
   e_log, e_input, g_console, g_window, g_sound, g_gfx, g_player, Math,
   g_map, g_net, g_netmaster, SysUtils, CONFIG, g_game, g_main, e_texture,
-  g_items, wadreader, e_graphics, g_touch, SDL2, envvars;
+  g_items, wadreader, e_graphics, g_touch, envvars;
 
   var
     machine: Integer;
@@ -115,6 +118,7 @@ uses
       Result := Copy(Result, 1, 10) + ' ' + IntToStr(n)
   end;
 
+{$IFDEF USE_SDL2}
 procedure g_Options_SetDefaultVideo;
 var
   target, closest, display: TSDL_DisplayMode;
@@ -165,6 +169,24 @@ begin
   e_LogWriteLn('g_Options_SetDefaultVideo: w = ' + IntToStr(gScreenWidth) + ' h = ' + IntToStr(gScreenHeight));
   g_Console_ResetBinds;
 end;
+{$ELSE}
+procedure g_Options_SetDefaultVideo;
+begin
+  {$WARNING stub}
+  gScreenWidth := 640;
+  gScreenHeight := 480;
+  gBPP := 32;
+  gFullScreen := False;
+  gWinRealPosX := 0;
+  gWinRealPosY := 0;
+  gWinMaximized := False;
+  gVSync := True;
+  gTextureFilter := True;
+  glLegacyNPOT := False;
+  e_LogWriteLn('g_Options_SetDefaultVideo: w = ' + IntToStr(gScreenWidth) + ' h = ' + IntToStr(gScreenHeight));
+  g_Console_ResetBinds;
+end;
+{$ENDIF}
 
 procedure g_Options_SetDefault();
 var
diff --git a/src/game/g_touch.pas b/src/game/g_touch.pas
deleted file mode 100644 (file)
index a35a56e..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-(* 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;
-{$IFNDEF HEADLESS}
-    var i, x, y, w, h: Integer; founded: Boolean;
-{$ENDIF}
-  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 3adb2b616da1f09af1dfb5c3c7f0b0b09e1689fe..f623e8a69eca02f4924c5717b5a70a4569919679 100644 (file)
@@ -21,24 +21,9 @@ uses
   utils;
 
 function SDLMain (): Integer;
-function GetTimer (): Int64;
 procedure ResetTimer ();
-procedure PushExitEvent ();
-function ProcessMessage (): Boolean;
-procedure ReDrawWindow ();
-procedure SwapBuffers ();
-procedure Sleep (ms: LongWord);
-function GetDisplayModes (dbpp: LongWord; var selres: LongWord): SSArray;
-function g_Window_SetDisplay (preserveGL: Boolean=false): Boolean;
-function g_Window_SetSize (w, h: Word; fullscreen: Boolean): Boolean;
-procedure g_SetVSync (vsync: Boolean);
-
 procedure ProcessLoading (forceUpdate: Boolean=false);
 
-// returns `true` if quit event was received
-function g_ProcessMessages (): Boolean;
-
-
 var
   gwin_dump_extensions: Boolean = false;
   gwin_has_stencil: Boolean = false;
@@ -46,742 +31,38 @@ var
   g_dbg_aimline_on: Boolean = false;
   g_dbg_input: Boolean = False;
 
-
 implementation
 
 uses
 {$IFDEF WINDOWS}Windows,{$ENDIF}
-{$INCLUDE ../nogl/noGLuses.inc}
 {$IFDEF ENABLE_HOLMES}
   g_holmes, sdlcarcass, fui_ctls,
 {$ENDIF}
   SysUtils, Classes, MAPDEF, Math,
-  SDL2, e_graphics, e_log, e_texture, g_main,
+  e_graphics, e_log, e_texture, g_main,
   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, xprofiler,
-  g_touch, g_gui;
+  g_touch, g_gui, g_system;
 
 
 const
   ProgressUpdateMSecs = 35; //1;//100;
 
 var
-  h_Wnd: PSDL_Window = nil;
-  h_GL: TSDL_GLContext = nil;
   Time, Time_Delta, Time_Old: Int64;
   flag: Boolean;
-{$IF not DEFINED(HEADLESS)}
-  wTitle: PChar = nil;
-  wasFullscreen: Boolean = true; // so we need to recreate the window
-{$ENDIF}
   wNeedTimeReset: Boolean = false;
   wMinimized: Boolean = false;
   wMaximized: Boolean = false;
   wLoadingProgress: Boolean = false;
   wLoadingQuit: Boolean = false;
-{$IFNDEF WINDOWS}
-  ticksOverflow: Int64 = -1;
-  lastTicks: Uint32 = 0; // to detect overflow
-{$ENDIF}
-  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;
-
-procedure KillGLWindow (preserveGL: Boolean);
-begin
-{$IFDEF ENABLE_HOLMES}
-  if (h_GL <> nil) and (not preserveGL) then begin if (assigned(oglDeinitCB)) then oglDeinitCB(); end;
-{$ENDIF}
-  if (h_Wnd <> nil) then SDL_DestroyWindow(h_Wnd);
-  if (h_GL <> nil) and (not preserveGL) then
-  begin
-
-{$IFDEF USE_NANOGL}
-    nanoGL_Destroy;
-{$ENDIF}
-
-{$IFDEF USE_NOGL}
-    nogl_Quit;
-{$ENDIF}
-
-    SDL_GL_DeleteContext(h_GL);
-  end;
-  h_Wnd := nil;
-  if (not preserveGL) then h_GL := nil;
-end;
-
-
-function g_Window_SetDisplay (preserveGL: Boolean = false): Boolean;
-{$IF not DEFINED(HEADLESS)}
-var
-  mode, cmode: TSDL_DisplayMode;
-  wFlags: LongWord = 0;
-  nw, nh: Integer;
-{$ENDIF}
-begin
-{$IF not DEFINED(HEADLESS)}
-  result := false;
-
-  e_WriteLog('Setting display mode...', TMsgType.Notify);
-
-  wFlags := SDL_WINDOW_OPENGL {or SDL_WINDOW_RESIZABLE};
-  if gFullscreen then wFlags := wFlags {or SDL_WINDOW_FULLSCREEN} else wFlags := wFlags or SDL_WINDOW_RESIZABLE;
-  if (not gFullscreen) and (not preserveGL) and gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED else gWinMaximized := false;
-
-  if gFullscreen then
-  begin
-    mode.w := gScreenWidth;
-    mode.h := gScreenHeight;
-    mode.format := 0;
-    mode.refresh_rate := 0;
-    mode.driverdata := nil;
-    if (SDL_GetClosestDisplayMode(0, @mode, @cmode) = nil) then
-    begin
-      e_WriteLog('SDL: cannot find display mode for '+IntToStr(gScreenWidth), TMsgType.Notify);
-      gScreenWidth := 800;
-      gScreenHeight := 600;
-    end
-    else
-    begin
-      e_WriteLog('SDL: found display mode for '+IntToStr(gScreenWidth)+'x'+IntToStr(gScreenHeight)+': '+IntToStr(cmode.w)+'x'+IntToStr(cmode.h), TMsgType.Notify);
-      gScreenWidth := cmode.w;
-      gScreenHeight := cmode.h;
-    end;
-  end;
-
-  if (preserveGL) and (h_Wnd <> nil) and (not gFullscreen) and (not wasFullscreen) then
-  begin
-    //SDL_SetWindowMaximumSize(h_Wnd, gScreenWidth, gScreenHeight);
-    //SDL_SetWindowDisplayMode(h_Wnd, @cmode);
-    if (wMaximized) then SDL_RestoreWindow(h_Wnd);
-    wMaximized := false;
-    gWinMaximized := false;
-    SDL_SetWindowSize(h_Wnd, gScreenWidth, gScreenHeight);
-    //SDL_SetWindowFullscreen(h_Wnd, SDL_WINDOW_FULLSCREEN);
-    //SDL_SetWindowFullscreen(h_Wnd, 0);
-  end
-  else
-  begin
-    KillGLWindow(preserveGL);
-    h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
-    if gFullscreen then
-      SDL_SetWindowFullscreen(h_Wnd, SDL_WINDOW_FULLSCREEN);
-    if (h_Wnd = nil) then exit;
-  end;
-  wasFullscreen := gFullscreen;
-
-  SDL_GL_MakeCurrent(h_Wnd, h_GL);
-  SDL_ShowCursor(SDL_DISABLE);
-  if (h_GL <> nil) then g_SetVSync(gVSync);
-  if (gFullscreen) then
-  begin
-    nw := 0;
-    nh := 0;
-    SDL_GetWindowSize(h_Wnd, @nw, @nh);
-    if (nw > 128) and (nh > 128) then
-    begin
-      e_WriteLog('SDL: fullscreen window got size '+IntToStr(nw)+'x'+IntToStr(nh)+': '+IntToStr(gScreenWidth)+'x'+IntToStr(gScreenHeight), TMsgType.Notify);
-      gScreenWidth := nw;
-      gScreenHeight := nh;
-    end
-    else
-    begin
-      e_WriteLog('SDL: fullscreen window got invalid size: '+IntToStr(nw)+'x'+IntToStr(nh), TMsgType.Notify);
-    end;
-  end;
-
-  {$IFDEF ENABLE_HOLMES}
-    fuiScrWdt := gScreenWidth;
-    fuiScrHgt := gScreenHeight;
-    if (h_GL <> nil) and (not preserveGL) then begin if (assigned(oglInitCB)) then oglInitCB(); end;
-  {$ENDIF}
-{$ENDIF}
-
-  result := true;
-end;
-
-
-function GetDisplayModes (dbpp: LongWord; var selres: LongWord): SSArray;
-var
-  mode: TSDL_DisplayMode;
-  res, i, k, n, pw, ph: Integer;
-begin
-  SetLength(result, 0);
-  {$IFDEF HEADLESS}exit;{$ENDIF}
-  k := 0; selres := 0;
-  n := SDL_GetNumDisplayModes(0);
-  pw := 0; ph := 0;
-  for i := 0 to n do
-  begin
-    res := SDL_GetDisplayMode(0, i, @mode);
-    if res < 0 then continue;
-    if SDL_BITSPERPIXEL(mode.format) = gBPP then continue;
-    if (mode.w = pw) and (mode.h = ph) then continue;
-    if (mode.w = gScreenWidth) and (mode.h = gScreenHeight) then
-      selres := k;
-    Inc(k);
-    SetLength(result, k);
-    result[k-1] := IntToStr(mode.w) + 'x' + IntToStr(mode.h);
-    pw := mode.w; ph := mode.h
-  end;
-
-  e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', TMsgType.Notify);
-end;
-
-
-procedure Sleep (ms: LongWord);
-begin
-  SDL_Delay(ms);
-end;
-
-
-procedure ChangeWindowSize (requested: Boolean);
-begin
-  e_LogWritefln('  ChangeWindowSize: (ws=%dx%d) (ss=%dx%d)', [gWinSizeX, gWinSizeY, gScreenWidth, gScreenHeight]);
-  gWinSizeX := gScreenWidth;
-  gWinSizeY := gScreenHeight;
-{$IF not DEFINED(HEADLESS)}
-  {$IFDEF ENABLE_HOLMES}
-    fuiScrWdt := gScreenWidth;
-    fuiScrHgt := gScreenHeight;
-  {$ENDIF}
-  e_ResizeWindow(gScreenWidth, gScreenHeight);
-  g_Game_SetupScreenSize();
-  {$IF DEFINED(ANDROID)}
-    (* This will fix menu reset on keyboard showing *)
-    if requested then
-      g_Menu_Reset;
-  {$ELSE}
-    g_Menu_Reset;
-  {$ENDIF}
-  g_Game_ClearLoading();
-{$ENDIF}
-end;
-
-
-function g_Window_SetSize (w, h: Word; fullscreen: Boolean): Boolean;
-{$IF not DEFINED(HEADLESS)}
-var
-  preserve: Boolean;
-{$ENDIF}
-begin
-  result := false;
-{$IF not DEFINED(HEADLESS)}
-  preserve := false;
-
-  if (gScreenWidth <> w) or (gScreenHeight <> h) then
-  begin
-    result := true;
-    preserve := true;
-    gScreenWidth := w;
-    gScreenHeight := h;
-  end;
-
-  if (gFullscreen <> fullscreen) then
-  begin
-    result := true;
-    preserve := true;
-    gFullscreen := fullscreen;
-    preserve := true;
-  end;
-
-  if result then
-  begin
-    g_Window_SetDisplay(preserve);
-    ChangeWindowSize(true);
-  end;
-{$ENDIF}
-end;
-
-
-function WindowEventHandler (constref ev: TSDL_WindowEvent): Boolean;
-var
-  wActivate, wDeactivate: Boolean;
-begin
-  result := false;
-  wActivate := false;
-  wDeactivate := false;
-
-  case ev.event of
-    SDL_WINDOWEVENT_MOVED:
-    begin
-      if not (gFullscreen or gWinMaximized) then
-      begin
-        gWinRealPosX := ev.data1;
-        gWinRealPosY := ev.data2;
-      end;
-    end;
-
-    SDL_WINDOWEVENT_MINIMIZED:
-    begin
-      e_UnpressAllKeys();
-      if not wMinimized then
-      begin
-        e_ResizeWindow(0, 0);
-        wMinimized := true;
-        if g_debug_WinMsgs then
-        begin
-          g_Console_Add('Now minimized');
-          e_WriteLog('[DEBUG] WinMsgs: Now minimized', TMsgType.Notify);
-        end;
-        wDeactivate := true;
-      end;
-    end;
-
-    SDL_WINDOWEVENT_RESIZED:
-    begin
-      e_LogWritefln('Resize: (os=%dx%d) (ns=%dx%d)', [gScreenWidth, gScreenHeight, Integer(ev.data1), Integer(ev.data2)]);
-      {if (gFullscreen) then
-      begin
-        e_LogWriteln('  fullscreen fix applied.');
-        if (gScreenWidth <> ev.data1) or (gScreenHeight <> ev.data2) then
-        begin
-          SDL_SetWindowSize(h_Wnd, gScreenWidth, gScreenHeight);
-        end;
-      end
-      else}
-      begin
-        gScreenWidth := ev.data1;
-        gScreenHeight := ev.data2;
-      end;
-      ChangeWindowSize(false);
-      SwapBuffers();
-      if g_debug_WinMsgs then
-      begin
-        g_Console_Add('Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2));
-        e_WriteLog('[DEBUG] WinMsgs: Resized to ' + IntToStr(ev.data1) + 'x' + IntToStr(ev.data2), TMsgType.Notify);
-      end;
-    end;
-
-    SDL_WINDOWEVENT_EXPOSED:
-      SwapBuffers();
-
-    SDL_WINDOWEVENT_MAXIMIZED:
-    begin
-      wMaximized := true;
-      if wMinimized then
-      begin
-        e_ResizeWindow(gScreenWidth, gScreenHeight);
-        wMinimized := false;
-        wActivate := true;
-      end;
-      if (not gWinMaximized) and (not gFullscreen) then
-      begin
-        gWinMaximized := true;
-        if g_debug_WinMsgs then
-        begin
-          g_Console_Add('Now maximized');
-          e_WriteLog('[DEBUG] WinMsgs: Now maximized', TMsgType.Notify);
-        end;
-      end;
-    end;
-
-    SDL_WINDOWEVENT_RESTORED:
-    begin
-      wMaximized := false;
-      if wMinimized then
-      begin
-        e_ResizeWindow(gScreenWidth, gScreenHeight);
-        wMinimized := false;
-        wActivate := true;
-      end;
-      gWinMaximized := false;
-      if g_debug_WinMsgs then
-      begin
-        g_Console_Add('Now restored');
-        e_WriteLog('[DEBUG] WinMsgs: Now restored', TMsgType.Notify);
-      end;
-    end;
-
-    SDL_WINDOWEVENT_FOCUS_GAINED:
-    begin
-      wActivate := true;
-      //e_WriteLog('window gained focus!', MSG_NOTIFY);
-    end;
-
-    SDL_WINDOWEVENT_FOCUS_LOST:
-    begin
-      wDeactivate := true;
-      e_UnpressAllKeys();
-      //e_WriteLog('window lost focus!', MSG_NOTIFY);
-    end;
-  end;
-
-  if wDeactivate then
-  begin
-    if gWinActive then
-    begin
-      e_WriteLog('deactivating window', TMsgType.Notify);
-      e_UnpressAllKeys;
-
-      if gMuteWhenInactive then
-      begin
-        //e_WriteLog('deactivating sounds', MSG_NOTIFY);
-        e_MuteChannels(true);
-      end;
-
-      if g_debug_WinMsgs then
-      begin
-        g_Console_Add('Now inactive');
-        e_WriteLog('[DEBUG] WinMsgs: Now inactive', TMsgType.Notify);
-      end;
-
-      gWinActive := false;
-
-      {$IFDEF ENABLE_HOLMES}
-        if assigned(winBlurCB) then winBlurCB();
-      {$ENDIF}
-    end;
-  end
-  else if wActivate then
-  begin
-    if not gWinActive then
-    begin
-      //e_WriteLog('activating window', MSG_NOTIFY);
-
-      if gMuteWhenInactive then
-      begin
-        //e_WriteLog('activating sounds', MSG_NOTIFY);
-        e_MuteChannels(false);
-      end;
-
-      if g_debug_WinMsgs then
-      begin
-        g_Console_Add('Now active');
-        e_WriteLog('[DEBUG] WinMsgs: Now active', TMsgType.Notify);
-      end;
-
-      gWinActive := true;
-
-      {$IFDEF ENABLE_HOLMES}
-        if assigned(winFocusCB) then winFocusCB();
-      {$ENDIF}
-    end;
-  end;
-end;
-
-
-function EventHandler (var ev: TSDL_Event): Boolean;
-var
-  key, keychr, minuskey: Word;
-  uc: UnicodeChar;
-  down: Boolean;
-  i: Integer;
-  hat: array [HAT_LEFT..HAT_DOWN] of Boolean;
-begin
-  result := false;
-
-  case ev.type_ of
-    SDL_WINDOWEVENT:
-      result := WindowEventHandler(ev.window);
-
-    SDL_QUITEV:
-      begin
-        if (gExit <> EXIT_QUIT) then
-        begin
-          if not wLoadingProgress then
-          begin
-            g_Game_Free();
-            g_Game_Quit();
-          end
-          else
-          begin
-            wLoadingQuit := true;
-          end;
-        end;
-        result := true;
-      end;
-
-    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) and DEFINED(ENABLE_HOLMES)}
-        if fuiOnSDLEvent(ev) then
-        begin
-          // event eaten, but...
-          if not down then e_KeyUpDown(key, false);
-          exit;
-        end;
-        {$ENDIF}
-        if ev.key._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
-          // key repeat in menus and shit
-          KeyPress(key);
-        end;
-      end;
-
-    SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP:
-      if (ev.jbutton.which < e_MaxJoys) and (ev.jbutton.button < e_MaxJoyBtns) then
-      begin
-        key := e_JoyButtonToKey(ev.jbutton.which, ev.jbutton.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.jbutton.which, ev.jbutton.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.jbutton.which, ev.jbutton.button, down])
-        end
-      end;
-
-    SDL_JOYAXISMOTION:
-      if (ev.jaxis.which < e_MaxJoys) and (ev.jaxis.axis < e_MaxJoyAxes) then
-      begin
-        key := e_JoyAxisToKey(ev.jaxis.which, ev.jaxis.axis, AX_PLUS);
-        minuskey := e_JoyAxisToKey(ev.jaxis.which, ev.jaxis.axis, AX_MINUS);
-
-        if g_dbg_input then
-          e_LogWritefln('Input Debug: jaxis, joy=%s, axis=%s, value=%s, zeroaxes=%s, deadzone=%s', [ev.jaxis.which, ev.jaxis.axis, ev.jaxis.value, JoystickZeroAxes[ev.jaxis.which, ev.jaxis.axis], e_JoystickDeadzones[ev.jaxis.which]]);
-
-        if ev.jaxis.value < JoystickZeroAxes[ev.jaxis.which, ev.jaxis.axis] - e_JoystickDeadzones[ev.jaxis.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.jaxis.value > JoystickZeroAxes[ev.jaxis.which, ev.jaxis.axis] + e_JoystickDeadzones[ev.jaxis.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.jaxis.which, ev.jaxis.axis, ev.jaxis.value, JoystickZeroAxes[ev.jaxis.which, ev.jaxis.axis], e_JoystickDeadzones[ev.jaxis.which]])
-      end;
-
-    SDL_JOYHATMOTION:
-      if (ev.jhat.which < e_MaxJoys) and (ev.jhat.hat < e_MaxJoyHats) then
-      begin
-        if g_dbg_input then
-          e_LogWritefln('Input Debug: jhat, joy=%s, hat=%s, value=%s', [ev.jhat.which, ev.jhat.hat, ev.jhat.value]);
-        hat[HAT_UP] := LongBool(ev.jhat.value and SDL_HAT_UP);
-        hat[HAT_DOWN] := LongBool(ev.jhat.value and SDL_HAT_DOWN);
-        hat[HAT_LEFT] := LongBool(ev.jhat.value and SDL_HAT_LEFT);
-        hat[HAT_RIGHT] := LongBool(ev.jhat.value and SDL_HAT_RIGHT);
-        for i := HAT_LEFT to HAT_DOWN do
-        begin
-          if JoystickHatState[ev.jhat.which, ev.jhat.hat, i] <> hat[i] then
-          begin
-            down := hat[i];
-            key := e_JoyHatToKey(ev.jhat.which, ev.jhat.hat, i);
-            e_KeyUpDown(key, down);
-            g_Console_ProcessBind(key, down);
-          end
-        end;
-        JoystickHatState[ev.jhat.which, ev.jhat.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.jhat.which, ev.jhat.hat, ev.jhat.value])
-      end;
-
-    SDL_JOYDEVICEADDED:
-      if (ev.jdevice.which < e_MaxJoys) then
-      begin
-        JoystickHandle[ev.jdevice.which] := SDL_JoystickOpen(ev.jdevice.which);
-        if JoystickHandle[ev.jdevice.which] <> nil then
-        begin
-          e_LogWritefln('Added Joystick %s', [ev.jdevice.which]);
-          e_JoystickAvailable[ev.jdevice.which] := True;
-          for i := 0 to Min(SDL_JoystickNumAxes(JoystickHandle[ev.jdevice.which]), e_MaxJoyAxes) - 1 do
-            JoystickZeroAxes[ev.jdevice.which, i] := SDL_JoystickGetAxis(JoystickHandle[ev.jdevice.which], i)
-        end
-        else
-          e_LogWritefln('Warning! Failed to open Joystick %s', [ev.jdevice.which])
-      end
-      else
-      begin
-        e_LogWritefln('Warning! Added Joystick %s, but we support only <= %s', [ev.jdevice.which, e_MaxJoys])
-      end;
-
-    SDL_JOYDEVICEREMOVED:
-      begin
-        e_LogWritefln('Removed Joystick %s', [ev.jdevice.which]);
-        if (ev.jdevice.which < e_MaxJoys) then
-        begin
-          e_JoystickAvailable[ev.jdevice.which] := False;
-          if JoystickHandle[ev.jdevice.which] <> nil then
-            SDL_JoystickClose(JoystickHandle[ev.jdevice.which]);
-          JoystickHandle[ev.jdevice.which] := nil
-        end
-      end;
-
-    {$IF not DEFINED(HEADLESS) and DEFINED(ENABLE_HOLMES)}
-    SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL, SDL_MOUSEMOTION:
-      fuiOnSDLEvent(ev);
-    {$ENDIF}
-
-    SDL_TEXTINPUT:
-      begin
-        if g_dbg_input then
-          e_LogWritefln('Input Debug: text, text=%s', [ev.text.text]);
-        Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
-        keychr := Word(uc);
-        if (keychr > 127) then keychr := Word(wchar2win(WideChar(keychr)));
-        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;
-
-
-procedure SwapBuffers ();
-begin
-  {$IF not DEFINED(HEADLESS)}
-  SDL_GL_SwapWindow(h_Wnd);
-  {$ENDIF}
-end;
-
-
-function CreateGLWindow (Title: PChar): Boolean;
-begin
-  result := false;
-
-  gWinSizeX := gScreenWidth;
-  gWinSizeY := gScreenHeight;
-
-{$IF not DEFINED(HEADLESS)}
-  wTitle := Title;
-{$ENDIF}
-  e_WriteLog('Creating window', TMsgType.Notify);
-
-  if not g_Window_SetDisplay() then
-  begin
-    KillGLWindow(false);
-    e_WriteLog('Window creation error (resolution not supported?)', TMsgType.Fatal);
-    exit;
-  end;
-
-{$IF not DEFINED(HEADLESS)}
-  h_GL := SDL_GL_CreateContext(h_Wnd);
-  if (h_GL = nil) then exit;
-  {$IFDEF ENABLE_HOLMES}
-    fuiScrWdt := gScreenWidth;
-    fuiScrHgt := gScreenHeight;
-  {$ENDIF}
-  SDL_GL_MakeCurrent(h_Wnd, h_GL);
-{$IFDEF USE_NANOGL}
-  if nanoGL_Init() = 0 then
-  begin
-    KillGLWindow(false);
-    e_WriteLog('nanoGL initialization error', TMsgType.Fatal);
-    exit;
-  end;
-{$ENDIF}
-{$IFDEF USE_NOGL}
-  nogl_Init;
-{$ENDIF}
-  {$IFDEF ENABLE_HOLMES}
-    if (assigned(oglInitCB)) then oglInitCB();
-  {$ENDIF}
-  if (h_GL <> nil) then g_SetVSync(gVSync);
-{$ENDIF}
-
-  e_ResizeWindow(gScreenWidth, gScreenHeight);
-  e_InitGL();
-
-  result := true;
-end;
-
-
-{$IFDEF WINDOWS}
-// windoze sux; in headless mode `GetTickCount()` (and SDL) returns shit
-function GetTimer (): Int64;
-var
-  F, C: Int64;
-begin
-  QueryPerformanceFrequency(F);
-  QueryPerformanceCounter(C);
-  result := Round(C/F*1000{000});
-end;
-{$ELSE}
-function GetTimer (): Int64;
-var
-  t: Uint32;
-  tt: Int64;
-begin
-  t := SDL_GetTicks();
-  if (ticksOverflow = -1) then
-  begin
-    ticksOverflow := 0;
-    lastTicks := t;
-  end
-  else
-  begin
-    if (lastTicks > t) then
-    begin
-      // overflow, increment overflow ;-)
-      ticksOverflow := ticksOverflow+(Int64($ffffffff)+Int64(1));
-      tt := (Int64($ffffffff)+Int64(1))+Int64(t);
-      t := Uint32(tt-lastTicks);
-    end;
-  end;
-  lastTicks := t;
-  result := ticksOverflow+Int64(t);
-end;
-{$ENDIF}
-
 
 procedure ResetTimer ();
 begin
   wNeedTimeReset := true;
 end;
 
-
-procedure PushExitEvent ();
-var
-  ev: TSDL_Event;
-begin
-  ev.type_ := SDL_QUITEV;
-  SDL_PushEvent(@ev);
-end;
-
-
 {$IFNDEF HEADLESS}
 var
   prevLoadingUpdateTime: UInt64 = 0;
@@ -789,26 +70,26 @@ var
 
 procedure ProcessLoading (forceUpdate: Boolean=false);
 var
-  ev: TSDL_Event;
 {$IFNDEF HEADLESS}
+//  ev: TSDL_Event;
   stt: UInt64;
 {$ENDIF}
 begin
-  FillChar(ev, sizeof(ev), 0);
+//  FillChar(ev, sizeof(ev), 0);
   wLoadingProgress := true;
 
-  while (SDL_PollEvent(@ev) > 0) do
-  begin
-    EventHandler(ev);
-    if (ev.type_ = SDL_QUITEV) then break;
-  end;
+//  while (SDL_PollEvent(@ev) > 0) do
+//  begin
+//    EventHandler(ev);
+//    if (ev.type_ = SDL_QUITEV) then break;
+//  end;
   //e_PollJoysticks();
 
-  if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
-  begin
-    wLoadingProgress := false;
-    exit;
-  end;
+//  if (ev.type_ = SDL_QUITEV) or (gExit = EXIT_QUIT) then
+//  begin
+//    wLoadingProgress := false;
+//    exit;
+//  end;
 
 {$IFNDEF HEADLESS}
   if not wMinimized then
@@ -826,7 +107,7 @@ begin
 
       DrawLoadingStat();
       g_Console_Draw(True);
-      SwapBuffers();
+      sys_Repaint;
       prevLoadingUpdateTime := getTimeMilli();
     end;
   end;
@@ -847,28 +128,13 @@ begin
 end;
 
 
-function g_ProcessMessages (): Boolean;
-var
-  ev: TSDL_Event;
-begin
-  result := false;
-  FillChar(ev, SizeOf(ev), 0);
-  while (SDL_PollEvent(@ev) > 0) do
-  begin
-    result := EventHandler(ev);
-    if (ev.type_ = SDL_QUITEV) then exit;
-  end;
-  //e_PollJoysticks();
-end;
-
-
 function ProcessMessage (): Boolean;
 var
   i, t: Integer;
 begin
-  result := g_ProcessMessages();
+  result := sys_HandleInput();
 
-  Time := GetTimer();
+  Time := sys_GetTicks();
   Time_Delta := Time-Time_Old;
 
   flag := false;
@@ -919,111 +185,21 @@ begin
   // Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ
   if flag then
   begin
-    Time_Old := Time-(Time_Delta mod 28);
+    Time_Old := Time - (Time_Delta mod 28);
     if (not wMinimized) then
     begin
-      Draw();
-      SwapBuffers();
-    end;
+      Draw;
+      sys_Repaint
+    end
   end
   else
   begin
-    Sleep(1); // release time slice, so we won't eat 100% CPU
+    sys_Delay(1) // release time slice, so we won't eat 100% CPU
   end;
 
   e_SoundUpdate();
 end;
 
-
-procedure ReDrawWindow ();
-begin
-  SwapBuffers();
-end;
-
-
-procedure g_SetVSync (vsync: Boolean);
-{$IF not DEFINED(HEADLESS)}
-var
-  v: Byte;
-{$ENDIF}
-begin
-{$IF not DEFINED(HEADLESS)}
-  if vsync then v := 1 else v := 0;
-  if (SDL_GL_SetSwapInterval(v) <> 0) then
-  begin
-    e_WriteLog('oops; can''t change vsync option, restart required', TMsgType.Warning);
-  end
-  else
-  begin
-    if vsync then e_WriteLog('VSync: ON', TMsgType.Notify) else e_WriteLog('VSync: OFF', TMsgType.Notify);
-  end;
-{$ENDIF}
-end;
-
-
-procedure InitOpenGL ();
-begin
-{$IF not DEFINED(HEADLESS)}
-  {$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}
-{$ENDIF}
-end;
-
-
-function glHasExtension (const name: AnsiString): Boolean;
-var
-  exts: PChar;
-  i: Integer;
-  found: Boolean;
-  extName: ShortString;
-begin
-  result := false;
-  if (Length(name) = 0) then exit;
-  exts := glGetString(GL_EXTENSIONS);
-  if (exts = nil) then exit;
-  while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
-  while (exts[0] <> #0) do
-  begin
-    if gwin_dump_extensions then
-    begin
-      i := 0;
-      while (exts[i] <> #0) and (exts[i] <> ' ') do Inc(i);
-      if i > 255 then
-      begin
-        e_WriteLog('FUUUUUUUUUUUUU', TMsgType.Warning);
-      end
-      else
-      begin
-        Move(exts^, extName[1], i);
-        extName[0] := Char(i);
-        e_WriteLog(Format('EXT: %s', [extName]), TMsgType.Notify);
-      end;
-    end;
-    found := true;
-    for i := 0 to length(name)-1 do
-    begin
-      if (exts[i] = #0) then begin found := false; break; end;
-      if (exts[i] <> name[i+1]) then begin found := false; break; end;
-    end;
-    if found and ((exts[Length(name)] = #0) or (exts[Length(name)] = ' ')) then begin result := true; exit; end;
-    while (exts[0] <> #0) and (exts[0] <> ' ') do Inc(exts);
-    while (exts[0] <> #0) and (exts[0] = ' ') do Inc(exts);
-  end;
-end;
-
-
 function SDLMain (): Integer;
 var
   idx: Integer;
@@ -1132,45 +308,8 @@ begin
     end;
   end;
 
-  e_WriteLog('Initializing OpenGL', TMsgType.Notify);
-  InitOpenGL();
-
-  e_WriteLog('Creating GL window', TMsgType.Notify);
-  if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
-  begin
-    result := 0;
-    e_WriteLog('Unable to create GL window: ' + SDL_GetError(), TMsgType.Fatal);
-    exit;
-  end;
-
-  {EnumDisplayModes();}
-
-{$IFDEF HEADLESS}
-  //gwin_k8_enable_light_experiments := false;
-  gwin_has_stencil := false;
-  glLegacyNPOT := false;
-  gwin_dump_extensions := false;
-{$ELSE}
-  SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, @ltmp);
-  e_LogWritefln('stencil buffer size: %s', [ltmp]);
-  gwin_has_stencil := (ltmp > 0);
-
-  if glHasExtension('GL_ARB_texture_non_power_of_two') or
-     glHasExtension('GL_OES_texture_npot') then
-  begin
-    e_WriteLog('NPOT textures: YES', TMsgType.Notify);
-    glLegacyNPOT := false;
-  end
-  else
-  begin
-    e_WriteLog('NPOT textures: NO', TMsgType.Warning);
-    glLegacyNPOT := true;
-  end;
-  gwin_dump_extensions := false;
-{$ENDIF}
-
-  Init();
-  Time_Old := GetTimer();
+  Init;
+  Time_Old := sys_GetTicks();
 
   // Êîìàíäíàÿ ñòðîêà
   if (ParamCount > 0) then g_Game_Process_Params();
@@ -1186,8 +325,6 @@ begin
   while not ProcessMessage() do begin end;
 
   Release();
-  KillGLWindow(false);
-
   result := 0;
 end;
 
diff --git a/src/game/sdl/g_system.pas b/src/game/sdl/g_system.pas
new file mode 100644 (file)
index 0000000..a72f658
--- /dev/null
@@ -0,0 +1,301 @@
+(* 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
+
+  (* To fix:
+   *   - Text input
+   *   - Joystick support
+   *   - Window resizing using SDL_VIDEORESIZE
+   *)
+
+  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, SDL, GL,
+    e_log, e_graphics, e_input,
+    g_options, g_window, g_console, g_game, g_menu;
+
+  var
+    screen: PSDL_Surface;
+
+  (* --------- 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;
+    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...
+    flags := SDL_OPENGL or SDL_VIDEORESIZE;
+    if fullScreen then
+      flags := flags or SDL_FULLSCREEN;
+    if (screen = nil) or (SDL_VideoModeOk(w, h, bpp, flags) <> 0) then
+    begin
+      SDL_FreeSurface(screen);
+      screen := SDL_SetVideoMode(w, h, bpp, flags);
+      if screen <> nil then
+      begin
+        SDL_WM_SetCaption('Doom 2D: Forever (SDL 1.2)', nil);
+        UpdateSize(w, h);
+        Result := True
+      end
+    end
+    else
+    begin
+      e_LogWritefln('SDL: video mode not supported', [])
+    end
+  end;
+
+  procedure sys_Repaint;
+  begin
+    SDL_GL_SwapBuffers
+  end;
+
+  procedure sys_EnableVSync (yes: Boolean);
+  begin
+    (* ??? *)
+  end;
+
+  function sys_GetDispalyModes (bpp: Integer): SSArray;
+    var m: PPSDL_Rect; f: TSDL_PixelFormat; i, count: Integer;
+  begin
+    SetLength(result, 0);
+    FillChar(f, sizeof(f), 0);
+    f.palette := nil;
+    f.BitsPerPixel := bpp;
+    f.BytesPerPixel := (bpp + 7) div 8;
+    m := SDL_ListModes(@f, SDL_OPENGL or SDL_FULLSCREEN);
+    if (m <> NIL) and (IntPtr(m) <> -1) then
+    begin
+      count := 0;
+      while m[count] <> nil do inc(count);
+      SetLength(result, count);
+      for i := 0 to count - 1 do
+        result[i] := IntToStr(m[i].w) + 'x' + IntToStr(m[i].h);
+    end
+  end;
+
+  function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
+  begin
+    result := InitWindow(w, h, bpp, fullscreen)
+  end;
+
+  (* --------- Input --------- *)
+
+  function Key2Stub (key: Integer): Integer;
+    var x: Integer;
+  begin
+    case key of
+      SDLK_ESCAPE: x := IK_ESCAPE;
+      SDLK_RETURN: x := IK_RETURN;
+      SDLK_KP_ENTER: x := IK_KPRETURN;
+      SDLK_KP0: x := IK_KPINSERT;
+      SDLK_UP: x := IK_UP;
+      SDLK_KP8: x := IK_KPUP;
+      SDLK_DOWN: x := IK_DOWN;
+      SDLK_KP2: x := IK_KPDOWN;
+      SDLK_LEFT: x := IK_LEFT;
+      SDLK_KP4: x := IK_KPLEFT;
+      SDLK_RIGHT: x := IK_RIGHT;
+      SDLK_KP6: x := IK_KPRIGHT;
+      SDLK_DELETE: x := IK_DELETE;
+      SDLK_HOME: x := IK_HOME;
+      SDLK_KP7: x := IK_KPHOME;
+      SDLK_INSERT: x := IK_INSERT;
+      SDLK_SPACE: x := IK_SPACE;
+      SDLK_LSHIFT: x := IK_SHIFT;
+      SDLK_LALT: x := IK_ALT;
+      SDLK_TAB: x := IK_TAB;
+      SDLK_PAGEUP: x := IK_PAGEUP;
+      SDLK_KP9: x := IK_KPPAGEUP;
+      SDLK_PAGEDOWN: x := IK_PAGEDN;
+      SDLK_KP3: x := IK_KPPAGEDN;
+      SDLK_KP5: x := IK_KP5;
+      SDLK_NUMLOCK: x := IK_NUMLOCK;
+      SDLK_KP_DIVIDE: x := IK_KPDIVIDE;
+      SDLK_KP_MULTIPLY: x := IK_KPMULTIPLE;
+      SDLK_KP_MINUS: x := IK_KPMINUS;
+      SDLK_KP_PLUS: x := IK_KPPLUS;
+      SDLK_KP_PERIOD: x := IK_KPDOT;
+      SDLK_CAPSLOCK: x := IK_CAPSLOCK;
+      SDLK_RSHIFT: x := IK_RSHIFT;
+      SDLK_LCTRL: x := IK_CTRL;
+      SDLK_RCTRL: x := IK_RCTRL;
+      SDLK_RALT: x := IK_RALT;
+      SDLK_LSUPER: x := IK_WIN;
+      SDLK_RSUPER: x := IK_RWIN;
+      SDLK_MENU: x := IK_MENU;
+      SDLK_PRINT: x := IK_PRINTSCR;
+      SDLK_SCROLLOCK: x := IK_SCROLLLOCK;
+      SDLK_LEFTBRACKET: x := IK_LBRACKET;
+      SDLK_RIGHTBRACKET: x := IK_RBRACKET;
+      SDLK_SEMICOLON: x := IK_SEMICOLON;
+      SDLK_QUOTE: x := IK_QUOTE;
+      SDLK_BACKSLASH: x := IK_BACKSLASH;
+      SDLK_SLASH: x := IK_SLASH;
+      SDLK_COMMA: x := IK_COMMA;
+      SDLK_PERIOD: x := IK_DOT;
+      SDLK_EQUALS: x := IK_EQUALS;
+      SDLK_0: x := IK_0;
+      SDLK_1: x := IK_1;
+      SDLK_2: x := IK_2;
+      SDLK_3: x := IK_3;
+      SDLK_4: x := IK_4;
+      SDLK_5: x := IK_5;
+      SDLK_6: x := IK_6;
+      SDLK_7: x := IK_7;
+      SDLK_8: x := IK_8;
+      SDLK_9: x := IK_9;
+      SDLK_F1: x := IK_F1;
+      SDLK_F2: x := IK_F2;
+      SDLK_F3: x := IK_F3;
+      SDLK_F4: x := IK_F4;
+      SDLK_F5: x := IK_F5;
+      SDLK_F6: x := IK_F6;
+      SDLK_F7: x := IK_F7;
+      SDLK_F8: x := IK_F8;
+      SDLK_F9: x := IK_F9;
+      SDLK_F10: x := IK_F10;
+      SDLK_F11: x := IK_F11;
+      SDLK_F12: x := IK_F12;
+      SDLK_END: x := IK_END;
+      SDLK_KP1: x := IK_KPEND;
+      SDLK_BACKSPACE: x := IK_BACKSPACE;
+      SDLK_BACKQUOTE: x := IK_BACKQUOTE;
+      SDLK_PAUSE: x := IK_PAUSE;
+      SDLK_A..SDLK_Z: x := IK_A + (key - SDLK_A);
+      SDLK_MINUS: x := IK_MINUS;
+    else
+      x := IK_INVALID
+    end;
+    result := x
+  end;
+
+  procedure HandleKeyboard (var ev: TSDL_KeyboardEvent);
+    var down: Boolean; key, stb: Integer;
+  begin
+    down := (ev.type_ = SDL_KEYDOWN);
+    key := ev.keysym.sym;
+    stb := Key2Stub(key);
+    if g_dbg_input then
+      e_LogWritefln('Input Debug: keysym, press=%s, scancode=%s SDL.ev.key.state=%s', [down, key, ev.state]);
+    e_KeyUpDown(stb, down);
+    g_Console_ProcessBind(stb, down);
+    (* !!! need text input -- console, cheaats, fields *)
+  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_VIDEORESIZE: InitWindow(ev.resize.w, ev.resize.h, gBPP, gFullscreen);
+        SDL_KEYUP, SDL_KEYDOWN: HandleKeyboard(ev.key);
+      end
+    end
+  end;
+
+  procedure sys_RequestQuit;
+    var ev: TSDL_Event;
+  begin
+    ev.quit.type_ := SDL_QUITEV;
+    SDL_PushEvent(@ev)
+  end;
+
+  (* --------- Init --------- *)
+
+  procedure sys_Init;
+    var flags: Uint32; ok: Boolean;
+  begin
+    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());
+    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 SDL', TMsgType.Notify);
+    SDL_FreeSurface(screen);
+    SDL_Quit
+  end;
+
+end.
diff --git a/src/game/sdl/g_touch.pas b/src/game/sdl/g_touch.pas
new file mode 100644 (file)
index 0000000..d07de41
--- /dev/null
@@ -0,0 +1,53 @@
+(* 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
+
+  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_Draw;
+
+implementation
+
+  uses g_console;
+
+  procedure g_Touch_Init;
+  begin
+  end;
+
+  procedure g_Touch_ShowKeyboard(yes: Boolean);
+  begin
+  end;
+
+  procedure g_Touch_Draw;
+  begin
+  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.
diff --git a/src/game/stub/g_system.pas b/src/game/stub/g_system.pas
new file mode 100644 (file)
index 0000000..84ae121
--- /dev/null
@@ -0,0 +1,94 @@
+(* 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
+
+  (* --------- Utils --------- *)
+
+  function sys_GetTicks (): Int64;
+  begin
+    Result := 0
+  end;
+
+  procedure sys_Delay (ms: Integer);
+  begin
+  end;
+
+  (* --------- Graphics --------- *)
+
+  procedure sys_Repaint;
+  begin
+  end;
+
+  procedure sys_EnableVSync (yes: Boolean);
+  begin
+  end;
+
+  function sys_GetDispalyModes (bpp: Integer): SSArray;
+  begin
+    SetLength(result, 0);
+  end;
+
+  function sys_SetDisplayMode (w, h, bpp: Integer; fullscreen: Boolean): Boolean;
+  begin
+    result := True
+  end;
+
+  (* --------- Input --------- *)
+
+  function sys_HandleInput (): Boolean;
+  begin
+    result := false
+  end;
+
+  procedure sys_RequestQuit;
+  begin
+  end;
+
+  (* --------- Init --------- *)
+
+  procedure sys_Init;
+  begin
+  end;
+
+  procedure sys_Final;
+  begin
+  end;
+
+end.
diff --git a/src/game/stub/g_touch.pas b/src/game/stub/g_touch.pas
new file mode 100644 (file)
index 0000000..d07de41
--- /dev/null
@@ -0,0 +1,53 @@
+(* 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
+
+  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_Draw;
+
+implementation
+
+  uses g_console;
+
+  procedure g_Touch_Init;
+  begin
+  end;
+
+  procedure g_Touch_ShowKeyboard(yes: Boolean);
+  begin
+  end;
+
+  procedure g_Touch_Draw;
+  begin
+  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 be2a86a28d68881d128e8ce49d47883bf04db57a..5e6212b921b5b7ddc04784ad9d601503b3d93483 100644 (file)
@@ -21,6 +21,12 @@ interface
 
 {$IFNDEF IN_TOOLS}
   uses
+  {$IFDEF USE_SDL}
+    SDL,
+  {$ENDIF}
+  {$IFDEF USE_SDL2}
+    SDL2,
+  {$ENDIF}
     SysUtils;
 
   {$DEFINE STOPWATCH_IS_HERE}
@@ -46,6 +52,11 @@ interface
   ;
 {$ENDIF} // IN_TOOLS
 
+{$IFDEF USE_SDL}
+  type
+    UInt64 = QWord; (* !!! *)
+{$ENDIF}
+
 {$IF DEFINED(STOPWATCH_IS_HERE)}
 type
   TStopWatch = record
@@ -160,9 +171,6 @@ function getTimeMilli (): UInt64; inline;
 implementation
 
 {$IFNDEF IN_TOOLS}
-uses
-  SDL2;
-
 type
   THPTimeType = Int64;
 {$ELSE}
@@ -205,7 +213,7 @@ begin
 end;
 
 
-{$IFDEF IN_TOOLS}
+{$IF DEFINED(IN_TOOLS)}
 function getTimeMicro (): UInt64; inline;
 var
   r: THPTimeType;
@@ -219,17 +227,30 @@ begin
   result := UInt64(r)*1000000 div mFrequency;
   {$ENDIF}
 end;
-{$ELSE}
+(* !!!
+{$ELSEIF DEFINED(USE_SDL)}
+function getTimeMicro: UInt64; inline;
+begin
+  {$WARNING use inaccurate profiling timer}
+  result := SDL_GetTicks() * 1000
+end;
+*)
+{$ELSEIF DEFINED(USE_SDL2)}
 function getTimeMicro (): UInt64; inline;
 begin
   Result := SDL_GetPerformanceCounter() * 1000000 div SDL_GetPerformanceFrequency()
 end;
+{$ELSE}
+function getTimeMicro: UInt64; inline;
+begin
+  {$WARNING use stub profiling timer}
+end;
 {$ENDIF}
 
 
 function getTimeMilli (): UInt64; inline;
 begin
-  result := getTimeMicro div 1000;
+  result := getTimeMicro() div 1000;
 end;