program FlameSS;

uses
  Forms,
  Dialogs,
  SysUtils,
  Render,
  controlpoint,
  windows,
  graphics,
  messages,
  ScrConfig in '..\..\ScreenSaver\ScrConfig.pas' {frmConfig},
  ScrMain in '..\..\ScreenSaver\ScrMain.pas' {frmMain},
  FlameIO in '..\..\ScreenSaver\FlameIO.pas';

{$E SCR}

{$R *.res}

type  TSSMode = (ssSetPwd,ssPreview,ssConfig,ssRun);

var
  MySem: THandle;

function GetScreenSaverMode: TSSMode;
var
  ParamChar: Char;
begin
  Result := ssRun;
  if ParamCount = 0 then
    Exit;

  if Length(ParamStr(1)) = 1 then
    ParamChar := ParamStr(1)[1]
  else
    ParamChar := ParamStr(1)[2];

  Case ParamChar of
  'A', 'a':
    Result := ssSetPwd;
  'P', 'p':
    Result := ssPreview;
  'C', 'c':
    Result := ssConfig;
  else
    Result := ssRun;
  end;
end;

procedure SetPassWord;
var
  SysDir: string;
  NewLen: integer;
  MyMod: THandle;
  PwdFunc:     function (a : PChar; ParentHandle : THandle; b, c : Integer) :
                     Integer; stdcall;
begin
  SetLength(SysDir,MAX_PATH);
  NewLen := GetSystemDirectory(PChar(SysDir),MAX_PATH);
  SetLength(SysDir,NewLen);

  MyMod := LoadLibrary(PChar(IncludeTrailingPathDelimiter(SysDir) + 'MPR.DLL'));
  if MyMod <> 0 then begin
    PwdFunc := GetProcAddress(MyMod,'PwdChangePasswordA');
    if Assigned(PwdFunc) then
      PwdFunc('SCRSAVE',StrToInt(paramstr(2)),0,0);
    FreeLibrary(MyMod);
  end;
end;

function WindowProc(Wnd: HWnd; Msg: Integer; wParam: Word; lParam: Integer): Integer; far; stdcall;
begin

  { Window procedure for the saver preview. Only used for terminating the preview
    version of the saver. }
  if (Msg = WM_DESTROY) or (Msg = WM_CLOSE) then PostMessage(Wnd, WM_QUIT, 0, 0);
  Result := DefWindowProc(Wnd, Msg, wParam, lParam);

end;

procedure Preview;
var
  PreviewCanvas: TCanvas;
  PreviewRect: TRect;
  WndClass: TWndClass;
  DC: hDC;
  MyWnd: hWnd;
  Msg: TMsg;
  ParentHandle: THandle;
  cp : TControlPoint;
  Render: TRenderer;
  bm: TBitmap;
begin
  { To run the preview, you need to create a window class corresponding with the
    little display in the screensaver control panel. This doesn't look very
    elegant in a Delphi project, but I don't think you can use VCL functionality
    to do this... }
  with WndClass do
  begin
    style := CS_PARENTDC;
    lpfnWndProc := @WindowProc;
    cbClsExtra := 0;
    cbWndExtra := 0;
    hIcon := 0;
    hCursor := 0;
    hbrBackground := 0;
    lpszMenuName := nil;
    lpszClassName := 'DeskSpin';
  end;
  WndClass.hInstance := hInstance;
  Windows.RegisterClass(WndClass);

  ParentHandle := StrToInt(ParamStr(2));

  // Initialize a Rect that matches the preview area:
  GetWindowRect(Parenthandle, PreviewRect);
  PreviewRect.Right := PreviewRect.Right - PreviewRect.Left;
  PreviewRect.Bottom := PreviewRect.Bottom - PreviewRect.Top;
  PreviewRect.Left := 0;
  PreviewRect.Top := 0;

  // Instantiate the window class so we can draw to the preview area:
  MyWnd := CreateWindow('DeskSpin', 'DeskSpin',
                        WS_CHILD or WS_DISABLED or WS_VISIBLE, 0, 0,
                        PreviewRect.Right, PreviewRect.Bottom, ParentHandle,
                        0, hInstance, nil);

  // We need a DC before we can draw:
  DC := GetDC(MyWnd);
  { We can create a TCanvas matching the DC, so we can draw the preview with
    familiar functions: }
  PreviewCanvas := TCanvas.Create;
  PreviewCanvas.Handle := DC;

  randomize;
  cp := TControlPoint.Create;
  Render := TRenderer.Create;

  cp.ParseString('pixels_per_unit 277.456647 center -1.0982659 0 gamma 2 spatial_filter_radius' +
                 ' 0.5 contrast 1 brightness 1.5 zoom 0 spatial_oversample 1 sample_density 1 nbatches' +
                 ' 1 white_level 200 cmap_inter 0 time 0 cmap 33 xform 0 density 1 color 0 var 0 0 0 1 0' +
                 ' 0 0 coefs 0.466381997 -0.0618700013 0.0792416036 0.610638022 -0.475656986 -0.28115499'+
                 ' xform 1 density 1 color 1 var 0 0 0 0 1 0 0 coefs -0.513867021 0.271649003 -0.254521996' +
                 ' -0.550984025 -0.674094975 -0.600323975');

  cp.sample_density := 1;
  cp.Width := PreviewRect.Right - PreviewRect.Left;
  cp.Height := PreviewRect.Bottom - PreviewRect.Top;
  cp.spatial_oversample := 2;
  cp.spatial_filter_radius := 0.1;
  cp.Gamma := 4;
  cp.brightness := 4;
  cp.CalcBoundbox;
  Render.SetCP(cp);
  Render.Render;
  BM := Render.GetImage;
  PreviewCanvas.Draw(0,0,bm);


  { Enter a message loop to keep the preview going. I've kept the preview simple
    (plain text output), but if you wanted, you could initialize OpenGL for the
    DC you already have, and actually let your saver render to that. }
  while GetMessage(Msg, 0, 0, 0) do
  begin
    PreviewCanvas.Draw(0,0,bm);

//    PreviewCanvas.FillRect(PreviewRect);
//    PreviewCanvas.TextOut(5, 5, 'Your preview here.');
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
  PreviewCanvas.Free;

  // Close and destroy the preview window:
  CloseWindow(MyWnd);
  DestroyWindow(MyWnd);

  Render.Free;
  cp.Free;
end;

begin
  Case GetScreenSaverMode of
  ssSetPwd:
    begin
      Application.Initialize;
      SetPassWord;
    end;
  ssConfig:
    begin
      Application.Initialize;
      Application.Title := 'Flame Screensaver';
  Application.CreateForm(TfrmConfig, frmConfig);
  Application.Run;
    end;
  ssPreview:
    Preview;
  else // ssrun
    // Test if screen save was already started
    MySem := CreateSemaphore(nil,0,1,'ESDSaverSemaphore');
    if (MySem <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then begin
      CloseHandle(MySem);
      Exit;
    end;

    Application.Initialize;
    Application.CreateForm(TfrmMain, frmMain);
    Application.Run;

    if (MySem <> 0) then
      CloseHandle(MySem);
  end; // Case GetScreenSaverMode of

end.