unit e_screen;

interface

uses Windows, OpenGL, e_global, e_types, e_utils;

type
  TScreenResolution = record
    width, height : integer;
  end;

  TScreen = record
    width, height, color_depth : integer;
    resolutions : TSelect;
    resolution_string : TString;
    fullscreen : boolean;
    aspect : single;
    vsync : boolean;
  end;

  PScreen = ^TScreen;

var                                                      
  screen : TScreen = (color_depth : 32; fullscreen : true; vsync : true);

  screen_resolutions : array of TScreenResolution;

  wglSwapIntervalEXT       : function (interval: GLint): Boolean; stdcall;
  wglGetSwapIntervalEXT    : function: GLint; stdcall;

procedure ScreenPrepare(scr : PScreen);
procedure ScreenSet(scr : PScreen);
function  ScreenSetMode(scr : PScreen; const Test: Boolean = False) : boolean;
//procedure ScreenSetVSync(scr : PScreen; scr_vsync : boolean);

implementation

procedure ScreenPrepare(scr : PScreen);
var
b, m : boolean;
i, a, n : integer;
mode : TDevMode;
begin
i := 0;
n := 0;
b := false;
repeat
b := not EnumDisplaySettings(nil, i, mode);

SetLength(screen_resolutions, n + 1);
m := true;

for a := 0 to n do
  if (screen_resolutions[a].width  = mode.dmPelsWidth) and
     (screen_resolutions[a].height = mode.dmPelsHeight) then m := false;

if (mode.dmPelsWidth < 800) or (mode.dmPelsHeight < 600) or (mode.dmBitsPerPel < 32) then m := false;
if ChangeDisplaySettings(mode, CDS_TEST or CDS_FULLSCREEN) <> DISP_CHANGE_SUCCESSFUL then m := false;

if m then
  with screen_resolutions[n] do
    begin
      width  := mode.dmPelsWidth;
      height := mode.dmPelsHeight;
      SetLength(scr^.resolutions.elements, n + 1);
      scr^.resolutions.elements[n] := inttostr(width) + 'x' + inttostr(height);
      inc(n);
    end;

inc(i);
until b;

scr^.resolutions.number := n;
end;

procedure ScreenVSync(enabled : boolean);
var
  wglSwapIntervalEXT : function(interval : GLint) : GLboolean; stdcall;
  wglGetSwapIntervalEXT : function: GLint; stdcall;
  interval : GLint;
begin
  interval := 0;
  if enabled then interval := 1;
  
  wglSwapIntervalEXT := wglGetProcAddress('wglSwapIntervalEXT');
  wglGetSwapIntervalEXT := wglGetProcAddress('wglGetSwapIntervalEXT');

  if addr(wglGetSwapIntervalEXT) <> nil then
    if wglGetSwapIntervalEXT <> interval then
    begin
      if addr(wglSwapIntervalEXT) <> nil then
        wglSwapIntervalEXT(interval);
    end;
end;

procedure ScreenSet(scr : PScreen);
var
x, y : integer;
Style : DWORD;
Rect  : TRect;
begin
with scr^ do
  begin
    if not ScreenSetMode(Scr, True) then Exit;

    width  := screen_resolutions[resolutions.number - 1].width;
    height := screen_resolutions[resolutions.number - 1].height;
    
    screen.resolution_string := inttostr(width) + 'x' + inttostr(height);

    //mouse_system := GetPoint(0, 0, 0);

    aspect := width / height;
    //PrepareFont(width, height);
    x := GetSystemMetrics(SM_CXSCREEN);
    y := GetSystemMetrics(SM_CYSCREEN);
    if fullscreen then Style := WS_POPUP
    else               Style := WS_POPUP or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX;
    SetWindowLong(handle, GWL_STYLE, Style or WS_VISIBLE);
    Rect.Left   := 0;
    Rect.Top    := 0;
    Rect.Right  := width;
    Rect.Bottom := height;
    AdjustWindowRect(Rect, Style, False);
    if not fullscreen then
      with Rect do
        SetWindowPos(handle, 0, round((x - width) / 2), round((y - height) / 2), Right - Left, Bottom - Top, 0)
    else
      SetWindowPos(handle, 0, 0, 0, width, height, 0);

    ShowWindow(handle, SW_SHOW);
    //glViewport(0, 0, width, height);

    ScreenSetMode(scr);
    ScreenVSync(vsync);
    //VSync(scr, vsync_enabled);
    //SetCursorPos(0, 0);
  end;
end;

function ScreenSetMode(scr : PScreen; const Test: Boolean = False) : boolean;
var
DeviceMode : TDevMode;
begin
if scr^.fullscreen then
  with DeviceMode do
    begin
      dmBitsPerPel := scr^.color_depth;
      dmPelsWidth := scr^.width;
      dmPelsHeight := scr^.height;
      dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
      dmSize := SizeOf(DeviceMode);
      dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
      if not Test then
        Result := ChangeDisplaySettings(DeviceMode, CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL
      else
        Result := ChangeDisplaySettings(DeviceMode, CDS_TEST or CDS_FULLSCREEN) = DISP_CHANGE_SUCCESSFUL;
    end
else if not Test then ChangeDisplaySettings(TDevMode(nil^), CDS_FULLSCREEN);
end;

end.
