{$IF not Defined(DENG_DEMO_MODE)}
//{{{ TWindowEvent
function TWindowEvent.IsClose: Boolean;
begin
  Result := Msg = WM_CLOSE;
end;

function TWindowEvent.IsKeyDown: Boolean;
begin
  Result := (Msg = WM_KEYDOWN) or (Msg = WM_SYSKEYDOWN);
end;

function TWindowEvent.IsKeyDown(_Key: LongInt): Boolean;
begin
  Result := IsKeyDown and (Key = _Key);
end;

function TWindowEvent.IsKeyUp: Boolean;
begin
  Result := Msg = WM_KEYUP;
end;

function TWindowEvent.IsKeyUp(_Key: LongInt): Boolean;
begin
  Result := IsKeyUp and (Key = _Key);
end;

function TWindowEvent.Key: LongInt;
begin
  Result := wParam;
end;

function TWindowEvent.IsChar: Boolean;
begin
  Result := Msg = WM_CHAR;
end;

function TWindowEvent.IsAltPressed: Boolean;
begin
  Result := Msg = WM_SYSKEYDOWN;
end;

function TWindowEvent.IsShiftPressed: Boolean; inline;
begin
  Exit(GetKeyState(VK_SHIFT) and $8000 <> 0);
end;

function TWindowEvent.JoyId: LongInt;
begin
  if (Msg = MM_JOY1BUTTONUP) or (Msg = MM_JOY1BUTTONDOWN) or (Msg = MM_JOY1MOVE) then begin
    Result := 1;
  end else if (Msg = MM_JOY2BUTTONUP) or (Msg = MM_JOY2BUTTONDOWN) or (Msg = MM_JOY2MOVE) then begin
    Result := 2;
  end else
    Result := 0;
end;

function TWindowEvent.IsJoyMove: Boolean;
begin
  Result := (Msg = MM_JOY1MOVE) or (Msg = MM_JOY2MOVE) or
            (Msg = MM_JOY1ZMOVE) or (Msg = MM_JOY2ZMOVE);
end;

function TWindowEvent.IsJoyDown: Boolean;
begin
  Result := (Msg = MM_JOY1BUTTONDOWN) or (Msg = MM_JOY2BUTTONDOWN);
end;

function TWindowEvent.IsJoyDown(Joy: LongInt): Boolean;
begin
  Result := IsJoyDown and (Self.Joy = Joy);
end;

function TWindowEvent.IsJoyUp: Boolean;
begin
  Result := (Msg = MM_JOY1BUTTONUP) or (Msg = MM_JOY2BUTTONUP);
end;

function TWindowEvent.IsJoyUp(Joy: LongInt): Boolean;
begin
  Result := IsJoyUp and (Self.Joy = Joy);
end;

function TWindowEvent.Joy: LongInt;
begin
  if (wParam and JOY_BUTTON1CHG) <> 0 then begin
    Result := 1;
  end else if (wParam and JOY_BUTTON2CHG) <> 0 then begin
    Result := 2;
  end else if (wParam and JOY_BUTTON3CHG) <> 0 then begin
    Result := 3;
  end else if (wParam and JOY_BUTTON4CHG) <> 0 then begin
    Result := 4;
  end else
    Result := 0;
end;

function TWindowEvent.GetJoyPos: TVec2i;
begin
  Result := Vec2i(LOWORD(lParam), HIWORD(lParam));
end;

function TWindowEvent.IsCursorMove: Boolean;
begin
  Result := (GetKeyState(VK_LBUTTON) and $100) <> 0;
end;

function TWindowEvent.IsLeftClickDown: Boolean;
begin
  Result := Msg = WM_LBUTTONDOWN;
end;

function TWindowEvent.IsLeftClickUp: Boolean;
begin
  Result := Msg = WM_LBUTTONUP;
end;

function TWindowEvent.IsRightClickDown: Boolean;
begin
  Result := Msg = WM_RBUTTONDOWN;
end;

function TWindowEvent.IsRightClickUp: Boolean;
begin
  Result := Msg = WM_RBUTTONUP;
end;

function TWindowEvent.IsMiddleClickDown: Boolean;
begin
  Result := Msg = WM_MBUTTONDOWN;
end;

function TWindowEvent.IsMiddleClickUp: Boolean;
begin
  Result := Msg = WM_MBUTTONUP;
end;

function TWindowEvent.IsDoubleLeftClick: Boolean;
begin
  Result := Msg = WM_LBUTTONDBLCLK;
end;

function TWindowEvent.GetCursor: TVec2f;
var
  Point: TPoint;
begin
  GetCursorPos(@Point);
  // if Caption
  ScreenToClient(Handle, @Point);
  // else begin
  //GetClientRect(Handle, @Rect);
  //Point.X := Point.X - Rect.Left;
  //Point.Y := Point.Y - Rect.Top;
  // end
  Result := Vec2f(Point.X, Point.Y);
end;

function TWindowEvent.IsResized: Boolean;
begin
  Exit(Msg = WM_SIZE);
end;

function TWindowEvent.Width: LongInt;
begin
  Exit(LOWORD(lParam))
end;

