diff --git a/src/game/g_window.pas b/src/game/g_window.pas
index bb20c47dd3feba89956de37b19402342bcbdecc8..5e7e926727f3989e0db09c1867e9750930e65c0b 100644 (file)
--- a/src/game/g_window.pas
+++ b/src/game/g_window.pas
+{$MODE DELPHI}
unit g_window;
interface
uses
unit g_window;
interface
uses
- WADEDITOR;
+ wadreader;
function SDLMain(): Integer;
function GetTimer(): Int64;
function SDLMain(): Integer;
function GetTimer(): Int64;
implementation
uses
implementation
uses
- SDL, GL, GLExt, e_graphics, e_log, g_main,
+{$IFDEF WINDOWS}Windows,{$ENDIF}
+ SDL2, GL, GLExt, e_graphics, e_log, g_main,
g_console, SysUtils, e_input, g_options, g_game,
g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net;
var
g_console, SysUtils, e_input, g_options, g_game,
g_basic, g_textures, e_sound, g_sound, g_menu, ENet, g_net;
var
- h_Wnd: PSDL_Surface;
+ h_Wnd: PSDL_Window;
+ h_GL: TSDL_GLContext;
wFlags: LongWord = 0;
Time, Time_Delta, Time_Old: Int64;
flag: Boolean;
wFlags: LongWord = 0;
Time, Time_Delta, Time_Old: Int64;
flag: Boolean;
+ wTitle: PChar = nil;
wNeedTimeReset: Boolean = False;
wNeedTimeReset: Boolean = False;
- wWindowCreated: Boolean = False;
+ //wWindowCreated: Boolean = False;
//wCursorShown: Boolean = False;
wMinimized: Boolean = False;
//wNeedFree: Boolean = True;
wLoadingProgress: Boolean = False;
wLoadingQuit: Boolean = False;
{wWinPause: Byte = 0;}
//wCursorShown: Boolean = False;
wMinimized: Boolean = False;
//wNeedFree: Boolean = True;
wLoadingProgress: Boolean = False;
wLoadingQuit: Boolean = False;
{wWinPause: Byte = 0;}
+{$IFNDEF WINDOWS}
+ ticksOverflow: Int64 = -1;
+ lastTicks: Uint32 = 0; // to detect overflow
+{$ENDIF}
const
// TODO: move this to a separate file
const
// TODO: move this to a separate file
// TODO: make a transition table or something
function WCharToCP1251(wc: Word): Word;
// TODO: make a transition table or something
function WCharToCP1251(wc: Word): Word;
+var
+ n: Word;
begin
begin
- for Result := 0 to 127 do
- if CP1251[Result] = wc then
- break;
+ Result := 0;
+ for n := 0 to 127 do
+ if CP1251[n] = wc then begin Result := n; break end;
Result := Result + 128;
end;
function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
Result := Result + 128;
end;
function g_Window_SetDisplay(PreserveGL: Boolean = False): Boolean;
+var
+ mode, cmode: TSDL_DisplayMode;
begin
begin
+{$IFDEF HEADLESS}
+ Result := True;
+ Exit;
+{$ENDIF}
+
Result := False;
e_WriteLog('Setting display mode...', MSG_NOTIFY);
Result := False;
e_WriteLog('Setting display mode...', MSG_NOTIFY);
- if wWindowCreated and PreserveGL then
- e_SaveGLContext(); // we need this and restore because of a bug in SDL1.2, apparently
+ wFlags := SDL_WINDOW_OPENGL or SDL_WINDOW_RESIZABLE;
+ if gFullscreen then wFlags := wFlags or SDL_WINDOW_FULLSCREEN;
+ if gWinMaximized then wFlags := wFlags or SDL_WINDOW_MAXIMIZED;
- wFlags := SDL_RESIZABLE or SDL_OPENGL;
- if gFullscreen then wFlags := wFlags or SDL_FULLSCREEN;
+ if h_Wnd <> nil then
+ begin
+ SDL_DestroyWindow(h_Wnd);
+ h_Wnd := nil;
+ end;
- h_Wnd := SDL_SetVideoMode(gScreenWidth, gScreenHeight, gBPP, wFlags);
- SDL_EnableUNICODE(SDL_ENABLE);
- SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
- SDL_ShowCursor(SDL_DISABLE);
+ 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
+ gScreenWidth := 800;
+ gScreenHeight := 600;
+ end
+ else
+ begin
+ gScreenWidth := cmode.w;
+ gScreenHeight := cmode.h;
+ end;
+ end;
+
+ h_Wnd := SDL_CreateWindow(PChar(wTitle), gWinRealPosX, gWinRealPosY, gScreenWidth, gScreenHeight, wFlags);
+ if h_Wnd = nil then Exit;
- if wWindowCreated and PreserveGL then
- e_RestoreGLContext();
+ SDL_GL_MakeCurrent(h_Wnd, h_GL);
+ SDL_ShowCursor(SDL_DISABLE);
- Result := h_Wnd <> nil;
+ Result := True;
end;
procedure ReShowCursor();
end;
procedure ReShowCursor();
function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
var
function GetDisplayModes(dBPP: DWORD; var SelRes: DWORD): SArray;
var
- modesp: PPSDL_Rect;
- tmpp: PSDL_Rect;
- tmpr: SDL_Rect;
- i: Integer;
+ mode: TSDL_DisplayMode;
+ res, i, k, n, pw, ph: Integer;
begin
SetLength(Result, 0);
begin
SetLength(Result, 0);
- modesp := SDL_ListModes(nil, SDL_FULLSCREEN or SDL_HWSURFACE);
- if modesp = nil then exit;
- if Pointer(-1) = modesp then exit;
-
- tmpp := modesp^;
- i := 0;
- while tmpp <> nil do
+ {$IFDEF HEADLESS}Exit;{$ENDIF}
+ k := 0; SelRes := 0;
+ n := SDL_GetNumDisplayModes(0);
+ pw := 0; ph := 0;
+ for i := 0 to n do
begin
begin
- tmpr := tmpp^;
- if (tmpr.w = gScreenWidth) and (tmpr.h = gScreenHeight) then
- SelRes := i;
- SetLength(Result, Length(Result) + 1);
- Result[i] := IntToStr(tmpr.w) + 'x' + IntToStr(tmpr.h);
-
- modesp := Pointer(Cardinal(modesp) + SizeOf(PSDL_Rect));
- tmpp := modesp^;
- Inc(i);
+ 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;
end;
- e_WriteLog('SDL: Got ' + IntToStr(Length(Result)) + ' resolutions.', MSG_NOTIFY);
+ e_WriteLog('SDL: Got ' + IntToStr(k) + ' resolutions.', MSG_NOTIFY);
end;
procedure Sleep(ms: LongWord);
end;
procedure Sleep(ms: LongWord);
begin
gWinSizeX := gScreenWidth;
gWinSizeY := gScreenHeight;
begin
gWinSizeX := gScreenWidth;
gWinSizeY := gScreenHeight;
+ {$IFDEF HEADLESS}Exit;{$ENDIF}
e_ResizeWindow(gScreenWidth, gScreenHeight);
g_Game_SetupScreenSize();
g_Menu_Reset();
e_ResizeWindow(gScreenWidth, gScreenHeight);
g_Game_SetupScreenSize();
g_Menu_Reset();
Preserve: Boolean;
begin
Result := False;
Preserve: Boolean;
begin
Result := False;
+ {$IFDEF HEADLESS}Exit;{$ENDIF}
Preserve := False;
if (gScreenWidth <> W) or (gScreenHeight <> H) then
Preserve := False;
if (gScreenWidth <> W) or (gScreenHeight <> H) then
end;
end;
end;
end;
-function EventHandler(ev: TSDL_Event): Boolean;
+function WindowEventHandler(ev: TSDL_WindowEvent): Boolean;
var
var
- key, keychr: Word;
- //joy: Integer;
+ wActivate, wDeactivate: Boolean;
begin
Result := False;
begin
Result := False;
- case ev.type_ of
- SDL_VIDEORESIZE:
+ wActivate := False;
+ wDeactivate := False;
+
+ case ev.event of
+ SDL_WINDOWEVENT_MOVED:
begin
begin
- g_Window_SetSize(ev.resize.w, ev.resize.h, gFullscreen);
- e_Clear();
+ if not (gFullscreen or gWinMaximized) then
+ begin
+ gWinRealPosX := ev.data1;
+ gWinRealPosY := ev.data2;
+ end;
end;
end;
- SDL_ACTIVEEVENT:
+ SDL_WINDOWEVENT_MINIMIZED:
begin
begin
- if (ev.active.gain = 0) then
+ if not wMinimized then
begin
begin
+ e_ResizeWindow(0, 0);
+ wMinimized := True;
+
if g_debug_WinMsgs then
begin
if g_debug_WinMsgs then
begin
- g_Console_Add('Inactive');
- e_WriteLog('[DEBUG] WinMsgs: Inactive', MSG_NOTIFY);
+ g_Console_Add('Now minimized');
+ e_WriteLog('[DEBUG] WinMsgs: Now minimized', MSG_NOTIFY);
end;
end;
+ wDeactivate := True;
+ end;
+ end;
- if LongBool(ev.active.state and SDL_APPINPUTFOCUS) and gWinActive then
- begin
- e_EnableInput := False;
- e_ClearInputBuffer();
-
- if gMuteWhenInactive then
- e_MuteChannels(True);
-
- if g_debug_WinMsgs then
- begin
- g_Console_Add('Inactive indeed');
- e_WriteLog('[DEBUG] WinMsgs: Inactive indeed', MSG_NOTIFY);
- end;
+ SDL_WINDOWEVENT_RESIZED:
+ begin
+ gScreenWidth := ev.data1;
+ gScreenHeight := ev.data2;
+ ChangeWindowSize();
+ 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), MSG_NOTIFY);
+ end;
+ end;
- gWinActive := False;
- end;
+ SDL_WINDOWEVENT_EXPOSED:
+ SwapBuffers();
- if LongBool(ev.active.state and SDL_APPACTIVE) and (not wMinimized) then
- begin
- e_ResizeWindow(0, 0);
- wMinimized := True;
-
- if g_debug_WinMsgs then
- begin
- g_Console_Add('Minimized indeed');
- e_WriteLog('[DEBUG] WinMsgs: Minimized indeed', MSG_NOTIFY);
- end;
- end;
- end
- else
+ SDL_WINDOWEVENT_MAXIMIZED:
+ begin
+ if wMinimized then
+ begin
+ e_ResizeWindow(gScreenWidth, gScreenHeight);
+ wMinimized := False;
+ wActivate := True;
+ end;
+ if not gWinMaximized then
begin
begin
+ gWinMaximized := True;
if g_debug_WinMsgs then
begin
if g_debug_WinMsgs then
begin
- g_Console_Add('Active');
- e_WriteLog('[DEBUG] WinMsgs: Active', MSG_NOTIFY);
+ g_Console_Add('Now maximized');
+ e_WriteLog('[DEBUG] WinMsgs: Now maximized', MSG_NOTIFY);
end;
end;
+ end;
+ end;
- // Åñëè îêíî áûëî íåàêòèâíûì:
- if LongBool(ev.active.state and SDL_APPINPUTFOCUS) and (not gWinActive) then
- begin
- e_EnableInput := True;
-
- if gMuteWhenInactive then
- e_MuteChannels(False);
+ SDL_WINDOWEVENT_RESTORED:
+ begin
+ if wMinimized then
+ begin
+ e_ResizeWindow(gScreenWidth, gScreenHeight);
+ wMinimized := False;
+ wActivate := True;
+ end;
+ if gWinMaximized then
+ gWinMaximized := False;
+ if g_debug_WinMsgs then
+ begin
+ g_Console_Add('Now restored');
+ e_WriteLog('[DEBUG] WinMsgs: Now restored', MSG_NOTIFY);
+ end;
+ end;
- if g_debug_WinMsgs then
- begin
- g_Console_Add('Active indeed');
- e_WriteLog('[DEBUG] WinMsgs: Active indeed', MSG_NOTIFY);
- end;
+ SDL_WINDOWEVENT_FOCUS_GAINED:
+ begin
+ wActivate := True;
+ //e_WriteLog('window gained focus!', MSG_NOTIFY);
+ end;
- gWinActive := True;
- end;
+ SDL_WINDOWEVENT_FOCUS_LOST:
+ begin
+ wDeactivate := True;
+ //e_WriteLog('window lost focus!', MSG_NOTIFY);
+ end;
+ end;
- if LongBool(ev.active.state and SDL_APPACTIVE) and wMinimized then
- begin
- e_ResizeWindow(gScreenWidth, gScreenHeight);
+ if wDeactivate then
+ begin
+ if gWinActive then
+ begin
+ e_WriteLog('deactivating window', MSG_NOTIFY);
+ e_EnableInput := False;
+ e_ClearInputBuffer();
- wMinimized := False;
+ if gMuteWhenInactive then
+ begin
+ //e_WriteLog('deactivating sounds', MSG_NOTIFY);
+ e_MuteChannels(True);
+ end;
- if g_debug_WinMsgs then
- begin
- g_Console_Add('Restored indeed');
- e_WriteLog('[DEBUG] WinMsgs: Restored indeed', MSG_NOTIFY);
- end;
- end;
+ if g_debug_WinMsgs then
+ begin
+ g_Console_Add('Now inactive');
+ e_WriteLog('[DEBUG] WinMsgs: Now inactive', MSG_NOTIFY);
end;
end;
- end;
- SDL_VIDEOEXPOSE:
+ gWinActive := False;
+ end;
+ end
+ else if wActivate then
+ begin
+ if not gWinActive then
begin
begin
- // TODO: the fuck is this event?
- // Draw();
+ //e_WriteLog('activating window', MSG_NOTIFY);
+ e_EnableInput := True;
+
+ 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', MSG_NOTIFY);
+ end;
+
+ gWinActive := True;
end;
end;
+ end;
+end;
+
+function EventHandler(ev: TSDL_Event): Boolean;
+var
+ key, keychr: Word;
+ uc: UnicodeChar;
+ //joy: Integer;
+begin
+ Result := False;
+ case ev.type_ of
+ SDL_WINDOWEVENT:
+ Result := WindowEventHandler(ev.window);
SDL_QUITEV:
begin
SDL_QUITEV:
begin
SDL_KEYDOWN:
begin
SDL_KEYDOWN:
begin
- key := ev.key.keysym.sym;
- keychr := ev.key.keysym.unicode;
+ key := ev.key.keysym.scancode;
KeyPress(key);
KeyPress(key);
- if (keychr > 7) and (key <> IK_BACKSPACE) then
- begin
- if (keychr >= 128) then
- keychr := WCharToCP1251(keychr);
- CharPress(Chr(keychr));
- end;
end;
end;
- // key presses and joysticks are handled in e_input
+ SDL_TEXTINPUT:
+ begin
+ Utf8ToUnicode(@uc, PChar(ev.text.text), 1);
+ keychr := Word(uc);
+ if (keychr > 127) then
+ keychr := WCharToCP1251(keychr);
+ CharPress(Chr(keychr));
+ end;
+
+ // other key presses and joysticks are handled in e_input
end;
end;
procedure SwapBuffers();
begin
end;
end;
procedure SwapBuffers();
begin
- SDL_GL_SwapBuffers();
+ {$IFDEF HEADLESS}Exit;{$ENDIF}
+ SDL_GL_SwapWindow(h_Wnd);
end;
procedure KillGLWindow();
begin
end;
procedure KillGLWindow();
begin
- wWindowCreated := False;
+ if h_Wnd <> nil then SDL_DestroyWindow(h_Wnd);
+ if h_GL <> nil then SDL_GL_DeleteContext(h_GL);
+ h_Wnd := nil;
+ h_GL := nil;
+ //wWindowCreated := False;
end;
function CreateGLWindow(Title: PChar): Boolean;
end;
function CreateGLWindow(Title: PChar): Boolean;
gWinSizeX := gScreenWidth;
gWinSizeY := gScreenHeight;
gWinSizeX := gScreenWidth;
gWinSizeY := gScreenHeight;
+ wTitle := Title;
e_WriteLog('Creating window', MSG_NOTIFY);
if not g_Window_SetDisplay() then
e_WriteLog('Creating window', MSG_NOTIFY);
if not g_Window_SetDisplay() then
exit;
end;
exit;
end;
- SDL_WM_SetCaption(Title, Title);
- wWindowCreated := True;
+{$IFNDEF HEADLESS}
+ h_Gl := SDL_GL_CreateContext(h_Wnd);
+ if h_Gl = nil then Exit;
+{$ENDIF}
+ //wWindowCreated := True;
e_ResizeWindow(gScreenWidth, gScreenHeight);
e_InitGL();
e_ResizeWindow(gScreenWidth, gScreenHeight);
e_InitGL();
Result := True;
end;
Result := True;
end;
+{$IFDEF WINDOWS}
+// windoze sux; in headless mode `GetTickCount()` (and SDL) returns shit
function GetTimer(): Int64;
function GetTimer(): Int64;
+var
+ F, C: Int64;
begin
begin
- Result := SDL_GetTicks() * 1000; // TODO: do we really need microseconds here?
+ QueryPerformanceFrequency(F);
+ QueryPerformanceCounter(C);
+ Result := Round(C/F*1000{000});
end;
end;
+{$ELSE}
+function GetTimer(): Int64;
+var
+ t: Uint32;
+ tt: Int64;
+begin
+ t := SDL_GetTicks() {* 1000}; // TODO: do we really need microseconds here? k8: NOPE!
+ 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
procedure ResetTimer();
begin
ev: TSDL_Event;
ID: DWORD;
begin
ev: TSDL_Event;
ID: DWORD;
begin
+ FillChar(ev, SizeOf(ev), 0);
//wNeedFree := False;
wLoadingProgress := True;
while SDL_PollEvent(@ev) > 0 do
//wNeedFree := False;
wLoadingProgress := True;
while SDL_PollEvent(@ev) > 0 do
ev: TSDL_Event;
begin
Result := False;
ev: TSDL_Event;
begin
Result := False;
+ FillChar(ev, SizeOf(ev), 0);
while SDL_PollEvent(@ev) > 0 do
begin
while SDL_PollEvent(@ev) > 0 do
begin
if wNeedTimeReset then
begin
if wNeedTimeReset then
begin
- Time_Delta := 27777;
+ Time_Delta := 28{(27777 div 1000)};
wNeedTimeReset := False;
end;
wNeedTimeReset := False;
end;
- t := Time_Delta div 27777;
+ t := Time_Delta div 28{(27777 div 1000)};
if t > 0 then
begin
flag := True;
if t > 0 then
begin
flag := True;
// Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
if flag then
begin
// Âðåìÿ ïðåäûäóùåãî îáíîâëåíèÿ:
if flag then
begin
- Time_Old := Time - (Time_Delta mod 27777);
+ Time_Old := Time - (Time_Delta mod 28{(27777 div 1000)});
if (not wMinimized) then
begin
Draw();
if (not wMinimized) then
begin
Draw();
var
v: Byte;
begin
var
v: Byte;
begin
+ {$IFDEF HEADLESS}Exit;{$ENDIF}
if VSync then v := 1 else v := 0;
if VSync then v := 1 else v := 0;
+ 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_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_SWAP_CONTROL, v);
+ SDL_GL_SetSwapInterval(v);
end;
function SDLMain(): Integer;
begin
end;
function SDLMain(): Integer;
begin
+{$IFDEF HEADLESS}
+ e_NoGraphics := True;
+{$ENDIF}
+
e_WriteLog('Creating GL window', MSG_NOTIFY);
if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
begin
e_WriteLog('Creating GL window', MSG_NOTIFY);
if not CreateGLWindow(PChar(Format('Doom 2D: Forever %s', [GAME_VERSION]))) then
begin