Apophysis-AV/Core/Global.pas

476 lines
13 KiB
ObjectPascal
Raw Normal View History

2022-03-08 12:25:51 -05:00
{
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
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
type
TFileType = (ftApo, ftXML); // AV: moved here from ControlPoint
2022-03-08 12:25:51 -05:00
{ 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;
2022-03-08 12:25:51 -05:00
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}
2022-03-08 12:25:51 -05:00
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
2022-03-08 12:25:51 -05:00
prefilter_white: integer = 1024;
White_level = 200;
//FT_BMP = 1; FT_PNG = 2; FT_JPG = 3;
2022-03-08 12:25:51 -05:00
const
crEditArrow = 20;
crEditMove = 21;
crEditRotate = 22;
crEditScale = 23;
var
MainSeed: integer;
Transforms: smallint; // Count of Tranforms
2022-03-08 12:25:51 -05:00
EnableFinalXform: boolean;
AppPath, AppData: string; // Path of application file
2022-03-08 12:25:51 -05:00
OpenFile: string; // Name of currently open file
CanDrawOnResize: boolean;
2022-03-08 12:25:51 -05:00
AlwaysCreateBlankFlame : boolean;
2022-03-08 12:25:51 -05:00
ThumbnailPlaceholder : TBitmap;
WarnOnMissingPlugin : boolean;
RandomizeTemplates: boolean;
LanguageFile : string;
AvailableLanguages : TStringList;
PluginPath : string;
(*
PreserveWeights: boolean;
StartupCheckForUpdates : boolean;
EmbedThumbnails : boolean;
*)
2022-03-08 12:25:51 -05:00
{ AV: GUI Theme Stuff }
2022-03-08 12:25:51 -05:00
CurrentStyle: string;
// theme-aware system colors
WinColor, BrightColor, MidColor, TextColor: TColor;
IsDarkTheme, IsLightMenu: boolean;
{ UPR Options }
UPRSampleDensity: integer;
UPRFilterRadius: double;
UPROversample: byte;
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
ExtEditEnabled, TransformAxisLock, RebuildXaosLinks: boolean;
ShowAllXforms: boolean;
EditorPreviewTransparency: integer;
EnableEditorPreview: boolean;
AllowResetCoefs, AllowResetLinear, UseTriangleSync: boolean; // AV
2022-03-08 12:25:51 -05:00
{ Display }
defSampleDensity: Double;
2022-03-08 12:25:51 -05:00
defGamma, defBrightness, defVibrancy, defContrast, // AV
defFilterRadius, defGammaThreshold: Double;
defOversample: byte; // integer;
2022-03-08 12:25:51 -05:00
FUSE: byte; // AV: moved from ControlPoint and changed to variable
RhombTR, SquareTR, HexTR: single; // AV: tile radii
cmap_index: integer; // Index to current gradient
2022-03-08 12:25:51 -05:00
{ Render }
renderDensity, renderFilterRadius: double;
renderOversample, renderWidth, renderHeight: integer;
renderPath: string;
renderFileFormat: byte; // integer;
2022-03-08 12:25:51 -05:00
EmbedFlame, SaveInFlame: boolean; // AV
NrTreads: smallint;
UseNrThreads: smallint; // AV: currently holds Nr CPU cores
2022-03-08 12:25:51 -05:00
JPEGQuality: smallint;
PNGTransparency: byte; // integer;
2022-03-08 12:25:51 -05:00
ShowTransparency: boolean;
MainPreviewScale: double;
ExtendMainPreview: boolean;
(*
renderBitsPerSample: integer;
InternalBitsPerSample: integer;
2022-03-08 12:25:51 -05:00
StoreEXIF : boolean;
StoreParamsEXIF : boolean;
ExifAuthor : string;
*)
2022-03-08 12:25:51 -05:00
{ 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
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
BrowserPath: string; // Stored path of browser open dialog
EditPrevQual, MutatePrevQual, AdjustPrevQual: byte; // AV: menu item index
ThumbPrevQual, AnimPrevQual: byte; // AV
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
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;
2022-03-08 12:25:51 -05:00
BatchSize: Integer;
randMinTransforms, randMaxTransforms: smallint;
mutantMinTransforms, mutantMaxTransforms: smallint;
KeepBackground: boolean;
RandBackColor: TColor; // AV
{ Scripting }
2022-03-08 12:25:51 -05:00
Favorites: TStringList;
Script: string;
ScriptPath: string;
2022-03-08 12:25:51 -05:00
flam3Path, helpPath: string;
ExportWidth, ExportHeight: Integer;
ExportOversample, ExportFileFormat: byte; // AV
ExportFilter, ExportDensity, ExportGammaTreshold: Double;
2022-03-08 12:25:51 -05:00
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;
*)
2022-03-08 12:25:51 -05:00
OpenFileType: TFileType;
ShowProgress: Boolean;
defLibrary: string;
LimitVibrancy: Boolean;
DefaultPalette: TColorMap;
ChaoticaPath: string;
UseX64IfPossible: boolean;
AutoOpenLog: Boolean;
AutoSaveEnabled: Boolean;
AutoSaveFreq: byte;
2022-03-08 12:25:51 -05:00
AutoSavePath: string;
LineCenterColor, LineThirdsColor, LineGRColor : TColor;
2022-03-08 12:25:51 -05:00
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);
2022-03-08 12:25:51 -05:00
if BufSize > 0 then
begin
// Read env var value into result string
SetLength(Result, BufSize - 1);
GetEnvironmentVariable(PChar(VarName), PChar(Result), BufSize);
2022-03-08 12:25:51 -05:00
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);
2022-03-08 12:25:51 -05:00
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}
2022-03-08 12:25:51 -05:00
IsWow64Process := GetProcAddress(GetModuleHandle('kernel32.dll'), 'IsWow64Process');
Wow64Process := False;
if Assigned(IsWow64Process) then
Wow64Process := IsWow64Process(GetCurrentProcess, Wow64Process) and Wow64Process;
Result := Wow64Process;
{$endif}
2022-03-08 12:25:51 -05:00
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
2022-03-08 12:25:51 -05:00
begin
if (fQuotes and(fText[vI] = fSep)and vOn)or(Not(fQuotes) and (fText[vI] = fSep)) then
2022-03-08 12:25:51 -05:00
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));
2022-03-08 12:25:51 -05:00
Result.Add(vBuffer);
vBuffer := '';
2022-03-08 12:25:51 -05:00
end;
if fQuotes then
begin
if fText[vI] = '"' then
2022-03-08 12:25:51 -05:00
begin
vOn := Not(vOn);
2022-03-08 12:25:51 -05:00
Continue;
end;
if (fText[vI] <> fSep)or((fText[vI] = fSep)and(vOn = false)) then
vBuffer := vBuffer + fText[vI];
2022-03-08 12:25:51 -05:00
end else
if fText[vI] <> fSep then
vBuffer := vBuffer + fText[vI];
2022-03-08 12:25:51 -05:00
end;
if vBuffer <> '' then
2022-03-08 12:25:51 -05:00
begin
if fTrim then vBuffer := Trim(vBuffer);
2022-03-08 12:25:51 -05:00
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.