function TWindowEvent.Height: LongInt;
begin
  Exit(HIWORD(lParam))
end;

function TWindowEvent.IsMouseWheel: Boolean;
begin
  Result := Msg = WM_MOUSEWHEEL;
end;

function TWindowEvent.MouseWheel: LongInt;
var
  W: Word;
begin
  W := HIWORD(wParam);
  Result := TInt16(Pointer(@W)^);
  //Result := HIWORD(wParam);
end;
//}}}
{$ENDIF}

function WndProc(hWnd: HWND; Msg: Cardinal; wParam, lParam: LongInt): LongInt; stdcall;
var
  Window: PWindow;
begin
  Window := PWindow(GetWindowLongA(hWnd, GWL_USERDATA));
  if Window <> nil then
    if Window.WndProc(Msg, wParam, lParam) then
      Exit(0);
  Result := DefWindowProcA(hWnd, Msg, wParam, lParam);
end;

function CreateWindowClass(ClassName: PAnsiChar): Boolean;
var
  Wnd: WNDCLASSEX;
begin
  Result := False;
  FillChar(Wnd, SizeOf(Wnd), 0);
  with Wnd do begin
    cbSize          := SizeOf(Wnd);
    style           := CS_HREDRAW or
                       CS_VREDRAW or
                       CS_OWNDC;
    if WINAPI_SETTINGS.ReceiveDoubleClicks then begin
      Log('DOUBLE CLICKS');
      style := style or CS_DBLCLKS; // receive double clicks
    end;
    lpfnWndProc     := @DWinApi.WndProc;
    hCursor         := LoadCursorA(0, IDC_ARROW);
    hIcon           := LoadIconA(System.hInstance, 'MAINICON');
    lpszClassName   := ClassName;
    if WINAPI_SETTINGS.ShapedWindow then begin
      hbrBackground   := windows.CreateSolidBrush($00000000);
    end else
      hbrBackground   := 0;
  end;
  if RegisterClassExA(Wnd) = 0 then
      Exit;
  Result := True;
end;

//{{{ TWindow
procedure WindowAttachJoystick(Window: PWindow);
var
  JoyNums, JoyId: LongInt;
  JoyInfo: mmsystem.JOYINFO;
  JoyCaps: mmsystem.JOYCAPS;
begin
  JoyNums := joyGetNumDevs;
  if JoyNums = 0 then
    Exit;
  for JoyId := 0 to JoyNums - 1 do begin
    if joyGetPos(JoyId, @JoyInfo) = 0 then begin
      if joyGetDevCaps(JoyId, @JoyCaps, SizeOf(JoyCaps)) <> 0 then
        continue;
      if joySetCapture(Window^.FHandle, JoyId, 0, False) = 0 then begin
        LogTagged('D', 'Joystick device #' + IntToStr(JoyId) + ' is ready: ' + PAnsiChar(@JoyCaps.szPname[0]));
        //Exit;
      end;
    end;
  end;
  LogTagged('D', 'Connection joystick failed');
end;

function TWindow.WndProc(Msg: Cardinal; wParam, lParam: LongInt): Boolean;
var
  I: LongInt;
  Event: TWindowEvent;
  X, Y: LongInt;
  Rect: TRect;
  Point: TPoint;
