{ 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 Global; interface uses Windows, SysUtils, Classes, SyncObjs, Controls, Graphics, Math, cmap, Xform, CommDlg; type TFileType = (ftApo, ftXML); // AV: moved here from ControlPoint { Misc } function OpenSaveFileDialog(Parent: TWinControl; const DefExt, Filter, InitialDir, Title: string; var FileName: string; MustExist, OverwritePrompt, NoChangeDir, DoOpen: Boolean): Boolean; procedure LoadThumbnailPlaceholder(ThumbnailSize : integer); function GetEnvVarValue(const VarName: string): string; function Round6(x: double): double; inline; function MiddleColor(const clOne, clTwo: TColor): TColor; // AV function CheckX64: Boolean; // AV const APP_NAME: string = 'Apophysis AV'; APP_VERSION: string = 'Phoenix Edition'; {$ifdef CPUX64} APP_BUILD: string = ' - 64 bit'; {$else} APP_BUILD: string = ' - 32 bit'; {$endif} // MAX_TRANSFORMS: integer = 100; // AV: why if we have NXFORMS? // eps: double = 1E-10; // AV: this one is used nowhere prefilter_white: integer = 1024; White_level = 200; //FT_BMP = 1; FT_PNG = 2; FT_JPG = 3; const crEditArrow = 20; crEditMove = 21; crEditRotate = 22; crEditScale = 23; var MainSeed: integer; Transforms: smallint; // Count of Tranforms EnableFinalXform: boolean; AppPath, AppData: string; // Path of application file OpenFile: string; // Name of currently open file CanDrawOnResize: boolean; AlwaysCreateBlankFlame : boolean; ThumbnailPlaceholder : TBitmap; WarnOnMissingPlugin : boolean; RandomizeTemplates: boolean; LanguageFile : string; AvailableLanguages : TStringList; PluginPath : string; (* PreserveWeights: boolean; StartupCheckForUpdates : boolean; EmbedThumbnails : boolean; *) { AV: GUI Theme Stuff } CurrentStyle: string; // theme-aware system colors WinColor, BrightColor, MidColor, TextColor: TColor; IsDarkTheme, IsLightMenu: boolean; { UPR Options } UPRSampleDensity: integer; UPRFilterRadius: double; UPROversample: byte; UPRAdjustDensity: boolean; UPRColoringIdent: string; UPRColoringFile: string; UPRFormulaIdent: string; UPRFormulaFile: string; UPRWidth: Integer; UPRHeight: Integer; UPRPath: string; // Name and folder of last UPR file { Editor } UseFlameBackground, UseTransformColors: boolean; HelpersEnabled: boolean; EditorBkgColor, ReferenceTriangleColor: TColor; GridColor1, GridColor2, HelpersColor, FlipColor: TColor; ExtEditEnabled, TransformAxisLock, RebuildXaosLinks: boolean; ShowAllXforms: boolean; EditorPreviewTransparency: integer; EnableEditorPreview: boolean; AllowResetCoefs, AllowResetLinear, UseTriangleSync: boolean; // AV { Display } defSampleDensity: Double; defGamma, defBrightness, defVibrancy, defContrast, // AV defFilterRadius, defGammaThreshold: Double; defOversample: byte; // integer; FUSE: byte; // AV: moved from ControlPoint and changed to variable RhombTR, SquareTR, HexTR: single; // AV: tile radii cmap_index: integer; // Index to current gradient { Render } renderDensity, renderFilterRadius: double; renderOversample, renderWidth, renderHeight: integer; renderPath: string; renderFileFormat: byte; // integer; EmbedFlame, SaveInFlame: boolean; // AV NrTreads: smallint; UseNrThreads: smallint; // AV: currently holds Nr CPU cores JPEGQuality: smallint; PNGTransparency: byte; // integer; ShowTransparency: boolean; MainPreviewScale: double; ExtendMainPreview: boolean; (* renderBitsPerSample: integer; InternalBitsPerSample: integer; StoreEXIF : boolean; StoreParamsEXIF : boolean; ExifAuthor : string; *) { Defaults } LastOpenFile: string; LastOpenFileEntry: integer; RememberLastOpenFile: boolean; UseSmallThumbnails: boolean; ClassicListMode: boolean; ConfirmDelete: boolean; // Flag confirmation of entry deletion OldPaletteFormat: boolean; ConfirmExit, ConfirmStopRender: boolean; ConfirmClearScript, ConfirmResetUndo: boolean; // AV SavePath, SmoothPalettePath: string; RandomPrefix, RandomDate: string; RandomIndex: integer; FlameFile, GradientFile, GradientEntry, FlameEntry: string; ParamFolder: string; prevLowQuality, prevMediumQuality, prevHighQuality: double; { Settings for smooth palette } SmoothPaletteFile, defSmoothPaletteFile: string; NumTries, TryLength: integer; ImageFolder: string; BrowserPath: string; // Stored path of browser open dialog EditPrevQual, MutatePrevQual, AdjustPrevQual: byte; // AV: menu item index ThumbPrevQual, AnimPrevQual: byte; // AV defFlameFile: string; defScriptFile: string; // AV SetEngLayout: boolean; // AV ScreenShotPath: string; // AV AutoSaveXML, ApplyFlatten: boolean; // AV PlaySoundOnRenderComplete: boolean; RenderCompleteSoundFile: string; SaveIncompleteRenders: boolean; ShowRenderStats, ShowRenderImage: boolean; LowerRenderPriority: boolean; { AV: Animation parameters } AnimFPS: word; defAnimPrefix: string; defFrameExt: shortint; CreateAnimFolder: boolean; SymmetryType: shortint; SymmetryOrder: smallint; SymmetryNVars: word; Variations: array of boolean; FavouriteVariations: array of boolean; MainForm_RotationMode: byte; // integer; PreserveQuality: boolean; FlameEnumMode: byte; // AV { For random gradients } MinNodes, MaxNodes, MinHue, MaxHue, MinSat, MaxSat, MinLum, MaxLum: integer; randGradient: shortint; randGradientFile: string; randColorBlend: byte; // AV EqualStripes: boolean; BatchSize: Integer; randMinTransforms, randMaxTransforms: smallint; mutantMinTransforms, mutantMaxTransforms: smallint; KeepBackground: boolean; RandBackColor: TColor; // AV { Scripting } Favorites: TStringList; Script: string; ScriptPath: string; flam3Path, helpPath: string; ExportWidth, ExportHeight: Integer; ExportOversample, ExportFileFormat: byte; // AV ExportFilter, ExportDensity, ExportGammaTreshold: Double; ExportEstimator, ExportEstimatorMin, ExportEstimatorCurve: double; (* // AV: user cannot change them, anyway ReferenceMode: integer; Compatibility: integer; //0 = original, 1 = Drave's SheepServer, SheepNick, SheepURL, SheepPW: string; ExportBatches, ExportJitters: byte; ResizeOnLoad: Boolean; *) OpenFileType: TFileType; ShowProgress: Boolean; defLibrary: string; LimitVibrancy: Boolean; DefaultPalette: TColorMap; ChaoticaPath: string; UseX64IfPossible: boolean; AutoOpenLog: Boolean; AutoSaveEnabled: Boolean; AutoSaveFreq: byte; AutoSavePath: string; LineCenterColor, LineThirdsColor, LineGRColor : TColor; EnableGuides : boolean; implementation function GetEnvVarValue(const VarName: string): string; var BufSize: Integer; // buffer size required for value begin // Get required buffer size (inc. terminal #0) BufSize := GetEnvironmentVariable(PChar(VarName), nil, 0); if BufSize > 0 then begin // Read env var value into result string SetLength(Result, BufSize - 1); GetEnvironmentVariable(PChar(VarName), PChar(Result), BufSize); end else // No such environment variable Result := ''; end; procedure LoadThumbnailPlaceholder(ThumbnailSize : integer); var placeholderIcon: TBitmap; const pi_width = 48; pi_height = 48; begin placeholderIcon := TBitmap.Create; placeholderIcon.Handle := LoadBitmap(hInstance, 'THUMB_PLACEHOLDER'); // AV: replaced a local variable by the global one ThumbnailPlaceholder.PixelFormat := pf32bit; ThumbnailPlaceholder.HandleType := bmDIB; ThumbnailPlaceholder.Width := ThumbnailSize; ThumbnailPlaceholder.Height := ThumbnailSize; with ThumbnailPlaceholder.Canvas do begin Brush.Color := $000000; FillRect(Rect(0, 0, ThumbnailPlaceholder.Width, ThumbnailPlaceholder.Height)); Draw((ThumbnailSize - pi_width) shr 1, (ThumbnailSize - pi_height) shr 1, placeholderIcon); end; placeholderIcon.Free; end; function MiddleColor(const clOne, clTwo: TColor): TColor; // AV begin Result := (((clOne and $ff) + (clTwo and $ff)) shr 1 ) + ((((clOne shr 8) and $ff) + ((clTwo shr 8) and $ff)) shr 1 ) shl 8 + ((((clOne shr 16) and $ff) + ((clTwo shr 16) and $ff)) shr 1 ) shl 16; end; function Round6(x: double): double; // Really ugly, but it works begin // --Z-- this is ridiculous: // Result := StrToFloat(Format('%.6f', [x])); // and yes, this is REALLY ugly :-\ Result := RoundTo(x, -6); end; function CheckX64: Boolean; // AV var IsWow64Process: function(hProcess: THandle; out Wow64Process: boolean): boolean; stdcall; Wow64Process: boolean; begin {$ifdef CPUX64} Result := True; {$else} IsWow64Process := GetProcAddress(GetModuleHandle('kernel32.dll'), 'IsWow64Process'); Wow64Process := False; if Assigned(IsWow64Process) then Wow64Process := IsWow64Process(GetCurrentProcess, Wow64Process) and Wow64Process; Result := Wow64Process; {$endif} end; function ReplaceStr(Str, SearchStr, ReplaceStr: string): string; begin while Pos(SearchStr, Str) <> 0 do begin Insert(ReplaceStr, Str, Pos(SearchStr, Str)); system.Delete(Str, Pos(SearchStr, Str), Length(SearchStr)); end; Result := Str; end; function SplitFilter(const fText: String; const fSep: Char; fTrim: Boolean=false; fQuotes: Boolean=false): TStringList; var vI: Integer; vBuffer: String; vOn: Boolean; begin Result := TStringList.Create; vBuffer := ''; vOn := true; for vI := 1 to Length(fText) do begin if (fQuotes and(fText[vI] = fSep)and vOn)or(Not(fQuotes) and (fText[vI] = fSep)) then begin if fTrim then vBuffer := Trim(vBuffer); if vBuffer = '' then vBuffer := fSep; // !!! e.g. split(',**',',')... if vBuffer[1] = fSep then vBuffer := Copy(vBuffer, 2, Length(vBuffer)); Result.Add(vBuffer); vBuffer := ''; end; if fQuotes then begin if fText[vI] = '"' then begin vOn := Not(vOn); Continue; end; if (fText[vI] <> fSep)or((fText[vI] = fSep)and(vOn = false)) then vBuffer := vBuffer + fText[vI]; end else if fText[vI] <> fSep then vBuffer := vBuffer + fText[vI]; end; if vBuffer <> '' then begin if fTrim then vBuffer := Trim(vBuffer); Result.Add(vBuffer); end; end; function OpenSaveFileDialog(Parent: TWinControl; const DefExt, Filter, InitialDir, Title: string; var FileName: string; MustExist, OverwritePrompt, NoChangeDir, DoOpen: Boolean): Boolean; // uses commdlg var ofn: TOpenFileName; szFile: array[0..260] of Char; fa, fa2: TStringList; h,i,j,k,c : integer; cs, s : string; begin Result := False; FillChar(ofn, SizeOf(TOpenFileName), 0); with ofn do begin lStructSize := SizeOf(TOpenFileName); hwndOwner := Parent.Handle; lpstrFile := szFile; nMaxFile := SizeOf(szFile); if (Title <> '') then lpstrTitle := PChar(Title); if (InitialDir <> '') then lpstrInitialDir := PChar(InitialDir); StrPCopy(lpstrFile, FileName); lpstrFilter := PChar(ReplaceStr(Filter, '|', #0)+#0#0); fa := splitFilter(Filter, '|'); k := 0; c := (fa.Count div 2); for i := 0 to c - 1 do begin j := 2 * i + 1; cs := LowerCase(fa.Strings[j]); fa2 := splitFilter(cs, ';'); for h := 0 to fa2.Count - 1 do begin cs := fa2.Strings[h]; s := '*.' + LowerCase(DefExt); if (cs = s) then k := i; end; fa2.Free; //AV: fixed multiple memory leaks! end; fa.Free; // AV: fixed memory leak! nFilterIndex := k + 1; if DefExt <> '' then lpstrDefExt := PChar(DefExt); end; if MustExist then ofn.Flags := ofn.Flags or OFN_FILEMUSTEXIST; if OverwritePrompt then ofn.Flags := ofn.Flags or OFN_OVERWRITEPROMPT; if NoChangeDir then ofn.Flags := ofn.Flags or OFN_NOCHANGEDIR; if DoOpen then begin if GetOpenFileName(ofn) then begin Result := True; FileName := StrPas(szFile); end; end else begin if GetSaveFileName(ofn) then begin Result := True; FileName := StrPas(szFile); end; end end; // function OpenSaveFileDialog end.