476 lines
13 KiB
ObjectPascal
476 lines
13 KiB
ObjectPascal
{
|
|
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.
|
|
|