begin
  if not FReady then
    Exit(False);

  if FDragging then begin
    if (Msg = WM_NCMOUSEMOVE) or (Msg = WM_MOUSEMOVE) then begin
        //Point.X := GET_X_LPARAM(lParam);
        //Point.Y := GET_Y_LPARAM(lParam);
        //ClientToScreen(FHandle, Point);
        GetCursorPos(Point);
        Log('New cursor pos: ' + IntToStr(Point.X) + ' ' + IntToStr(Point.Y));
        // SetWindowPos(FHandle, 0, FStartedDragX + Point.X, FStartedDragY + Point.Y, 0, 0, SWP_NOSIZE);
        GetWindowRect(FHandle, @Rect);
        MoveWindow(FHandle, FStartedDragX + Point.X,
                            FStartedDragY + Point.Y,
                            Rect.Right - Rect.Left,
                            Rect.Bottom - Rect.Top, True);
      // Force render now for new position
      Eng.Render;
    end else if (Msg = WM_LBUTTONUP) or (Msg = WM_NCLBUTTONUP) then begin
      FDragging := False;
      ReleaseCapture;
    end;
  end;

  if FResizing then begin
    if (Msg = WM_NCMOUSEMOVE) or (Msg = WM_MOUSEMOVE) then begin
      GetCursorPos(Point);
      GetWindowRect(FHandle, @Rect);
      Rect.Left   := FX1Initial + FX1Factor * Point.X;
      Rect.Top    := FY1Initial + FY1Factor * Point.Y;
      Rect.Right  := FX2Initial + FX2Factor * Point.X;
      Rect.Bottom := FY2Initial + FY2Factor * Point.Y;
      SetWindowPos(FHandle, 0, Rect.Left,
                               Rect.Top,
                               Rect.Right - Rect.Left,
                               Rect.Bottom - Rect.Top,
                               0);
      // Force render now for new size
      Eng.Render;
      // MoveWindow(FHandle, Rect.Left,
      //                     Rect.Top,
      //                     Rect.Right - Rect.Left,
      //                     Rect.Bottom - Rect.Top, True);
    end else if (Msg = WM_LBUTTONUP) or (Msg = WM_NCLBUTTONUP) then begin
      FResizing := False;
      ReleaseCapture;
    end;
  end;

  // TODO make it in better way later
  if Msg = WM_LBUTTONDOWN then begin
    // Catch left click up later
    windows.SetCapture(FHandle);
  end else if Msg = WM_LBUTTONUP then begin
    windows.ReleaseCapture();
  end;


  // ignore some unknown message codes
  if (Msg = 174) or (Msg = 127) or (Msg = 929) or (Msg = 931) or
     (Msg = 928) or (Msg = 930) or (Msg = 12) then
    Exit(False);

  if Msg = WM_SETFOCUS then begin
    FHasFocus := True;
    Exit(True);
  end else if Msg = WM_KILLFOCUS then begin
    FHasFocus := False;
    Exit(True);
  end;

  Event.Handle := FHandle;
  Event.Msg := Msg;
  Event.wParam := wParam;
  Event.lParam := lParam;
  FWinApi.OnWindowEvent(@Event);
  for I := 0 to High(FHandlers) do begin
    if FHandlers[I](@Event) then begin

      Exit(True);
    end;
  end;
  if Msg = WM_CLOSE then begin
    // If client code did not processed the close message, we just stop the
    // main loop by default.
    Eng.StopLoop;
  end;
  if Msg = WM_NCLBUTTONDOWN then begin
    if WINAPI_SETTINGS.AllowResize then begin
      X := GET_X_LPARAM(lParam);
      Y := GET_Y_LPARAM(lParam);
      // Do not let the DefWindowProc handle clicking on title bar or border
      // cause it leads to hanging the application loop
      case wParam of
        HTCAPTION: begin
          Log('GOTCHA!');
          FDragging := True;
          GetWindowRect(FHandle, @Rect);
          FStartedDragX := Rect.Left - X;
          FStartedDragY := Rect.Top  - Y;
          SetCapture(FHandle);
          Exit(True);
        end;
        HTBOTTOM:       Exit(StartResizing(X, Y, 0, 0, 0, 1));
        HTBOTTOMLEFT:   Exit(StartResizing(X, Y, 1, 0, 0, 1));
        HTBOTTOMRIGHT:  Exit(StartResizing(X, Y, 0, 0, 1, 1));
        HTLEFT:         Exit(StartResizing(X, Y, 1, 0, 0, 0));
        HTRIGHT:        Exit(StartResizing(X, Y, 0, 0, 1, 0));
        HTTOP:          Exit(StartResizing(X, Y, 0, 1, 0, 0));
        HTTOPLEFT:      Exit(StartResizing(X, Y, 1, 1, 0, 0));
        HTTOPRIGHT:     Exit(StartResizing(X, Y, 0, 1, 1, 0));
      end;
    end;
  end;
  //if Msg = WM_KEYDOWN then begin
  //end else if Msg = WM_KEYUP then begin
  //end else if Msg = WM_CHAR then begin
  //end else if Msg = WM_LBUTTONDOWN then begin
  //end else if Msg = WM_RBUTTONDOWN then begin
  //end else if Msg = WM_MBUTTONDOWN then begin
  //end else if Msg = WM_LBUTTONDBLCLK then begin
  //end else if Msg = WM_LBUTTONUP then begin
  //end else if Msg = WM_RBUTTONUP then begin
  //end else if Msg = WM_MBUTTONUP then begin
  //end else if Msg = WM_MOUSEWHEEL then begin
  //end else if Msg = WM_DESTROY then begin
  //end else
  //  Result := False;
  Exit(False);
end;

function ChoosePixelFormatCached(DC: HDC;
                                 Pfd: PPIXELFORMATDESCRIPTOR;
                                 CachedFormat: LongInt): LongInt;
var
  CachedPfd: PIXELFORMATDESCRIPTOR;
