{ Apophysis Copyright (C) 2001-2004 Mark Townsend Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov Apophysis Copyright (C) 2007-2008 Piotr Borys, Peter Sdobnov Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina 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; either version 2 of the License, or (at your option) any later version. 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit FormRender; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, Math, Buttons, Registry, ExtCtrls, MMSystem, System.Win.TaskbarCore, Vcl.Taskbar, Vcl.Samples.Spin, // AV ControlPoint, cmap, RenderThread, RenderingInterface, ShellAPI, ActiveX, ComObj; const {$ifdef T500} rendersAV = 'rendersAV_250.flame'; {$else} rendersAV = 'rendersAV.flame'; {$endif} type TWin32Version = (wvUnknown, wvWin95, wvWin98, wvWinNT, wvWin2000, wvWinXP, wvWinVista, wvWin7, wvWinFutureFromOuterSpace); type TRenderForm = class(TForm) btnRender: TButton; btnCancel: TButton; SaveDialog: TSaveDialog; btnPause: TButton; StatusBar: TStatusBar; PageCtrl: TPageControl; TabSettings: TTabSheet; TabOutput: TTabSheet; GroupBox5: TGroupBox; btnSavePreset: TSpeedButton; btnDeletePreset: TSpeedButton; cmbPreset: TComboBox; GroupBox2: TGroupBox; cbWidth: TComboBox; cbHeight: TComboBox; GroupBox3: TGroupBox; txtOversample: TEdit; txtFilterRadius: TEdit; udOversample: TUpDown; txtDensity: TComboBox; GroupBox4: TGroupBox; lblApproxMem: TLabel; lblPhysical: TLabel; lblMaxbits: TLabel; Label9: TLabel; cbMaxMemory: TComboBox; chkLimitMem: TCheckBox; Output: TMemo; lblMemory: TLabel; btnBrowse: TSpeedButton; txtFilename: TEdit; GroupBox1: TGroupBox; chkSave: TCheckBox; GroupBox6: TGroupBox; chkPostProcess: TCheckBox; chkShutdown: TCheckBox; btnGoTo: TSpeedButton; pnlWidth: TPanel; pnlHeight: TPanel; pnlDensity: TPanel; pnlFilter: TPanel; pnlOversample: TPanel; pnlLimit: TPanel; pnlTarget: TPanel; btnDonate: TButton; btnSaveLog: TButton; chkBinary: TCheckBox; ProgressBar2: TProgressBar; PBMem: TProgressBar; chkSaveIncompleteRenders: TCheckBox; lblCPUCores: TLabel; cbAspectRatio: TComboBox; chkEmbedFlame: TCheckBox; chkPlaySound: TCheckBox; btnSnapshot: TButton; ProgressTaskbar: TTaskbar; sbFilterRadius: TSpinButton; lblRatio: TPanel; procedure btnSaveLogClick(Sender: TObject); procedure btnDonateClick(Sender: TObject); procedure cbMaxMemoryChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure btnRenderClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure txtWidthChange(Sender: TObject); procedure txtHeightChange(Sender: TObject); procedure txtOversampleChange(Sender: TObject); procedure txtFilenameChange(Sender: TObject); procedure btnCancelClick(Sender: TObject); procedure txtDensityChange(Sender: TObject); procedure txtFilterRadiusExit(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure btnPauseClick(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure btnSavePresetClick(Sender: TObject); procedure btnBrowseClick(Sender: TObject); procedure btnDeletePresetClick(Sender: TObject); procedure cmbPresetChange(Sender: TObject); //procedure chkMaintainClick(Sender: TObject); procedure chkSaveIncompleteRendersClick(Sender: TObject); procedure btnGoToClick(Sender: TObject); procedure cbAspectRatioChange(Sender: TObject); procedure chkPlaySoundClick(Sender: TObject); procedure FormActivate(Sender: TObject); procedure btnSnapshotClick(Sender: TObject); procedure NumFieldKeyPress(Sender: TObject; var Key: Char); procedure sbFilterRadiusUpClick(Sender: TObject); procedure sbFilterRadiusDownClick(Sender: TObject); procedure txtDensityExit(Sender: TObject); procedure cbWidthExit(Sender: TObject); procedure cbHeightExit(Sender: TObject); procedure ProgressTaskbarThumbButtonClick(Sender: TObject; AButtonID: Integer); private StartTime, EndTime, oldElapsed, edt: TDateTime; oldProg: double; PhysicalMemory, ApproxMemory, TotalPhysicalMemory: int64; ApproxSamples: int64; procedure DoPostProcess; procedure HandleThreadCompletion(var Message: TMessage); message WM_THREAD_COMPLETE; procedure HandleThreadTermination(var Message: TMessage); message WM_THREAD_TERMINATE; procedure ListPresets; function WindowsExit(RebootParam: Longword = EWX_POWEROFF or EWX_FORCE): Boolean; procedure Save(const str: string); function IsLimitingMemory(): boolean; procedure OnProgress(prog: double); procedure ShowMemoryStatus; public Renderer: TRenderThread; //ColorMap: TColorMap; cp: TControlPoint; Filename: string; ImageWidth, ImageHeight, Oversample: Integer; Sample_Density, Filter_Radius: double; MaxMemory: integer; bRenderAll: boolean; RenderFlameFile: string; // AV FlameNames: array of string; // AV procedure ResetControls; end; function GetCpuCount: integer; // AV: this is used in Options function GetWinVersion: TWin32Version; // AV: moved from Main var RenderForm: TRenderForm; Ratio: double; implementation uses Main, Global, SavePreset, formPostProcess, ImageMaker, Tracer, Translation; {$R *.DFM} function TRenderForm.IsLimitingMemory():boolean; begin Result := (cbMaxMemory.ItemIndex > 0); end; procedure TRenderForm.ResetControls; begin txtFilename.Enabled := true; btnBrowse.Enabled := true; cbWidth.Enabled := true; cbHeight.Enabled := true; txtDensity.Enabled := true; txtFilterRadius.enabled := true; txtOversample.Enabled := true; //chkLimitMem.Enabled := true; cbMaxMemory.enabled := true; chkPostProcess.Enabled := not IsLimitingMemory; chkSaveIncompleteRenders.Enabled := not IsLimitingMemory; btnRender.Enabled := true; cmbPreset.enabled := true; btnSaveLog.Enabled := false; chkSave.enabled := true; chkPostProcess.enabled := true; chkShutdown.enabled := true; btnSavePreset.enabled := true; btnDeletePreset.enabled := true; btnCancel.Caption := TextByKey('common-close'); btnPause.enabled := false; //chkMaintain.Enabled := true; cbAspectRatio.Enabled := true; // AV btnSnapshot.Visible := false; // AV ProgressBar2.Position := 0; ProgressTaskBar.ProgressValue := 0; // AV ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV pnlWidth.Enabled := true; pnlHeight.Enabled := true; pnlDensity.Enabled := true; pnlFilter.Enabled := true; pnlOversample.Enabled := true; pnlLimit.Enabled := true; pnlTarget.Enabled := true; pnlWidth.Font.Color := clWindowText; pnlHeight.Font.Color := clWindowText; pnlDensity.Font.Color := clWindowText; pnlFilter.Font.Color := clWindowText; pnlOversample.Font.Color := clWindowText; pnlLimit.Font.Color := clWindowText; pnlTarget.Font.Color := clWindowText; ShowMemoryStatus; end; function GetCpuCount: integer; var si: TSystemInfo; begin; GetSystemInfo(si); Result := si.dwNumberOfProcessors; end; procedure TRenderForm.ShowMemoryStatus; var GlobalMemoryInfo: TMemoryStatus; // holds the global memory status information begin GlobalMemoryInfo.dwLength := SizeOf(GlobalMemoryInfo); GlobalMemoryStatus(GlobalMemoryInfo); PhysicalMemory := GlobalMemoryInfo.dwAvailPhys div 1048576; TotalPhysicalMemory := GlobalMemoryInfo.dwTotalPhys div 1048576; //TotalPhysicalMemory := TotalPhysicalMemory * 9 div 10; // assume that OS will take 10% of RAM ;) {$ifdef CPUX86} ApproxMemory := int64(ImageHeight) * int64(ImageWidth) * sqr(Oversample) * 16 div 1048576; {$else} ApproxMemory := int64(ImageHeight) * int64(ImageWidth) * sqr(Oversample) * 32 div 1048576; {$endif} lblMemory.Caption := Format(TextByKey('render-resourceusage-infotext'), [ApproxMemory, PhysicalMemory]); PBMem.Position := round(100 * (ApproxMemory / PhysicalMemory)); if ApproxMemory > PhysicalMemory then // AV: adapted for GUI styles begin // AV: exclude the style for the font to set its color properly lblMemory.StyleElements := [seClient, seBorder]; lblMemory.Font.Color := clRed; end else begin lblMemory.StyleElements := [seClient, seBorder, seFont]; lblMemory.Font.Color := clWindowText; end; if NrTreads > GetCpuCount then NrTreads := GetCpuCount; // AV: only actual Nrs { lblCpuCores.Font.Color := clRed else lblCpuCores.Font.Color := clWindowText; } lblCPUCores.Caption := Format(TextByKey('render-resourceusage-infotext2'), [NrTreads, GetCpuCount]); //btnRender.Enabled := (ApproxMemory <= PhysicalMemory) or (cbMaxMemory.ItemIndex > 0); if ApproxMemory > 0 then lblMaxbits.caption := format('%2.3f', [8 + log2( sample_density * sqr(power(2, cp.zoom)) * int64(ImageHeight) * int64(ImageWidth) / sqr(oversample) )]); end; procedure Trace2(const str: string); begin if TraceLevel >= 2 then RenderForm.Output.Lines.Add('. . ' + str); end; procedure TRenderForm.Save(const str:string); begin Renderer.SaveImage(FileName); end; procedure TRenderForm.sbFilterRadiusDownClick(Sender: TObject); // AV var n: double; begin try n := StrToFloat(txtFilterRadius.Text); n := RoundTo(n - 0.05, -3); if (n > 0) then txtFilterRadius.Text := FloatToStr(n); except raise Exception.Create(TextByKey('render-status-invalidfilterradius')); end; end; procedure TRenderForm.sbFilterRadiusUpClick(Sender: TObject); // AV var n: double; begin try n := StrToFloat(txtFilterRadius.Text); txtFilterRadius.Text := Format('%.3g', [n + 0.05]); except raise Exception.Create(TextByKey('render-status-invalidfilterradius')); end; end; procedure TRenderForm.HandleThreadCompletion(var Message: TMessage); var tryAgain: boolean; begin Trace2(MsgComplete + IntToStr(message.LParam)); if not assigned(Renderer) then begin Trace2(MsgNotAssigned); exit; end; if Renderer.ThreadID <> message.LParam then begin Trace2(MsgAnotherRunning); exit; end; EndTime := Now; repeat tryAgain := false; try Save(FileName); if ShowRenderImage then // AV if FileExists(FileName) then ShellExecute(Application.handle, PChar('open'), PChar(ExtractFileName(FileName)), nil, PChar(renderPath), SW_SHOWNORMAL); except on e: Exception do begin Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-saveerror-log')); tryAgain := (Application.MessageBox(PChar(TextByKey('render-status-saveerror-message1') + #13#10 + e.Message + #13#10 + TextByKey('render-status-saveerror-message2')), ApophysisSVN, MB_RETRYCANCEL or MB_ICONERROR) = IDRETRY); // AV: displaying status in red ProgressTaskBar.ProgressState := TTaskBarProgressState.Error; end; end; until tryAgain = false; if PlaySoundOnRenderComplete then if RenderCompleteSoundFile <> '' then sndPlaySound(PChar(RenderCompleteSoundFile), SND_FILENAME or SND_NOSTOP or SND_ASYNC) else sndPlaySound(pchar(SND_ALIAS_SYSTEMASTERISK), SND_ALIAS_ID or SND_NOSTOP or SND_ASYNC); PageCtrl.TabIndex := 1; if ShowRenderStats then Renderer.ShowBigStats else Renderer.ShowSmallStats; Output.Lines.Add(' ' + TextByKey('render-status-totaltime') + TimeToString(EndTime - StartTime)); Output.Lines.Add(''); ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV if not IsLimitingMemory and chkPostProcess.checked then DoPostProcess; Renderer.Free; Renderer := nil; if not bRenderAll then ResetControls; btnSaveLog.Enabled := true; if chkShutdown.Checked and not bRenderAll then WindowsExit; end; procedure TRenderForm.HandleThreadTermination(var Message: TMessage); begin Trace2(MsgTerminated + IntToStr(message.LParam)); if not assigned(Renderer) then begin Trace2(MsgNotAssigned); exit; end; if Renderer.ThreadID <> message.LParam then begin Trace2(MsgAnotherRunning); exit; end; { // AV: temporary commented out since undestroyed TBaseRenderer objects // from Renderer.GetRenderer method cause regular large memory leaks! if Renderer.GetRenderer.Hibernated then Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-renderhibernated')) else } Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-renderterminated')); Output.Lines.Add(''); ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV sndPlaySound(pchar(SND_ALIAS_SYSTEMEXCLAMATION), SND_ALIAS_ID or SND_NOSTOP or SND_ASYNC); PageCtrl.TabIndex := 0; // AV: moved from btnCancelClick Renderer.Free; Renderer := nil; ResetControls; btnSaveLog.Enabled := true; end; procedure TRenderForm.OnProgress(prog: double); var Elapsed, Remaining, dt: TDateTime; begin Elapsed := Now - StartTime; dt := Elapsed - oldElapsed; if (prog = 1.0) then begin StatusBar.Panels[0].text := Format(TextByKey('render-status-elapsed') + ': %2.2d:%2.2d:%2.2d.%2.2d', [Trunc(Elapsed * 24), Trunc(Elapsed * 24 * 60) mod 60, Trunc(Elapsed * 24 * 60 * 60) mod 60, Trunc(Elapsed * 24 * 60 * 60 * 100) mod 100]); StatusBar.Panels[1].text := TextByKey('render-status-remaining') + ': 00:00:00.00'; exit; end; //if (dt < 1/24/60/60/10) then exit; if (dt < 1/24/60/60) then exit; // PB: too much time consuming... was every 1/10th seconds! oldElapsed := Elapsed; prog := (Renderer.Slice + Prog) / Renderer.NrSlices; if ShowProgress then begin ProgressBar2.Position := round(100 * prog); // AV: to display the progress on the taskbar //ProgressTaskBar.ProgressState := TTaskBarProgressState.Normal; // AV ProgressTaskBar.ProgressValue := ProgressBar2.Position; // AV end; StatusBar.Panels[0].text := Format(TextByKey('render-status-elapsed') + ': %2.2d:%2.2d:%2.2d.%2.2d', [Trunc(Elapsed * 24), Trunc(Elapsed * 24 * 60) mod 60, Trunc(Elapsed * 24 * 60 * 60) mod 60, Trunc(Elapsed * 24 * 60 * 60 * 100) mod 100]); edt := edt + dt; if (edt > 1/24/60/60/2) and (prog > 0) then begin Remaining := (1 - prog) * edt / (prog - oldProg); edt := 0; oldProg := prog; StatusBar.Panels[1].text := Format(TextByKey('render-status-remaining') + ': %2.2d:%2.2d:%2.2d.%2.2d', [Trunc(Remaining * 24), Trunc(Remaining * 24 * 60) mod 60, Trunc(Remaining * 24 * 60 * 60) mod 60, Trunc(Remaining * 24 * 60 * 60 * 100) mod 100]); end; StatusBar.Panels[2].text := Format(TextByKey('render-status-slicestatus'), [(Renderer.Slice + 1), (Renderer.nrSlices)]); Application.ProcessMessages; end; procedure TRenderForm.ProgressTaskbarThumbButtonClick(Sender: TObject; AButtonID: Integer); begin if AButtonID = 0 then begin if Assigned(Renderer) and (not bRenderAll) then begin if Renderer.Suspended = false then begin Renderer.Suspend; btnSnapshotClick(Sender); Renderer.Resume; end else btnSnapshotClick(Sender); end; end else btnCancelClick(Sender); end; procedure TRenderForm.FormCreate(Sender: TObject); begin {$ifdef CPUX64} cbMaxMemory.Items.Add('2048'); cbMaxMemory.Items.Add('3072'); cbMaxMemory.Items.Add('4096'); {$endif} pnlWidth.Caption := TextByKey('common-width'); pnlHeight.Caption := TextByKey('common-height'); GroupBox2.Caption := TextByKey('common-size'); cbAspectRatio.Items[0] := TextByKey('adjustment-tab-size-custom'); // AV cbAspectRatio.Items[1] := TextByKey('common-keepaspect'); // AV lblRatio.Caption := TextByKey('adjustment-tab-size-ratio'); // AV pnlTarget.Caption := TextByKey('common-destination'); btnBrowse.Hint := TextByKey('common-browse'); GroupBox3.Caption := TextByKey('common-quality'); pnlFilter.Caption := TextByKey('common-filterradius'); pnlDensity.Caption := TextByKey('common-density'); pnlOversample.Caption := TextByKey('common-oversample'); btnRender.Caption := TextByKey('common-start'); btnPause.Caption := TextByKey('common-pause'); btnCancel.Caption := TextByKey('common-close'); self.Caption := TextByKey('render-title'); self.Hint := self.Caption; // AV: hack TabSettings.Caption := TextByKey('render-tab-settings-title'); TabOutput.Caption := TextByKey('render-tab-output-title'); btnGoTo.Hint := TextByKey('render-common-gotofolder'); GroupBox4.Caption := TextByKey('render-resourceusage-title'); pnlLimit.Caption := TextByKey('render-resourceusage-limit'); chkSave.Caption := TextByKey('render-output-saveparams1'); chkEmbedFlame.Caption := TextByKey('render-output-saveparams2'); GroupBox6.Caption := TextByKey('render-completion-title'); chkPostProcess.Caption := TextByKey('render-completion-postprocess'); chkShutdown.Caption := TextByKey('render-completion-shutdown'); chkPlaySound.Caption := TextByKey('render-completion-playsound'); chkSaveIncompleteRenders.Caption := TextByKey('render-completion-saveincomplete'); cbMaxMemory.Items[0] := TextByKey('render-resourceusage-nolimit') ; Groupbox1.Caption := TextByKey('render-output-title'); Groupbox5.Caption := TextByKey('render-presets-title'); btnSavePreset.Hint := TextByKey('render-presets-save'); btnDeletePreset.Hint := TextByKey('render-presets-delete'); btnDonate.Caption := TextByKey('common-donate'); btnDonate.Hint := TextByKey('common-donatehint'); btnSnapshot.Caption := TextByKey('render-status-dosnapshot'); // AV btnSnapshot.Hint := TextByKey('render-status-dosnapshothint'); ProgressTaskbar.TaskbarButtons[1].Hint := TextByKey('render-status-stop'); ProgressTaskbar.TaskbarButtons[0].Hint := TextByKey('render-status-showimage'); // AV: fixed the filter order and moved this here since it never changes SaveDialog.Filter := Format('%s|*.bmp;*.dib|%s|*.png|%s|*.jpg;*.jpeg|%s|*.bmp;*.dib;*.jpg;*.jpeg;*.png', [TextByKey('common-filter-bitmap'), TextByKey('common-filter-png'), TextByKey('common-filter-jpeg'), TextByKey('common-filter-allimages')]); cp := TControlPoint.Create; cbMaxMemory.ItemIndex := 0; cbAspectRatio.ItemIndex := 1; // AV MainForm.Buttons.GetBitmap(2, btnSavePreset.Glyph); // MainForm.Buttons.GetBitmap(9, btnDeletePreset.Glyph); bRenderAll := false; ListPresets; end; procedure TRenderForm.FormDestroy(Sender: TObject); begin if assigned(Renderer) then begin Renderer.Terminate; Renderer.WaitFor; Renderer.Free; end; cp.free; end; procedure TRenderForm.NumFieldKeyPress(Sender: TObject; var Key: Char); // AV var cs: TSysCharSet; begin cs := ['0'..'9', #8]; if Sender = txtFilterRadius then begin if (Key = ',') then Key := '.'; include(cs, '.'); end; if not CharInSet(Key, cs) then Key:= #0; end; procedure TRenderForm.btnRenderClick(Sender: TObject); var iCurrFlame: integer; t, ext: string; lim: integer; ilm: boolean; { sl: TStringList; tryAgain: boolean; cancel: boolean; result: integer; } begin // overwrite target with 0b file // this to test writability in output directory {sl := TStringList.Create; sl.Text := ''; repeat tryAgain := false; cancel := false; try sl.SaveToFile(txtFileName.Text); except on e: Exception do begin Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-saveerror-log')); result := (Application.MessageBox(PChar(TextByKey('render-status-saveerror-message1') + #13#10 + e.Message + #13#10 + TextByKey('render-status-saveerror-message2')), ApophysisSVN, MB_RETRYCANCEL or MB_ICONERROR)); tryAgain := (result = IDRETRY); cancel := (result = IDCANCEL); end; end; until (tryAgain = false) or (cancel = true); sl.Destroy; } //if (cancel) then Exit; Output.Text := ''; ImageWidth := StrToInt(cbWidth.text); ImageHeight := StrToInt(cbHeight.text); ilm := IsLimitingMemory; if (IsLimitingMemory) then begin lim := StrToInt(cbMaxMemory.text); MaxMemory := lim; end else lim := PhysicalMemory + 1; if not ilm then begin if (ApproxMemory > {Total}PhysicalMemory) then begin if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-notenoughmemory1')), ApophysisSVN, MB_ICONWARNING or MB_YESNO) then exit; end; end else if (PhysicalMemory < lim) and (Approxmemory > PhysicalMemory) then begin if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-notenoughmemory2')), ApophysisSVN, MB_ICONWARNING or MB_YESNO) then exit; end; t := txtFilename.Text; if t = '' then begin Application.MessageBox(PChar(TextByKey('render-status-nofilename')), ApophysisSVN, 48); exit; end; if FileExists(t) then if Application.MessageBox(PChar(Format(TextByKey('render-status-fileexists-message1'), [t]) + #13#10 + TextByKey('render-status-fileexists-message2')), ApophysisSVN, 52) = ID_NO then exit; if not DirectoryExists(ExtractFileDir(t)) then raise Exception.Create(TextByKey('render-status-pathdoesnotexist')); // AV {Check for invalid values } { AV: all MessageBoxes replaced by raised Exceptions for speed } if (sample_density <= 0) then raise Exception.Create(TextByKey('render-status-invaliddensity')); // AV if filter_radius <= 0 then raise Exception.Create(TextByKey('render-status-invalidfilterradius')); // AV { // AV: how is it possible, if (udOversample.Min = 1) and (txtOversample.ReadOnly = true)? if Oversample < 1 then raise Exception.Create(TextByKey('render-status-invalidoversample')); } if ImageWidth < 1 then raise Exception.Create(TextByKey('render-status-invalidwidth')); // AV if ImageHeight < 1 then raise Exception.Create(TextByKey('render-status-invalidheight')); // AV if (ilm) then if lim * 1024*1024 < ImageWidth * (int64(ImageHeight) * 4 + oversample) then begin // Must be enough memory to hold the final image (RGBA) if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-maxmemorytoosmall')), ApophysisSVN, MB_ICONERROR or MB_YESNO) then exit; end; // AV: activate the taskbar progress ProgressTaskBar.ProgressState := TTaskBarProgressState.Normal; // AV ProgressTaskBar.ProgressValue := 0; // AV txtFilename.Enabled := false; btnBrowse.Enabled := false; cbWidth.Enabled := False; cbHeight.Enabled := false; txtDensity.Enabled := false; txtFilterRadius.enabled := false; txtOversample.Enabled := false; //chkLimitMem.Enabled := true; cbMaxMemory.Enabled := false; cmbPreset.enabled := false; chkSave.enabled := false; chkPostProcess.enabled := false; chkShutdown.enabled := false; btnSavePreset.enabled := false; btnDeletePreset.enabled := false; btnRender.Enabled := false; btnSaveLog.Enabled := false; btnPause.enabled := true; btnCancel.Caption := TextByKey('common-cancel'); //chkMaintain.Enabled := false; cbAspectRatio.Enabled := False; StartTime := Now; pnlWidth.Enabled := false; pnlHeight.Enabled := false; pnlDensity.Enabled := false; pnlFilter.Enabled := false; pnlOversample.Enabled := false; pnlLimit.Enabled := false; pnlTarget.Enabled := false; pnlWidth.Font.Color := clGrayText; pnlHeight.Font.Color := clGrayText; pnlDensity.Font.Color := clGrayText; pnlFilter.Font.Color := clGrayText; pnlOversample.Font.Color := clGrayText; pnlLimit.Font.Color := clGrayText; pnlTarget.Font.Color := clGrayText; PageCtrl.TabIndex := 1; if Output.Lines.Count >= 1000 then Output.Lines.Clear; if bRenderAll then begin renderPath := ExtractFilePath(FileName); // AV ext := ExtractFileExt(FileName); // AV if Assigned(Renderer) then begin Output.Lines.Add(TimeToStr(Now) + TextByKey('render-status-shuttingdownrender')); Renderer.Terminate; Renderer.WaitFor; Renderer.Free; Renderer := nil; end; for iCurrFlame := 0 to High(FlameNames) {MainForm.ListView1.Items.Count-1} do begin { MainForm.ListView1.ItemIndex := iCurrFlame; cp.Free; cp := TControlPoint.Create; cp.Copy(MainCP); cp.cmap := maincp.cmap; zoom := maincp.zoom; Center[0] := MainForm.center[0]; Center[1] := MainForm.center[1]; } t := LoadXMLFlameText(RenderFlameFile, FlameNames[iCurrFlame]); // AV if t = '' then continue; // AV: user may delete an item from opened file MainForm.ParseXML(cp, t, true); // the same was done via ListView - but slower FileName := renderPath + cp.name + ext; Output.Lines.Add('--- ' + Format(TextByKey('render-status-log-title'), [ExtractFileName(FileName)]) + ' ---'); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-size'), [ImageWidth, ImageHeight])); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-quality'), [sample_density])); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-oversampling'), [oversample, filter_radius])); {$ifdef CPUX86} Output.Lines.Add(' ' + Format(TextByKey('render-status-log-bufferdepth'), ['32-bit float'])); {$else} Output.Lines.Add(' ' + Format(TextByKey('render-status-log-bufferdepth'), ['64-bit float'])); {$endif} if (ilm) then Output.Lines.Add(' ' + Format(TextByKey('render-status-log-memorylimit'), [MaxMemory])) else if (UpperCase(ext) = '.PNG') and (ImageWidth * ImageHeight >= 20000000) then begin Output.Lines.Add(TextByKey('render-status-log-largepng-message1')); Output.Lines.Add(TextByKey('render-status-log-largepng-message2')); Output.Lines.Add(TextByKey('render-status-log-largepng-message3')); end; if not Assigned(Renderer) then begin // disable screensaver SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, nil, 0); cp.sample_density := Sample_density; cp.spatial_oversample := Oversample; cp.spatial_filter_radius := Filter_Radius; cp.AdjustScale(ImageWidth, ImageHeight); cp.Transparency := (PNGTransparency <> 0) and (UpperCase(ext) = '.PNG'); // renderPath := ExtractFilePath(Filename); if chkSave.checked then begin // AV: added check for duplicates t := ExtractFileName(FileName); if XMLEntryExists(t, renderPath + rendersAV) then t := t + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); MainForm.SaveXMLFlame(cp, t, renderPath + rendersAV); end; oldProg := 0; oldElapsed := 0; edt := 0; ApproxSamples := Round(sample_density * sqr(power(2, cp.zoom)) * int64(ImageHeight) * int64(ImageWidth) / sqr(oversample) ); ProgressTaskBar.ProgressState := TTaskBarProgressState.Normal; // AV try if not bRenderAll then exit; if iCurrFlame = High(FlameNames){MainForm.ListView1.Items.Count-1} then bRenderAll := false; Renderer := TRenderThread.Create; assert(Renderer <> nil); { if chkThreadPriority.Checked then Renderer.SetPriority(tpLower) else Renderer.SetPriority(tpNormal); } //Renderer.ExportBuffer := chkBinary.Checked; if (ilm) then Renderer.MaxMem := lim; //StrToInt(cbMaxMemory.text); Renderer.OnProgress := OnProgress; Renderer.TargetHandle := self.Handle; Renderer.SetCP(cp); if chkEmbedFlame.checked then Renderer.EmbedText(Trim(FlameToXML(cp))); // AV Renderer.Priority := tpLower; // tpNormal; Renderer.NrThreads := NrTreads; Renderer.Output := Output.Lines; Renderer.Resume; if bRenderAll then Renderer.WaitFor; while Renderer <> nil do Application.ProcessMessages; // wait for HandleThreadCompletion except Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-rendererror-log')); end; end; end; if not Assigned(Renderer) then SetLength(FlameNames, 0); // AV: free memory end // end RenderAll else begin Output.Lines.Add('--- ' + Format(TextByKey('render-status-log-title'), [ExtractFileName(FileName)]) + '" ---'); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-size'), [ImageWidth, ImageHeight])); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-quality'), [sample_density])); Output.Lines.Add(' ' + Format(TextByKey('render-status-log-oversampling'), [oversample, filter_radius])); {$ifdef CPUX86} Output.Lines.Add(' ' + Format(TextByKey('render-status-log-bufferdepth'), ['32-bit float'])); {$else} Output.Lines.Add(' ' + Format(TextByKey('render-status-log-bufferdepth'), ['64-bit float'])); {$endif} if (ilm) then Output.Lines.Add(' ' + Format(TextByKey('render-status-log-memorylimit'), [lim])) else if (UpperCase(ExtractFileExt(FileName)) = '.PNG') and (ImageWidth * ImageHeight >= 20000000) then begin Output.Lines.Add(TextByKey('render-status-log-largepng-message1')); Output.Lines.Add(TextByKey('render-status-log-largepng-message2')); Output.Lines.Add(TextByKey('render-status-log-largepng-message3')); end; if Assigned(Renderer) then begin Output.Lines.Add(TimeToStr(Now) + TextByKey('render-status-shuttingdownrender')); Renderer.Terminate; Renderer.WaitFor; Renderer.Free; Renderer := nil; end; if not Assigned(Renderer) then begin // disable screensaver SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, nil, 0); cp.sample_density := Sample_density; cp.spatial_oversample := Oversample; cp.spatial_filter_radius := Filter_Radius; cp.AdjustScale(ImageWidth, ImageHeight); cp.Transparency := (PNGTransparency <> 0) and (UpperCase(ExtractFileExt(FileName)) = '.PNG'); renderPath := ExtractFilePath(Filename); if chkSave.checked then begin // AV: added check for duplicates t := ExtractFileName(FileName); if XMLEntryExists(t, renderPath + rendersAV) then t := t + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); MainForm.SaveXMLFlame(cp, t, renderPath + rendersAV); end; oldProg := 0; oldElapsed := 0; edt := 0; ApproxSamples := Round(sample_density * sqr(power(2, cp.zoom)) * int64(ImageHeight) * int64(ImageWidth) / sqr(oversample) ); try Renderer := TRenderThread.Create; assert(Renderer <> nil); if (ilm) then Renderer.MaxMem := lim; //StrToInt(cbMaxMemory.text); //Renderer.ExportBuffer := chkBinary.Checked; Renderer.OnProgress := OnProgress; Renderer.TargetHandle := self.Handle; Renderer.SetCP(cp); if chkEmbedFlame.checked then Renderer.EmbedText(Trim(FlameToXML(cp))); // AV { if chkThreadPriority.Checked then Renderer.SetPriority(tpLower) else Renderer.SetPriority(tpNormal); } Renderer.Priority := tpLower; Renderer.NrThreads := NrTreads; Renderer.Output := Output.Lines; Renderer.Resume; except Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-rendererror-log')); Application.MessageBox(PChar(TextByKey('render-status-rendererror-message')), ApophysisSVN, 48); end; end; end; // enable screensaver SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, nil, 0); end; procedure TRenderForm.FormShow(Sender: TObject); var Registry: TRegistry; begin { Read position from registry } Registry := TRegistry.Create; try Registry.RootKey := HKEY_CURRENT_USER; if Registry.OpenKey('Software\' + APP_NAME + '\Forms\Render', False) then begin if Registry.ValueExists('Left') then self.Left := Registry.ReadInteger('Left'); if Registry.ValueExists('Top') then self.Top := Registry.ReadInteger('Top'); end; Registry.CloseKey; finally Registry.Free; end; SaveDialog.FileName := Filename; case renderFileFormat of 1: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.bmp'); 2: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.png'); 3: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.jpg'); end; chkEmbedFlame.Enabled := (renderFileFormat = 2); // AV chkEmbedFlame.Checked := (chkEmbedFlame.Enabled and EmbedFlame); // AV chkSave.Checked := SaveInFlame; // AV if (renderOversample < 1) or (renderOversample > 4) then renderOversample := 2; // AV: prevent checks in future txtOversample.Text := IntToStr(renderOversample); Filter_Radius := max(renderFilterRadius, 0.1); // AV: fixed! txtFilterRadius.Text := FloatToStr(RoundTo(Filter_Radius, -3)); // AV // AV: fixed 'Floating point division by zero' bug sample_density := max(renderDensity, 10); txtDensity.Text := FloatToStr(sample_density); // AV: fixed '"" is not a valid integer' bug if bRenderAll then begin ImageWidth := max(renderWidth, 100); // AV ImageHeight := max(renderHeight, 100); // AV end else begin ImageWidth := cp.Width; // AV ImageHeight := cp.Height; // AV end; Ratio := ImageWidth / ImageHeight; cbWidth.Text := IntToStr(ImageWidth); // AV cbHeight.Text := IntToStr(ImageHeight); // AV ShowMemoryStatus; chkSaveIncompleteRenders.Checked := SaveIncompleteRenders; chkPlaySound.Checked := PlaySoundOnRenderComplete; // AV end; procedure TRenderForm.txtWidthChange(Sender: TObject); begin try ImageWidth := StrToInt(cbWidth.Text); if (cbAspectRatio.ItemIndex > 0) and cbWidth.Focused then begin ImageHeight := Round(ImageWidth / ratio); cbHeight.Text := IntToStr(ImageHeight) end; except end; ShowMemoryStatus; end; procedure TRenderForm.txtHeightChange(Sender: TObject); begin try ImageHeight := StrToInt(cbHeight.Text); if (cbAspectRatio.ItemIndex > 0) and cbHeight.Focused then begin ImageWidth := Round(ImageHeight * ratio); cbWidth.Text := IntToStr(ImageWidth) end; except end; ShowMemoryStatus; end; procedure TRenderForm.txtOversampleChange(Sender: TObject); var o: integer; begin try o := StrToInt(txtOversample.Text); except txtOversample.Text := IntToStr(Oversample); exit; end; { // AV: this text field is read-only, moved all checks to FormShow if o > udOversample.Max then begin o := udOversample.Max; txtOversample.Text := IntToStr(o); end else if o < udOversample.Min then begin o := udOversample.Min; txtOversample.Text := IntToStr(o); end; } Oversample := o; ShowMemoryStatus; end; procedure TRenderForm.txtFilenameChange(Sender: TObject); var ext : string; begin filename := txtFilename.text; ext := LowerCase(ExtractFileExt(filename)); chkEmbedFlame.Enabled := (ext = '.png'); // AV chkEmbedFlame.Checked := (chkEmbedFlame.Enabled and EmbedFlame); end; procedure TRenderForm.btnCancelClick(Sender: TObject); begin if Assigned(Renderer) or bRenderAll then begin if Assigned(Renderer) then if Renderer.Suspended then begin Renderer.Resume; btnPause.caption := TextByKey('common-pause'); end; if ConfirmStopRender then begin if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then exit; end; bRenderAll := false; if Assigned(Renderer) then begin if SaveIncompleteRenders and (not IsLimitingMemory) then Renderer.BreakRender else Renderer.Terminate; Renderer.WaitFor; // ? end; ProgressTaskBar.ProgressValue := 0; // AV ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV end else Close; end; procedure TRenderForm.txtDensityChange(Sender: TObject); begin Sample_Density := StrToFloatDef(txtDensity.Text, renderDensity); // AV if Sample_Density > 0 then ShowMemoryStatus; end; procedure TRenderForm.txtDensityExit(Sender: TObject); // AV begin Sample_Density := StrToFloatDef(txtDensity.Text, renderDensity); txtDensity.Text := FloatToStr(Sample_Density); end; procedure TRenderForm.txtFilterRadiusExit(Sender: TObject); begin // AV: we don't need try - except here Filter_Radius := StrToFloatDef(txtFilterRadius.Text, renderFilterRadius); txtFilterRadius.Text := FloatToStr(Filter_Radius); // AV end; procedure TRenderForm.FormActivate(Sender: TObject); begin chkPlaySound.Checked := PlaySoundOnRenderComplete; // AV ShowMemoryStatus; //lblCPUCores.Refresh; end; procedure TRenderForm.FormClose(Sender: TObject; var Action: TCloseAction); var Ext: string; Registry: TRegistry; begin Ext := ExtractFileExt(txtFileName.Text); if Ext = '.bmp' then renderFileFormat := 1; if Ext = '.png' then renderFileFormat := 2; if (Ext = '.jpg') or (Ext = '.jpeg') then renderFileFormat := 3; renderFilterRadius := Filter_Radius; renderWidth := ImageWidth; renderHeight := ImageHeight; renderDensity := Sample_density; renderOversample := Oversample; EmbedFlame := chkEmbedFlame.Checked; // AV SaveInFlame := chkSave.Checked; // AV ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV if not Assigned(Renderer) then SetLength(FlameNames, 0); // AV: free memory { Write position to registry } Registry := TRegistry.Create; try Registry.RootKey := HKEY_CURRENT_USER; if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Render', True) then begin Registry.WriteInteger('Top', Top); Registry.WriteInteger('Left', Left); end; finally Registry.Free; end; end; procedure TRenderForm.btnPauseClick(Sender: TObject); begin if Assigned(Renderer) then if Renderer.Suspended = false then begin Renderer.Suspend; btnPause.caption := TextByKey('common-resume'); btnSnapshot.Visible := true; // AV // AV: displaying progress in yellow ProgressTaskBar.ProgressState := TTaskBarProgressState.Paused; end else begin Renderer.Resume; btnPause.caption := TextByKey('common-pause'); btnSnapshot.Visible := false; // AV // AV: restore the taskbar progress ProgressTaskBar.ProgressState := TTaskBarProgressState.Normal; end; end; procedure TRenderForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if Assigned(Renderer) then if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then CanClose := False else begin if Assigned(Renderer) then begin // AV: prevent Apo perpetual hanging when render is paused if Renderer.Suspended then Renderer.Resume; // AV Renderer.Terminate; Renderer.WaitFor; Renderer.Free; // AV Renderer := nil; // AV ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV end; end; end; procedure TRenderForm.btnSavePresetClick(Sender: TObject); var IFile: TextFile; Title, Filename: string; begin SavePresetForm.txtPresetName.Text := cmbPreset.Text; if SavePresetForm.ShowModal = mrOK then begin Title := Trim(SavePresetForm.txtPresetName.Text); Filename := AppPath + 'Render presets.av'; try AssignFile(IFile, FileName); if FileExists(FileName) then begin if EntryExists(Title, FileName) then DeleteEntry(Title, FileName); Append(IFile); end else ReWrite(IFile); WriteLn(IFile, Title + ' {'); WriteLn(IFile, Trim(cbWidth.text)); WriteLn(IFile, Trim(cbHeight.text)); WriteLn(IFile, Trim(txtDensity.text)); WriteLn(IFile, Trim(txtFilterRadius.text)); WriteLn(IFile, Trim(txtOversample.text)); WriteLn(IFile, ExtractFileExt(txtFileName.Text)); if (not IsLimitingMemory) then WriteLn(IFile, 'true') else WriteLn(IFile, 'false'); WriteLn(IFile, IntToStr(cbMaxMemory.ItemIndex)); WriteLn(IFile, '}'); WriteLn(IFile, ''); CloseFile(IFile); except on EInOutError do begin Application.MessageBox(PChar(TextByKey('render-prestatus-saveerror-preset')), ApophysisSVN, 16); Exit; end; end; ListPresets; cmbPreset.ItemIndex := cmbPreset.Items.count - 1; end; end; procedure TRenderForm.btnSnapshotClick(Sender: TObject); var tryAgain: boolean; begin if Assigned(Renderer) then if Renderer.Suspended = true then begin repeat tryAgain := false; try Renderer.DoSnapshot; // AV: to save mid-render images Renderer.SaveImage(FileName); // AV: show saved image if needed if ShowRenderImage or (Sender = ProgressTaskbar.TaskBarButtons[0]) then if FileExists(FileName) then ShellExecute(Application.handle, PChar('open'), PChar(ExtractFileName(FileName)), nil, PChar(renderPath), SW_SHOWNORMAL); except on e: Exception do begin Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-saveerror-log')); tryAgain := (Application.MessageBox(PChar(TextByKey('render-status-saveerror-message1') + #13#10 + e.Message + #13#10 + TextByKey('render-status-saveerror-message1')), 'Error', MB_RETRYCANCEL or MB_ICONERROR) = IDRETRY); // AV: displaying status in red ProgressTaskBar.ProgressState := TTaskBarProgressState.Error; end; end; until tryAgain = false; end; end; procedure TRenderForm.btnBrowseClick(Sender: TObject); var fn, ext: string; begin SaveDialog.Filename := Filename; case renderFileFormat of 1: SaveDialog.DefaultExt := 'bmp'; 2: SaveDialog.DefaultExt := 'png'; 3: SaveDialog.DefaultExt := 'jpg'; end; SaveDialog.FilterIndex := renderFileFormat; if SaveDialog.Execute then begin fn := SaveDialog.FileName; ext := LowerCase(ExtractFileExt(fn)); if (ext = '.jpg') or (ext = '.jpeg')then renderFileFormat := 3 else if (ext = '.png') then renderFileFormat := 2 else // if (ext = '.bmp') or (ext = '.dib') then renderFileFormat := 1; txtFileName.Text := ChangeFileExt(fn, ext); renderPath := ExtractFilePath(fn); end; end; procedure TRenderForm.ListPresets; { List identifiers in file } var i, p: integer; Title: string; FStrings: TStringList; begin FStrings := TStringList.Create; try if fileExists(AppPath + 'Render presets.av') then begin FStrings.LoadFromFile(AppPath + 'Render presets.av'); cmbPreset.Clear; if (Pos('{', FStrings.Text) <> 0) then begin for i := 0 to FStrings.Count - 1 do begin p := Pos('{', FStrings[i]); if (p <> 0) then begin Title := Trim(Copy(FStrings[i], 1, p - 1)); if Title <> '' then begin cmbPreset.Items.add(Copy(FStrings[i], 1, p - 1)); end; end; end; end; end; finally FStrings.Free; end; end; procedure TRenderForm.btnDeletePresetClick(Sender: TObject); var Title, Filename: string; begin Title := Trim(cmbPreset.Text); if Title = '' then exit; Filename := AppPath + 'Render presets.av'; if EntryExists(Title, FileName) then DeleteEntry(Title, FileName); ListPresets; end; procedure TRenderForm.cmbPresetChange(Sender: TObject); var chk: shortint; // AV i, j: integer; FStrings: TStringList; Title, Filename: string; begin Title := Trim(cmbPreset.Text); Filename := AppPath + 'Render presets.av'; // AV: added file extension if Title = '' then exit; if EntryExists(Title, FileName) then begin // Load preset FStrings := TStringList.Create; try FStrings.LoadFromFile(Filename); for i := 0 to FStrings.Count - 1 do if Pos(LowerCase(Title) + ' {', Lowercase(FStrings[i])) <> 0 then begin chk := cbAspectRatio.ItemIndex; // AV cbAspectRatio.ItemIndex := 0; j := i + 1; cbWidth.Text := FStrings[j]; inc(j); cbHeight.text := FStrings[j]; cbAspectRatio.ItemIndex := chk; inc(j); txtDensity.text := FStrings[j]; inc(j); txtFilterRadius.text := FStrings[j]; inc(j); txtOversample.text := FStrings[j]; inc(j); txtFileName.Text := ChangeFileExt(txtFileName.Text, FStrings[j]); inc(j, 2); // AV: avoiding conflicts with 32- and 64-bit versions cbMaxMemory.ItemIndex := min(StrToInt(FStrings[j]), cbMaxMemory.Items.Count-1); break; end; finally FStrings.Free; end end; ImageWidth := StrToInt(cbWidth.Text); ImageHeight := StrToInt(cbHeight.Text); Sample_Density := StrToFloat(txtDensity.Text); ShowMemoryStatus; end; procedure TRenderForm.DoPostProcess; begin frmPostProcess.cp := cp; frmPostProcess.SetRenderer(Renderer.GetRenderer); frmPostProcess.SetControlPoint(CP); frmPostProcess.SetImageName(FileName); frmPostProcess.Show; end; function GetWinVersion: TWin32Version; { Returns current version of a host Win32 platform } var wMinor, wMajor: integer; begin Result := wvUnknown; wMinor := Win32MinorVersion; // AV wMajor := Win32MajorVersion; // AV if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then if (wMajor > 4) or ((wMajor = 4) and (wMinor > 0)) then Result := wvWin98 else Result := wvWin95 else if wMajor <= 4 then Result := wvWinNT else if wMajor = 5 then begin // AV if wMinor = 0 then Result := wvWin2000 else if wMinor >= 1 then Result := wvWinXP end else if wMajor = 6 then begin // AV if wMinor = 0 then Result := wvWinVista else if wMinor >= 1 then Result := wvWin7 end else if wMajor >= 7 then Result := wvWinFutureFromOuterSpace; end; function TRenderForm.WindowsExit(RebootParam: Longword = EWX_POWEROFF or EWX_FORCE): Boolean; var TTokenHd: THandle; TTokenPvg: TTokenPrivileges; cbtpPrevious: DWORD; rTTokenPvg: TTokenPrivileges; pcbtpPreviousRequired: DWORD; tpResult: Boolean; WinVersion: TWin32Version; // AV const SE_SHUTDOWN_NAME = 'SeShutdownPrivilege'; begin WinVersion := GetWinVersion; // AV: we don't need to calc it many times if ((WinVersion = wvWinNT) or (WinVersion = wvWin2000) or (WinVersion = wvWinXP) or (WinVersion = wvWinVista) or (WinVersion = wvWin7) or (WinVersion = wvWinFutureFromOuterSpace)) then begin tpResult := OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, TTokenHd); if tpResult then begin tpResult := LookupPrivilegeValue(nil, SE_SHUTDOWN_NAME, TTokenPvg.Privileges[0].Luid); TTokenPvg.PrivilegeCount := 1; TTokenPvg.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED; cbtpPrevious := SizeOf(rTTokenPvg); pcbtpPreviousRequired := 0; if tpResult then Windows.AdjustTokenPrivileges(TTokenHd, False, TTokenPvg, cbtpPrevious, rTTokenPvg, pcbtpPreviousRequired); end; end; Result := ExitWindowsEx(RebootParam, 0); end; procedure TRenderForm.chkPlaySoundClick(Sender: TObject); begin PlaySoundOnRenderComplete := chkPlaySound.Checked; end; procedure TRenderForm.chkSaveIncompleteRendersClick(Sender: TObject); begin SaveIncompleteRenders := chkSaveIncompleteRenders.Checked; end; procedure TRenderForm.btnGoToClick(Sender: TObject); var path: string; begin path := ExtractFilePath(txtFilename.Text); if (path <> '') then WinShellExecute('open', path); end; procedure TRenderForm.cbAspectRatioChange(Sender: TObject); begin case cbAspectRatio.ItemIndex of 1: Ratio := ImageWidth / ImageHeight; // AV: replaced "Keep aspect ratio" 2: Ratio := 1.5; 3: Ratio := 4 / 3; 4: Ratio := 1.25; 5: Ratio := 16 / 9; 6: Ratio := 1.6; 7: Ratio := 21 / 9; end; end; procedure TRenderForm.cbHeightExit(Sender: TObject); // AV begin ImageHeight := StrToIntDef(cbHeight.Text, renderHeight); cbHeight.Text := IntToStr(ImageHeight); end; procedure TRenderForm.cbWidthExit(Sender: TObject); // AV begin ImageWidth := StrToIntDef(cbWidth.Text, renderWidth); cbWidth.Text := IntToStr(ImageWidth); end; procedure TRenderForm.cbMaxMemoryChange(Sender: TObject); begin //cbMaxMemory.enabled := IsLimitingMemory; chkPostProcess.Enabled := not IsLimitingMemory; chkSaveIncompleteRenders.Enabled := not IsLimitingMemory; //btnRender.Enabled := (ApproxMemory <= PhysicalMemory) or (cbMaxMemory.ItemIndex > 0); end; procedure TRenderForm.btnDonateClick(Sender: TObject); begin WinShellExecute('open', 'https://www.donationalerts.com/r/fract_alice'); end; procedure TRenderForm.btnSaveLogClick(Sender: TObject); var fn: string; sl: TStringList; begin if OpenSaveFileDialog(RenderForm, '.log', Format('Render-Log (*.txt;*.log)|*.txt;*.log|%s|*.*', [TextByKey('common-filter-allfiles')]), SaveDialog.InitialDir, TextByKey('common-browse'), fn, false, true, false, false) then begin sl := TStringList.Create; sl.Text := Output.Text; sl.SaveToFile(fn); sl.Destroy; end; end; end.