begin
  // First check cached value
  if DescribePixelFormat(DC, CachedFormat, SizeOf(CachedPfd), @CachedPfd) <> 0 then begin
    if CompareByte(CachedPfd, Pfd^, SizeOf(CachedPfd)) = 0 then begin
      LogTagged('D', 'ChoosePixelFormat Cached');
      Exit(CachedFormat);
    end;
    {if CachedPfd.nSize <> Pfd^.nSize then
      LogTagged('D', 'ChoosePixelFormat nSize differs');
    if CachedPfd.nVersion <> Pfd^.nVersion then
      LogTagged('D', 'ChoosePixelFormat nVersion differs');
    if CachedPfd.dwFlags <> Pfd^.dwFlags then
      LogTagged('D', 'ChoosePixelFormat dwFlags differs');
    if CachedPfd.iPixelType <> Pfd^.iPixelType then
      LogTagged('D', 'ChoosePixelFormat iPixelType differs');
    if CachedPfd.cColorBits <> Pfd^.cColorBits then
      LogTagged('D', 'ChoosePixelFormat cColorBits differs');
    if CachedPfd.cRedBits <> Pfd^.cRedBits then
      LogTagged('D', 'ChoosePixelFormat cRedBits differs');
    if CachedPfd.cRedShift <> Pfd^.cRedShift then
      LogTagged('D', 'ChoosePixelFormat cRedShift differs');
    if CachedPfd.cGreenBits <> Pfd^.cGreenBits then
      LogTagged('D', 'ChoosePixelFormat cGreenBits differs');
    if CachedPfd.cGreenShift <> Pfd^.cGreenShift then
      LogTagged('D', 'ChoosePixelFormat cGreenShift differs');
    if CachedPfd.cBlueBits <> Pfd^.cBlueBits then
      LogTagged('D', 'ChoosePixelFormat cBlueBits differs');
    if CachedPfd.cBlueShift <> Pfd^.cBlueShift then
      LogTagged('D', 'ChoosePixelFormat cBlueShift differs');
    if CachedPfd.cAlphaBits <> Pfd^.cAlphaBits then
      LogTagged('D', 'ChoosePixelFormat cAlphaBits differs');
    if CachedPfd.cAlphaShift <> Pfd^.cAlphaShift then
      LogTagged('D', 'ChoosePixelFormat cAlphaShift differs');
    if CachedPfd.cAccumBits <> Pfd^.cAccumBits then
      LogTagged('D', 'ChoosePixelFormat cAccumBits differs');
    if CachedPfd.cAccumRedBits <> Pfd^.cAccumRedBits then
      LogTagged('D', 'ChoosePixelFormat cAccumRedBits differs');
    if CachedPfd.cAccumGreenBits <> Pfd^.cAccumGreenBits then
      LogTagged('D', 'ChoosePixelFormat cAccumGreenBits differs');
    if CachedPfd.cAccumBlueBits <> Pfd^.cAccumBlueBits then
      LogTagged('D', 'ChoosePixelFormat cAccumBlueBits differs');
    if CachedPfd.cAccumAlphaBits <> Pfd^.cAccumAlphaBits then
      LogTagged('D', 'ChoosePixelFormat cAccumAlphaBits differs');
    if CachedPfd.cDepthBits <> Pfd^.cDepthBits then
      LogTagged('D', 'ChoosePixelFormat cDepthBits differs');
    if CachedPfd.cStencilBits <> Pfd^.cStencilBits then
      LogTagged('D', 'ChoosePixelFormat cStencilBits differs');
    if CachedPfd.cAuxBuffers <> Pfd^.cAuxBuffers then
      LogTagged('D', 'ChoosePixelFormat cAuxBuffers differs');
    if CachedPfd.iLayerType <> Pfd^.iLayerType then
      LogTagged('D', 'ChoosePixelFormat iLayerType differs');
    if CachedPfd.bReserved <> Pfd^.bReserved then
      LogTagged('D', 'ChoosePixelFormat bReserved differs');
    if CachedPfd.dwLayerMask <> Pfd^.dwLayerMask then
      LogTagged('D', 'ChoosePixelFormat dwLayerMask differs');
    if CachedPfd.dwVisibleMask <> Pfd^.dwVisibleMask then
      LogTagged('D', 'ChoosePixelFormat dwVisibleMask differs');
    if CachedPfd.dwDamageMask <> Pfd^.dwDamageMask then
      LogTagged('D', 'ChoosePixelFormat dwDamageMask differs');}
    Exit(CachedFormat);
  end;
  // If something went wrong, just call the ChoosePixelFormat as usual
  Exit(ChoosePixelFormat(DC, Pfd));
end;

function TWindow.CreatePixelFormat(Color, Depth, Stencil: LongInt): Boolean;
var
  Pfd: PIXELFORMATDESCRIPTOR;
  PixelFormat: LongInt;
  TempRC: HGLRC;
  T: PtrInt;
begin
  Result := False;
    FillChar(Pfd, SizeOf(Pfd), 0);
    with Pfd do begin
      nSize           := SizeOf(PIXELFORMATDESCRIPTOR);
      nVersion        := 2;
      dwFlags         := PFD_DRAW_TO_WINDOW or
                         PFD_SUPPORT_OPENGL or
                         PFD_DOUBLEBUFFER;
      if WINAPI_SETTINGS.ShapedWindow then begin
        dwFlags       := dwFlags or PFD_SUPPORT_COMPOSITION;
      end;
      iPixelType      := PFD_TYPE_RGBA;
      cColorBits      := Color;
      cDepthBits      := Depth;
      cStencilBits    := Stencil;
      iLayerType      := PFD_MAIN_PLANE;
    end;
    {T := Eng.Time;
    PixelFormat := ChoosePixelFormatCached(FDC, @Pfd, 11);
    T := Eng.Time - T;
    LogTagged('D', 'ChoosePixelFormat time: ' + IntToStr(T) + ', format=' + IntToStr(PixelFormat));}
    PixelFormat := ChoosePixelFormat(FDC, @Pfd);
    if (PixelFormat = 0) or not SetPixelFormat(FDC, PixelFormat, @Pfd) then
        Exit; // raise exception
  Result := True;
end;

function TWindow.CreatePixelFormatAdvanced(Title: PAnsiChar; X, Y, Width, Height, Color, Depth, Stencil: LongInt): Boolean;
var
  AttrI: array[0 .. 64 - 1] of GLint;
  Format: GLint;
  NumFormats: GLuint;
  Rect: TRect;
  Flags: UInt32;
  T: PtrInt;
begin
  if Load_WGL_ARB_pixel_format then begin
    AttrI[0] := WGL_DRAW_TO_WINDOW_ARB;
    AttrI[1] := GL_TRUE;
    AttrI[2] := WGL_SUPPORT_OPENGL_ARB;
    AttrI[3] := GL_TRUE;
    AttrI[4] := WGL_DOUBLE_BUFFER_ARB;
    AttrI[5] := GL_TRUE;
    AttrI[6] := WGL_PIXEL_TYPE_ARB;
    AttrI[7] := WGL_TYPE_RGBA_ARB;
    AttrI[8] := WGL_COLOR_BITS_ARB;
    AttrI[9] := Color - 8;
    AttrI[10] := WGL_DEPTH_BITS_ARB;
    AttrI[11] := Depth;
    AttrI[12] := WGL_STENCIL_BITS_ARB;
    AttrI[13] := Stencil;
    if WINAPI_SETTINGS.MultiSampling then begin
      AttrI[14] := WGL_SAMPLE_BUFFERS_ARB;
      AttrI[15] := GL_TRUE;
      AttrI[16] := WGL_SAMPLES_ARB;
      if WINAPI_SETTINGS.MultiSamplingLevel <> -1 then begin
        AttrI[17] := WINAPI_SETTINGS.MultiSamplingLevel;
      end else
        AttrI[17] := 16;
    end else
      AttrI[14] := 0;
    AttrI[18] := 0;
    T := Eng.Time;
    if not wglChoosePixelFormatARB(FDC, @AttrI[0], nil, 1, @Format, @NumFormats) then begin
      LogTagged('D', 'WARNING: wglChoosePixelFormatARB failed');
      Exit(False);
    end;
    T := Eng.Time - T;
    LogTagged('D', 'wglChoosePixelFormatARB time: ' + IntToStr(T));
    // No recreate Window with obtained format
    wglMakeCurrent(FDC, 0);
    wglDeleteContext(FRC);
    ReleaseDC(FHandle, FDC);
    DestroyWindow(FHandle);
    Rect.Left     := X;
    Rect.Top      := Y;
    Rect.Right    := Width;
    Rect.Bottom   := Height;
    // TODO WS_OVERLAPPEDWINDOW ?
    AdjustWindowRect(@Rect, WS_POPUP or WS_CAPTION, False{, WS_EX_APPWINDOW or WS_EX_WINDOWEDGE});
    Flags := WS_POPUP or WS_CAPTION;
    if WINAPI_SETTINGS.CloseButton then
      Flags := Flags or WS_SYSMENU;
    if WINAPI_SETTINGS.AllowResize then
      Flags := Flags or WS_THICKFRAME;
    InitHandle(DENG_WINDOWCLASS, Title, Flags,
          WS_EX_APPWINDOW or WS_EX_WINDOWEDGE {or (WS_EX_LAYERED * Ord(WINAPI_SETTINGS.ShapedWindow))}, 500, 100, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
    FDC := GetDC(FHandle);
    if not SetPixelFormat(FDC, Format, nil) then begin
      LogTagged('D', 'WARNING: could not SetPixelFormat for advanced: ' + IntToStr(GetLastError));
      Exit(False);
    end;
    InitRC;
  end else
    LogTagged('D', 'WARNING WGL_ARB_pixel_format is not supported');
  Exit(True);
end;

function TWindow.InitHandle(ClassName, Title: PAnsiChar;
                  Flags, FlagsEx: Cardinal;
                  X, Y, W, H: LongInt): Boolean;
begin
  Result := True;
  FHandle := CreateWindowExA(FlagsEx,
        ClassName,
        Title,
        Flags,
        X, Y, W, H, 0, 0, System.hInstance, nil);
  if WINAPI_SETTINGS.ShapedWindow then begin
    //if not SetLayeredWindowAttributes(FHandle, $00000000, 0, LWA_ALPHA or LWA_COLORKEY) then
    //  Exit(False);
  end;
  if FHandle = 0 then
      Result := False; // raise exception
end;

function TWindow.InitFakeBlurredRegion: Boolean;
var
  bb: DWM_BLURBEHIND;
  hRgn: windows.HRGN;
begin
  FillChar(bb, SizeOf(bb), 0);
  hRgn := CreateRectRgn(0, 0, -1, -1);
  bb.dwFlags := DWM_BB_ENABLE or DWM_BB_BLURREGION;
  bb.hRgnBlur := hRgn;
  bb.fEnable := True;
  Log('CALLED DwmEnableBlurBehindWindow');
  DwmEnableBlurBehindWindow(FHandle, @bb);
  Log('DONE DwmEnableBlurBehindWindow');
  Exit(True);
end;

function TWindow.InitDC: Boolean;
begin
  Result := True;
  FDC := GetDC(FHandle);
  if (FDC = 0) or not CreatePixelFormat(32, 24, 8) then
      Result := False; // raise exception
end;

function TWindow.InitRC: Boolean;
begin
  Result := True;
  FRC := wglCreateContext(FDC);
  if (FRC = 0) or not wglMakeCurrent(FDC, FRC) then
      Result := False; // raise exception
end;

function TWindow.StartResizing(X, Y, X1, Y1, X2, Y2: LongInt): Boolean;
var
  Rect: TRect;
begin
  FResizing := True;
  GetWindowRect(FHandle, @Rect);

  FX1Factor := X1;
  FY1Factor := Y1;
  FX2Factor := X2;
  FY2Factor := Y2;

  FX1Initial := Rect.Left   - X1 * X;
  FY1Initial := Rect.Top    - Y1 * Y;
  FX2Initial := Rect.Right  - X2 * X;
  FY2Initial := Rect.Bottom - Y2 * Y;

  SetCapture(FHandle);
  Exit(True);
end;

constructor TWindow.Init(WinApi: PWinApi; X, Y, W, H: LongInt; Title: PAnsiChar);
var
  Rect, ClientRect: TRect;
  Flags, FlagsEx: UInt32;
begin
  FWinApi := WinApi;

  FHasFocus := True;

  Rect.Left     := 0;
  Rect.Top      := 0;
  Rect.Right    := W;
  Rect.Bottom   := H;
  // TODO WS_OVERLAPPEDWINDOW ?
  AdjustWindowRect(@Rect, WS_POPUP or WS_CAPTION, False{, WS_EX_APPWINDOW or WS_EX_WINDOWEDGE});

  Flags := WS_POPUP or WS_CAPTION;
  if WINAPI_SETTINGS.CloseButton then
    Flags := Flags or WS_SYSMENU;
  if WINAPI_SETTINGS.AllowResize then
    Flags := Flags or WS_THICKFRAME;

  FlagsEx := WS_EX_APPWINDOW or WS_EX_WINDOWEDGE;
  // if WINAPI_SETTINGS.ShapedWindow then
  //   FlagsEx := FlagsEx or WS_EX_LAYERED;
  InitHandle(DENG_WINDOWCLASS, Title, Flags,
        FlagsEx, X, Y, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
  if WINAPI_SETTINGS.ShapedWindow then
    InitFakeBlurredRegion;
  InitDC;
  InitRC;
  {if need advanced then} begin
    CreatePixelFormatAdvanced(Title, 0, 0, W, H, 32, 24, 8);
    //CreatePixelFormat(32, 24, 8);
  end;

  SetWindowLongA(FHandle, 0, WS_VISIBLE);
  //with Rect do
  //  MoveWindow(FHandle, 0, 0, Right - Left, Bottom - Top, True);

  ShowCursor(True);
  SetForegroundWindow(FHandle);
  ShowWindow(FHandle, SW_SHOW);
  SetFocus(FHandle);
  UpdateWindow(FHandle);
  // FIXME range check error while evaluating constants:
  Flags := WS_CAPTION or WS_VISIBLE;
  if WINAPI_SETTINGS.CloseButton then
    Flags := Flags or WS_SYSMENU;
  if WINAPI_SETTINGS.AllowResize then
    Flags := Flags or WS_THICKFRAME;
  SetWindowLongA(FHandle, GWL_STYLE, Flags {or WS_POPUPWINDOW});
  //SetWindowPos(FHandle, 0, X, Y, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top, SWP_FRAMECHANGED or SWP_NOOWNERZORDER);

  //GetWindowRect(FHandle, @Rect);
  GetClientRect(FHandle, @ClientRect);
  //glViewport(0, Rect.Top - ClientRect.Top, W, H - (Rect.Top - ClientRect.Top));
  glViewport(ClientRect.Left, ClientRect.Top, ClientRect.Right, ClientRect.Bottom);
  LogTagged('D', 'VSYNC OFF');
  Load_WGL_EXT_swap_control;
  wglSwapIntervalExt(0);

  SetWindowLongA(FHandle, GWL_USERDATA, Cardinal(@Self));

  GetClientRect(FHandle, @Rect);

  WindowAttachJoystick(@Self);

  FReady := False;
end;

destructor TWindow.Done;
begin
  // TODO
end;

procedure TWindow.Subscribe(Handler: TOnWindowEvent);
begin
  SetLength(FHandlers, Length(FHandlers) + 1);
  FHandlers[High(FHandlers)] := Handler;
end;

procedure TWindow.SwapBuffers;
begin
  Windows.SwapBuffers(FDC);
end;

procedure TWindow.SetDisplayMode(X, Y: LongInt; Fullscreen: Boolean);
var
  Settings: TDevMode;
  DisplayFlags: LongInt;
  Flags: UInt32;
  //Font: HFont;
  R: TRect;
begin
  FFullScreen := Fullscreen;
  if Fullscreen then begin
    FillChar(Settings, SizeOf(Settings), 0);
    Settings.dmSize := SizeOf(Settings);
    Settings.dmPelsWidth := X;
    Settings.dmPelsHeight := Y;
    Settings.dmBitsPerPel := 32;
    Settings.dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
    if Fullscreen or (X = 0) or (Y = 0) then
      EnumDisplaySettings(nil, ENUM_REGISTRY_SETTINGS, @Settings);
    DisplayFlags := 0;
    if Fullscreen then
      DisplayFlags := CDS_FULLSCREEN;
    if ChangeDisplaySettings(Settings, DisplayFlags) <> DISP_CHANGE_SUCCESSFUL then
      ;// error
    ShowCursor(True);
    SetForegroundWindow(FHandle);
    ShowWindow(FHandle, SW_SHOW);
    SetFocus(FHandle);
    UpdateWindow(FHandle);
    SetWindowLongA(FHandle, GWL_STYLE, WS_VISIBLE);
    SetWindowPos(FHandle, 0, 0, 0, Settings.dmPelsWidth, Settings.dmPelsHeight, SWP_FRAMECHANGED or SWP_NOOWNERZORDER);
    glViewport(0, 0, Settings.dmPelsWidth, Settings.dmPelsHeight);

    Log('VSYNC OFF');
    Load_WGL_EXT_swap_control;
    wglSwapIntervalExt(0);

    while glGetError() <> 0 do;
    {
    font := CreateFont(-30,                            // Height Of Font
          0,                              // Width Of Font
          0,                              // Angle Of Escapement
          0,                              // Orientation Angle
          //FW_EXTRALIGHT,                      // Font Weight
          FW_BOLD,
          0,                          // Italic
          0,                          // Underline
          0,                          // Strikeout
          ANSI_CHARSET,                   // Character Set Identifier
          OUT_TT_PRECIS,                  // Output Precision
          CLIP_DEFAULT_PRECIS,            // Clipping Precision
          ANTIALIASED_QUALITY,            // Output Quality
          FF_DONTCARE or VARIABLE_PITCH,       // Family And Pitch
          'Courier');             // Font Name
    //SelectObject(FDC, GetStockObject(SYSTEM_FONT));
    SelectObject(FDC, Font);
    List := glGenLists(256);
    wglUseFontBitmaps(FDC, 0, 255, List);
    //wglUseFontOutlines(FDC, 0, 255, List, 10, 10, WGL_FONT_POLYGONS, nil);
    }
  end else begin
    if ChangeDisplaySettings(nil, 0) <> DISP_CHANGE_SUCCESSFUL then
      LogTagged('D', 'Error: Could not change display settings back to windowed');
    Flags := WS_POPUP or WS_VISIBLE or WS_CAPTION;
    if WINAPI_SETTINGS.CloseButton then
      Flags := Flags or WS_SYSMENU;
    if WINAPI_SETTINGS.AllowResize then
      Flags := Flags or WS_THICKFRAME;
    SetWindowLongA(FHandle, GWL_STYLE, Flags);
    R.Left := (FWinApi.ScreenSize.X - X) div 2;
    R.Top := (FWinApi.ScreenSize.Y - Y) div 2;
    R.Right := R.Left + X;
    R.Bottom := R.Top + Y;
    AdjustWindowRect(@R, Flags, False);
    MoveWindow(FHandle, R.Left, R.Top, X, Y, True);
    //SetWindowPos(FHandle, 0, 0, 0, Settings.dmPelsWidth, Settings.dmPelsHeight, SWP_FRAMECHANGED or SWP_NOOWNERZORDER);
    glViewport(0, 0, X, Y);
    LogTagged('D', 'VSYNC OFF');
    Load_WGL_EXT_swap_control;
    wglSwapIntervalExt(0);
  end;

  LogTagged('D', 'SetDisplayMode ' + IntToStr(X) + ' ' + IntToStr(Y) + ' ' + IntToStr(Ord(Fullscreen)));
end;

procedure TWindow.SetShowCursor(Value: Boolean);
begin
  while (Windows.ShowCursor(Value) >= 0) <> Value do;
end;

function TWindow.GetShowCursor: Boolean;
const
  CURSOR_SHOWING        = $00000001;
  CURSOR_SUPPRESSED     = $00000002;
var
  CursorInfo: windows.CURSORINFO;
begin
  CursorInfo.cbSize := SizeOf(CursorInfo);
  if not GetCursorInfo(CursorInfo) then begin
    LogTagged('D', 'FAILED GetCursorInfo: ' + IntToStr(windows.GetLastError));
    Exit(False);
  end;
  Result := (CursorInfo.flags and CURSOR_SHOWING) <> 0;
end;

procedure TWindow.SetCursor(const Pos: TVec2i);
var
  Point: TPoint;
begin
  Point.X := Pos.X;
  Point.Y := Pos.Y;
  ClientToScreen(FHandle, @Point);
  windows.SetCursorPos(Point.X, Point.Y);
end;

function TWindow.GetPos: TVec2i;
var
  Rect: TRect;
begin
  GetWindowRect(FHandle, @Rect);
  Result := Vec2i(Rect.Left, Rect.Top);
end;

function TWindow.GetSize: TVec2i;
var
  Rect: TRect;
begin
  GetClientRect(FHandle, @Rect);
  Result := Vec2i(Rect.Right - Rect.Left, Rect.Bottom - Rect.Top);
end;

function TWindow.GetMouse: TVec2i;
begin
  Result := FWinApi.GetMouse;
end;
//}}}
//{{{ TWinApi
constructor TWinApi.Init;
begin
  FWindow := nil;
  FOnWindowEvent := EmptyEventHandler;
end;

destructor TWinApi.Done;
begin
  if FWindow <> nil then
    FWindow.Free;
end;

procedure TWinApi.OnInit(Width, Height, Bits, Flags: LongInt; Title: PAnsiChar);
var
  S, P: TVec2i;
begin
  CreateWindowClass(DENG_WINDOWCLASS);
  S := ScreenSize;
  P := Vec2i(Max((S.X - Width) div 2, 0), Max((S.Y - Height) div 2, 0));
  FWindow := TWindow.Create(@Self, P.X, P.Y, Width, Height, Title);
  // Old way for fullscreen
  FWindow.FWindowedSize := Vec2i(Width, Height);
  FWindow.FFullScreen := (Flags and DENG_FULLSCREEN) > 0;
  if (Flags and DENG_FULLSCREEN) > 0 then
    FWindow.SetDisplayMode(S.X, S.Y, True);
  FWindow.FReady := True;
end;

procedure TWinApi.ReadMessages;
var
  Msg: TMsg;
begin
  while PeekMessageA(@Msg, 0, 0, 0, PM_REMOVE) do begin
    TranslateMessage(@Msg);
    DispatchMessageA(@Msg);
  end;
end;

function TWinApi.GetScreenSize: TVec2i;
var
  Mode: DEVMODE;
begin
  EnumDisplaySettingsA(nil, ENUM_CURRENT_SETTINGS, @Mode);
  Result := Vec2i(Mode.dmPelsWidth, Mode.dmPelsHeight);
end;

function TWinApi.GetMouse: TVec2i;
var
  Point: TPoint;
begin
  GetCursorPos(@Point);
  ScreenToClient(FWindow.FHandle, @Point);
  Result := Vec2i(Point.X, Point.Y);
end;

procedure TWinApi.SetCursorVisibility(Visibility: Boolean);
begin
  Windows.ShowCursor(Visibility);
end;

procedure TWinApi.HideCursor;
begin
  Windows.ShowCursor(False);
end;

procedure TWinApi.ShowCursor;
begin
  Windows.ShowCursor(True);
end;

function TWinApi.HasFocus: Boolean;
begin
  Result := FWindow^.FHasFocus;
end;

function TWinApi.IsActive: Boolean;
begin
  Exit(windows.GetActiveWindow() = FWindow^.FHandle);
end;

procedure TWinApi.ToggleFullScreen;
begin
  if FWindow.FFullScreen then begin
    FWindow.FFullScreen := False;
    FWindow.SetDisplayMode(FWindow.FWindowedSize.X, FWindow.FWindowedSize.Y, FWindow.FFullScreen);
  end else begin
    FWindow.FFullScreen := True;
    FWindow.SetDisplayMode(FWindow.FWindowedSize.X, FWindow.FWindowedSize.Y, FWindow.FFullScreen);
  end;
end;

procedure TWinApi.MakeFullscreen;
begin
  if not FWindow.FFullScreen then begin
    FWindow.FFullScreen := True;
    FWindow.SetDisplayMode(FWindow.FWindowedSize.X, FWindow.FWindowedSize.Y, FWindow.FFullScreen);
  end;
end;

procedure TWinApi.MakeWindowed;
begin
  if FWindow.FFullScreen then begin
    FWindow.FFullScreen := False;
    FWindow.SetDisplayMode(FWindow.FWindowedSize.X, FWindow.FWindowedSize.Y, FWindow.FFullScreen);
  end;
end;

function TWinApi.IsFullScreen: Boolean;
begin
  Exit(FWindow.FFullScreen);
end;

function TWinApi.GetTitle: TString;
begin
  // TODO GetWindowTextA
  Result := '';
end;

procedure TWinApi.SetTitle(const Value: TString);
begin
  SetWindowTextA(FWindow.FHandle, PAnsiChar(@Value[1]));
end;

function TWinApi.GetPos: TVec2i;
begin
  // TODO
  Result := Vec2i(0, 0);
end;

procedure TWinApi.SetPos(const Value: TVec2i);
begin
end;

function TWinApi.GetSize: TVec2i;
begin
  Result := Vec2i(0, 0);
end;

procedure TWinApi.SetSize(const Value: TVec2i);
begin
end;

procedure TWinApi.SetTransperency(Alpha: Single);
begin
  //SetLayeredWindowAttributes(FWindow.FHandle, $00000000, Round(Alpha * 255), LWA_ALPHA or LWA_COLORKEY);
end;
//}}}

function GetTimer: LongInt;
var
  T, F: LARGE_INTEGER;
begin
  QueryPerformanceFrequency(@F);
  QueryPerformanceCounter(@T);
  Result:=Trunc(1000*T.QuadPart/F.QuadPart);
end;

function GetTimerMicroSeconds: Double;
var
  T, F: LARGE_INTEGER;
begin
  QueryPerformanceFrequency(@F);
  QueryPerformanceCounter(@T);
  Exit(1000000 * T.QuadPart / F.QuadPart);
end;
