From b1552d0ebcf765dafc6023be8814fddda1b821ea Mon Sep 17 00:00:00 2001 From: Alice Vital Date: Thu, 23 Jun 2022 13:22:32 +0300 Subject: [PATCH] Added transform syncronization, an animation module and made the app work faster --- ApophysisAV.dpr | 30 +- ApophysisAV.dproj | 40 +- ApophysisAV.res | Bin 234384 -> 234392 bytes ColorMap/GradientHlpr.pas | 22 +- ColorMap/cmap.pas | 123 +- ColorMap/cmapdata.pas | 4 +- Core/BaseVariation.pas | 4 +- Core/Bezier.pas | 4 + Core/Chaotica.pas | 66 +- Core/Global.pas | 511 +---- Core/Translation.pas | 92 +- Core/XFormMan.pas | 139 +- Flame/ControlPoint.pas | 1278 ++++++----- Flame/RndFlame.pas | 211 +- Flame/XForm.pas | 262 ++- Forms/About.dfm | 12 +- Forms/Adjust.dfm | 82 +- Forms/Adjust.pas | 261 ++- Forms/Animate.dfm | 981 ++++++++ Forms/Animate.pas | 831 +++++++ Forms/Browser.dfm | 6 +- Forms/Browser.pas | 58 +- Forms/ColorRangeForm.dfm | 46 +- Forms/ColorRangeForm.pas | 11 +- Forms/Curves.dfm | 125 - Forms/Curves.pas | 123 - Forms/Editor.dfm | 359 ++- Forms/Editor.pas | 1015 +++++--- Forms/FlameComment.dfm | 303 +++ Forms/FlameComment.pas | 76 + Forms/FormExport.dfm | 10 +- Forms/FormExport.pas | 67 +- Forms/FormExportC.dfm | 553 ----- Forms/FormExportC.pas | 257 --- Forms/FormFavorites.pas | 71 +- Forms/FormRender.dfm | 171 +- Forms/FormRender.pas | 419 ++-- Forms/Fullscreen.pas | 21 +- Forms/Main.dfm | 192 +- Forms/Main.pas | 3053 +++++++++++-------------- Forms/Mutate.dfm | 173 +- Forms/Mutate.pas | 218 +- Forms/Options.dfm | 1204 ++++++---- Forms/Options.pas | 592 +++-- Forms/Preview.pas | 24 +- Forms/Save.dfm | 100 +- Forms/Save.pas | 48 +- Forms/SavePreset.dfm | 11 +- Forms/SavePreset.pas | 16 +- Forms/ScriptForm.dfm | 8 +- Forms/ScriptForm.pas | 1018 ++++----- Forms/ScriptRender.pas | 45 +- Forms/SplashForm.pas | 5 +- Forms/Template.pas | 281 +-- Forms/Tracer.dfm | 8 +- Forms/Tracer.pas | 29 +- Forms/VarOrderForm.pas | 19 +- Forms/formPostProcess.dfm | 5 +- Forms/formPostProcess.pas | 24 +- HARLOWSI.TTF | Bin 55060 -> 0 bytes IO/Binary.pas | 177 ++ IO/CommandLine.pas | 48 + IO/MissingPlugin.pas | 99 + IO/Settings.pas | 1474 ++++++++++++ Rendering/BucketFillerThread.pas | 7 +- Rendering/ImageMaker.pas | 17 +- Rendering/RenderThread.pas | 2 +- Rendering/RenderingCommon.pas | 5 +- Rendering/RenderingImplementation.pas | 6 +- Rendering/RenderingInterface.pas | 33 +- System/CurvesControl.pas | 56 +- System/CustomDrawControl.pas | 1 + System/MathExpressions.pas | 337 +++ System/RegexHelper.pas | 8 +- System/sdStringTable.pas | 633 ----- Variations/varAffine3D.pas | 41 +- Variations/varCothSpiral.pas | 2 +- Variations/varCurl.pas | 3 +- Variations/varDisc2.pas | 11 +- Variations/varExponential.pas | 3 +- Variations/varGenericPlugin.pas | 39 +- Variations/varHeart.pas | 70 +- Variations/varJulia.pas | 6 +- Variations/varJulia3Djf.pas | 6 +- Variations/varJulia3Dz.pas | 6 +- Variations/varJuliaN.pas | 6 +- Variations/varJuliaScope.pas | 6 +- Variations/varNGon.pas | 13 +- Variations/varPDJ.pas | 3 +- Variations/varPopcorn2.pas | 6 +- Variations/varPostFalloff2.pas | 3 + Variations/varPostMobius.pas | 254 ++ Variations/varPostSinusoidal.pas | 3 +- Variations/varPower.pas | 82 +- Variations/varPreMobius.pas | 254 ++ Variations/varPreSinusoidal.pas | 3 +- Variations/varSinusoidal.pas | 3 +- Variations/varTanhSpiral.pas | 2 +- 98 files changed, 11657 insertions(+), 7788 deletions(-) create mode 100644 Forms/Animate.dfm create mode 100644 Forms/Animate.pas delete mode 100644 Forms/Curves.dfm delete mode 100644 Forms/Curves.pas create mode 100644 Forms/FlameComment.dfm create mode 100644 Forms/FlameComment.pas delete mode 100644 Forms/FormExportC.dfm delete mode 100644 Forms/FormExportC.pas delete mode 100644 HARLOWSI.TTF create mode 100644 IO/Binary.pas create mode 100644 IO/CommandLine.pas create mode 100644 IO/MissingPlugin.pas create mode 100644 IO/Settings.pas create mode 100644 System/MathExpressions.pas delete mode 100644 System/sdStringTable.pas create mode 100644 Variations/varPostMobius.pas create mode 100644 Variations/varPreMobius.pas diff --git a/ApophysisAV.dpr b/ApophysisAV.dpr index e7ff67f..4470ad9 100644 --- a/ApophysisAV.dpr +++ b/ApophysisAV.dpr @@ -2,7 +2,8 @@ Apophysis Copyright (C) 2001-2004 Mark Townsend Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + Apophysis "7X" Copyright (C) 2009-2013 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 @@ -29,14 +30,12 @@ uses Vcl.Themes, Vcl.Styles, Binary in 'IO\Binary.pas', - Base64 in 'IO\Base64.pas', - sdStringTable in 'System\sdStringTable.pas', - CustomDrawControl in 'System\CustomDrawControl.pas', - LibXmlComps in 'System\LibXmlComps.pas', LibXmlParser in 'System\LibXmlParser.pas', + LibXmlComps in 'System\LibXmlComps.pas', + CustomDrawControl in 'System\CustomDrawControl.pas', RegexHelper in 'System\RegexHelper.pas', CurvesControl in 'System\CurvesControl.pas', - {$ifndef Apo7X64} + {$ifndef CPUX64} AsmRandom in 'System\AsmRandom.pas', {$endif } Global in 'Core\Global.pas', @@ -60,6 +59,7 @@ uses BucketFillerThread in 'Rendering\BucketFillerThread.pas', RenderThread in 'Rendering\RenderThread.pas', ImageMaker in 'Rendering\ImageMaker.pas', + MathExpressions in 'System\MathExpressions.pas', varSinusoidal in 'Variations\varSinusoidal.pas', varLog in 'Variations\varLog.pas', varModulus in 'Variations\varModulus.pas', @@ -131,6 +131,7 @@ uses varPreCircleCrop in 'Variations\varPreCircleCrop.pas', varPreCrop in 'Variations\varPreCrop.pas', varPreFalloff2 in 'Variations\varPreFalloff2.pas', + varPreMobius in 'Variations\varPreMobius.pas', varPostBoarders2 in 'Variations\varPostBoarders2.pas', varPostBwraps in 'Variations\varPostBwraps.pas', varPostCurl in 'Variations\varPostCurl.pas', @@ -138,6 +139,7 @@ uses varPostCircleCrop in 'Variations\varPostCircleCrop.pas', varPostCrop in 'Variations\varPostCrop.pas', varPostFalloff2 in 'Variations\varPostFalloff2.pas', + varPostMobius in 'Variations\varPostMobius.pas', varPostSpherical in 'Variations\varPostSpherical.pas', varPostSinusoidal in 'Variations\varPostSinusoidal.pas', varProjective in 'Variations\varProjective.pas', @@ -178,30 +180,29 @@ uses SavePreset in 'Forms\SavePreset.pas' {SavePresetForm}, SplashForm in 'Forms\SplashForm.pas' {SplashWindow}, Template in 'Forms\Template.pas' {TemplateForm}, - Curves in 'Forms\Curves.pas' {CurvesForm}, Preview in 'Forms\Preview.pas' {PreviewForm}, FormFavorites in 'Forms\FormFavorites.pas' {FavoritesForm}, ScriptForm in 'Forms\ScriptForm.pas' {ScriptEditor}, ScriptRender in 'Forms\ScriptRender.pas' {ScriptRenderForm}, ColorRangeForm in 'Forms\ColorRangeForm.pas' {ColorSelection}, Chaos in 'Forms\Chaos.pas' {ChaosForm}, - VarOrderForm in 'Forms\VarOrderForm.pas' {VarOrder}; + VarOrderForm in 'Forms\VarOrderForm.pas' {VarOrder}, + Animate in 'Forms\Animate.pas' {AnimateForm}, + FlameComment in 'Forms\FlameComment.pas' {CommentForm}; {$R *.res} - {$R Apophysis.res} +{$R Apophysis.res} + begin - ReportMemoryLeaksOnShutdown := true; - InitializePlugins; - SplashWindow := TSplashWindow.Create(Application); SplashWindow.Show; Application.Initialize; SplashWindow.Update; - {$ifdef Apo7X64} + {$ifdef CPUX64} Application.Title := 'Apophysis AV (64 bit)'; {$else} Application.Title := 'Apophysis AV (32 bit)'; @@ -222,7 +223,6 @@ begin Application.CreateForm(TSaveForm, SaveForm); Application.CreateForm(TSavePresetForm, SavePresetForm); Application.CreateForm(TTemplateForm, TemplateForm); - Application.CreateForm(TCurvesForm, CurvesForm); Application.CreateForm(TPreviewForm, PreviewForm); Application.CreateForm(TFavoritesForm, FavoritesForm); Application.CreateForm(TScriptEditor, ScriptEditor); @@ -230,6 +230,8 @@ begin Application.CreateForm(TColorSelection, ColorSelection); Application.CreateForm(TChaosForm, ChaosForm); Application.CreateForm(TVarOrder, VarOrder); + Application.CreateForm(TAnimateForm, AnimateForm); + Application.CreateForm(TCommentForm, CommentForm); Application.UpdateFormatSettings := False; FormatSettings.DecimalSeparator := '.'; Application.Run; diff --git a/ApophysisAV.dproj b/ApophysisAV.dproj index 8d94345..32d412f 100644 --- a/ApophysisAV.dproj +++ b/ApophysisAV.dproj @@ -8,7 +8,7 @@ Application VCL 18.8 - Win32 + Win64 true @@ -58,7 +58,7 @@ true - CompanyName=;FileDescription=IFS Fractal Generator;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis Phoenix Edition;ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.1.0 + CompanyName=;FileDescription=IFS Fractal Generator;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis Phoenix Edition;ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.2.0 $(BDS)\bin\default_app.manifest ApophysisAV_Icon2.ico false @@ -86,7 +86,7 @@ ApophysisAV true "Cyan Night|VCLSTYLE|$(BDSCOMMONDIR)\Styles\CyanNight.vsf";"Ruby Graphite|VCLSTYLE|$(BDSCOMMONDIR)\Styles\RubyGraphite.vsf" - 1 + 2 ..\..\Out\x86\ @@ -95,7 +95,7 @@ true $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png - CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.1.0 + CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.2.0 ApophysisAV_Icon.ico @@ -105,7 +105,7 @@ Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png - CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.1.0 + CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.2.0 ApophysisAV_Icon.ico @@ -115,14 +115,14 @@ RELEASE;$(DCC_Define) - CompanyName=Alice V., Apophysis Developers;FileDescription=RIFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.1.0 + CompanyName=Alice V., Apophysis Developers;FileDescription=RIFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.2.0 true Debug ApophysisAV_Icon.ico true - CompanyName=Alice V., Apophysis Developers;FileDescription=RIFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV_64.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.1.0 + CompanyName=Alice V., Apophysis Developers;FileDescription=RIFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV_64.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.2.0 Debug ApophysisAV_Icon.ico @@ -130,13 +130,13 @@ DEBUG;$(DCC_Define) false true - CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.1.0;InternalName=ApophysisAV;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.1.0 + CompanyName=;FileDescription=IFS Fractal Editor;FileVersion=1.0.2.0;InternalName=ApophysisAV;LegalCopyright=Alice Koryagina;LegalTrademarks=;OriginalFilename=Apophysis AV "Phoenix Edition";ProductName=Apophysis Phoenix Edition;ProductVersion=1.0.2.0 true true Debug - CompanyName=Apophysis Developers Team;FileDescription=RIFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.1.0 + CompanyName=Apophysis Developers Team;FileDescription=RIFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.2.0 ApophysisAV_Icon1.ico @@ -145,7 +145,7 @@ true true Debug - CompanyName=Apophysis Developers Team;FileDescription=RIFS Fractal Editor;FileVersion=1.0.1.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV64.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.1.0 + CompanyName=Apophysis Developers Team;FileDescription=RIFS Fractal Editor;FileVersion=1.0.2.0;InternalName=Apophysis;LegalCopyright=© 2021 Alice V. Koryagina;LegalTrademarks=;OriginalFilename=ApophysisAV64.exe;ProductName=Apophysis AV "Phoenix Edition";ProductVersion=1.0.2.0 ApophysisAV_Icon.ico @@ -153,11 +153,9 @@ MainSource - - - - + + @@ -182,6 +180,7 @@ + @@ -253,6 +252,7 @@ + @@ -260,6 +260,7 @@ + @@ -334,9 +335,6 @@
TemplateForm
- -
CurvesForm
-
PreviewForm
@@ -358,6 +356,14 @@
VarOrder
+ +
AnimateForm
+ dfm +
+ +
CommentForm
+ dfm +
Cfg_2 diff --git a/ApophysisAV.res b/ApophysisAV.res index b3967136800e403f8c35ac67a32cc84b73ef92c0..01751d31be2f06af04c9f92ca9a16006b0547c88 100644 GIT binary patch delta 94 zcmbQRoNvZ*z6lD91``$KfrO(eCldn$10xVKO{|w?oG@{&GGorfgYOxQCU0b%&g{n^ tJlUJcnm?YwjKPFKk0F(z0*DzV_cHY}8a2x@x63j!0x{EeS!U+q2>@)47SjL# delta 86 zcmbQSoNodUDKKhGRFnr2j;5T93=9llJh5Juv18&~WyX|=2j4RqPTt5ko!NsyV6r!p jHM<@|DnkWB>g1_R{fvgqs?6=G%#1+Hv|W{%xp)Eq%^4N_ diff --git a/ColorMap/GradientHlpr.pas b/ColorMap/GradientHlpr.pas index d26d290..3b0c75d 100644 --- a/ColorMap/GradientHlpr.pas +++ b/ColorMap/GradientHlpr.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,19 +27,12 @@ unit GradientHlpr; interface uses - windows, Graphics, Cmap; - -const - PixelCountMax = 32768; - -type - pRGBTripleArray = ^TRGBTripleArray; - TRGBTripleArray = array[0..PixelCountMax - 1] of TRGBTriple; + Graphics, Cmap; type TGradientHelper = class private - procedure RGBBlend(a, b: integer; var Palette: TColorMap); + //procedure RGBBlend(a, b: integer; var Palette: TColorMap); public function GetGradientBitmap(Index: integer; const hue_rotation: double): TBitmap; function RandomGradient: TColorMap; @@ -81,7 +74,7 @@ begin Result := BitMap; end; -/////////////////////////////////////////////////////////////////////////////// +{//////////////////////////////////////////////////////////////////////////////} function TGradientHelper.RandomGradient: TColorMap; var a, b, i, n, nodes: integer; @@ -143,7 +136,8 @@ begin Result := Pal; end; -/////////////////////////////////////////////////////////////////////////////// +{//////////////////////////////////////////////////////////////////////////////} +(* // AV: how many duplicated code has this app... procedure TGradientHelper.RGBBlend(a, b: integer; var Palette: TColorMap); { Linear blend between to indices of a palette } var @@ -181,8 +175,8 @@ begin Palette[i mod 256][2] := Round(c); end; end; - -/////////////////////////////////////////////////////////////////////////////// +*) +{//////////////////////////////////////////////////////////////////////////////} initialization GradientHelper := TGradientHelper.create; finalization diff --git a/ColorMap/cmap.pas b/ColorMap/cmap.pas index fd07fbc..1bbac69 100644 --- a/ColorMap/cmap.pas +++ b/ColorMap/cmap.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -25,23 +25,32 @@ unit Cmap; interface -uses sysutils, classes; +uses cmapdata, SysUtils, Classes, Windows; + +// AV: moved following from Main unit and deleted all duplicates +const + PixelCountMax = 32768; type + pRGBTripleArray = ^TRGBTripleArray; + TRGBTripleArray = array[0..PixelCountMax - 1] of TRGBTriple; + TColorMap = array[0..255, 0..3] of integer; -type - EFormatInvalid = class(Exception); + EPaletteInvalid = class(Exception); // AV: renamed due to name-space conflicts const RANDOMCMAP = -1; - NRCMAPS = 704; + NRCMAPS = NMAPS + 1; //704; procedure GetCmap(var Index: integer; const hue_rotation: double; out cmap: TColorMap); procedure GetCmapName(var Index: integer; out Name: string); procedure rgb2hsv(const rgb: array of double; out hsv: array of double); procedure hsv2rgb(const hsv: array of double; out rgb: array of double); function GetGradient(FileName, Entry: string): string; +function GetVal(token: string): string; // AV: make public +function ReplaceTabs(str: string): string; // AV: make public +function CreatePalette(strng: string): TColorMap; // AV: moved from RndFlame function GetPalette(strng: string; var Palette: TColorMap): boolean; procedure GetTokens(s: string; var mlist: TStringList); procedure HSVBlend(a, b: integer; var Palette: TColorMap); // AV @@ -51,7 +60,7 @@ procedure Brighten(const n: byte; var r, g, b: byte); // AV implementation uses - cmapdata, Math; + Math; procedure rgb2hsv(const rgb: array of double; out hsv: array of double); var @@ -91,10 +100,6 @@ var f, p, q, t, v: double; begin try -// rgb[0] := 0; -// rgb[1] := 0; -// rgb[2] := 0; - j := floor(hsv[0]); f := hsv[0] - j; @@ -111,6 +116,11 @@ begin 5: begin rgb[0] := v; rgb[1] := p; rgb[2] := q; end; end; except on EMathError do + begin + rgb[0] := 0; + rgb[1] := 0; + rgb[2] := 0; + end; end; end; @@ -152,7 +162,6 @@ begin Name := CMapNames[Index]; end; - procedure RGBBlend(a, b: integer; var Palette: TColorMap); { Linear blend between to indices of a palette } var @@ -286,6 +295,83 @@ begin end; end; +function CreatePalette(strng: string): TColorMap; // AV: moved from RndFlame +{ Loads a palette from a gradient string } +var + Strings: TStringList; + index, i: integer; + Tokens: TStringList; + Indices, Colors: TStringList; + a, b: integer; +begin + Strings := TStringList.Create; + Tokens := TStringList.Create; + Indices := TStringList.Create; + Colors := TStringList.Create; + try + try + Strings.Text := strng; + if Pos('}', Strings.Text) = 0 then raise EPaletteInvalid.Create('No closing brace'); + if Pos('{', Strings[0]) = 0 then raise EPaletteInvalid.Create('No opening brace.'); + GetTokens(ReplaceTabs(strings.text), tokens); + Tokens.Text := Trim(Tokens.text); + i := 0; + while (Pos('}', Tokens[i]) = 0) and (Pos('opacity:', Lowercase(Tokens[i])) = 0) do + begin + if Pos('index=', LowerCase(Tokens[i])) <> 0 then + Indices.Add(GetVal(Tokens[i])) + else if Pos('color=', LowerCase(Tokens[i])) <> 0 then + Colors.Add(GetVal(Tokens[i])); + inc(i) + end; + for i := 0 to 255 do + begin + Result[i][0] := 0; + Result[i][1] := 0; + Result[i][2] := 0; + end; + if Indices.Count = 0 then raise EPaletteInvalid.Create('No color info'); + for i := 0 to Indices.Count - 1 do + begin + try + index := StrToInt(Indices[i]); + while index < 0 do inc(index, 400); + index := Round(Index * (255 / 399)); + indices[i] := IntToStr(index); + assert(index >= 0); + assert(index < 256); + a := StrToInt(Colors[i]); // AV: added precalc + Result[index][0] := a mod 256; + Result[index][1] := trunc(a / 256) mod 256; + Result[index][2] := trunc(a / 65536); + except + end; + end; + i := 1; + repeat + a := StrToInt(Trim(Indices[i - 1])); + b := StrToInt(Trim(Indices[i])); + RGBBlend(a, b, Result); + inc(i); + until i = Indices.Count; + if (Indices[0] <> '0') or (Indices[Indices.Count - 1] <> '255') then + begin + a := StrToInt(Trim(Indices[Indices.Count - 1])); + b := StrToInt(Trim(Indices[0])) + 256; + RGBBlend(a, b, Result); + end; + except on EPaletteInvalid do + begin + // + end; + end; + finally + Tokens.Free; + Strings.Free; + Indices.Free; + Colors.Free; + end; +end; function GetPalette(strng: string; var Palette: TColorMap): boolean; { Loads a palette from a gradient string } @@ -304,8 +390,10 @@ begin try try Strings.Text := strng; - if Pos('}', Strings.Text) = 0 then raise EFormatInvalid.Create('No closing brace'); - if Pos('{', Strings[0]) = 0 then raise EFormatInvalid.Create('No opening brace.'); + if Pos('}', Strings.Text) = 0 then + raise EPaletteInvalid.Create('No closing brace'); + if Pos('{', Strings[0]) = 0 then + raise EPaletteInvalid.Create('No opening brace.'); GetTokens(ReplaceTabs(Strings.Text), Tokens); i := 0; while (Pos('}', Tokens[i]) = 0) and (Pos('opacity:', Lowercase(Tokens[i])) = 0) do @@ -322,7 +410,8 @@ begin Palette[i][1] := 0; Palette[i][2] := 0; end; - if Indices.Count = 0 then raise EFormatInvalid.Create('No color info'); + if Indices.Count = 0 then + raise EPaletteInvalid.Create('No color info'); for i := 0 to Indices.Count - 1 do begin try @@ -330,8 +419,8 @@ begin while index < 0 do inc(index, 400); index := Round(Index * (255 / 399)); indices[i] := IntToStr(index); - assert(index>=0); - assert(index<256); + assert(index >= 0); + assert(index < 256); Palette[index][0] := StrToInt(Colors[i]) mod 256; Palette[index][1] := trunc(StrToInt(Colors[i]) / 256) mod 256; Palette[index][2] := trunc(StrToInt(Colors[i]) / 65536); @@ -351,7 +440,7 @@ begin b := StrToInt(Indices[0]) + 256; RGBBlend(a, b, Palette); end; - except on EFormatInvalid do + except on EPaletteInvalid do begin Result := False; end; diff --git a/ColorMap/cmapdata.pas b/ColorMap/cmapdata.pas index ba368e7..9d0b0bf 100644 --- a/ColorMap/cmapdata.pas +++ b/ColorMap/cmapdata.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -31,7 +31,7 @@ interface Const NMAPS = 703; - cmaps : array[0..NMAPS,0..255,0..2] of byte = + cmaps : array[0..NMAPS, 0..255, 0..2] of byte = ( // 0 south-sea-bather ((185, 234, 235), (193, 238, 235), (197, 242, 235), (201, 242, 235), diff --git a/Core/BaseVariation.pas b/Core/BaseVariation.pas index ac356c4..c1fbb16 100644 --- a/Core/BaseVariation.pas +++ b/Core/BaseVariation.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -94,7 +94,7 @@ const PI_2 = 1.5707963267948966192313216916398; // AV function fmod(x, y: double) : double; -procedure SinhCosh(const v: double; var sh, ch: double); // AV +procedure SinhCosh(const v: double; var sh, ch: double); inline; // AV implementation diff --git a/Core/Bezier.pas b/Core/Bezier.pas index 23bcae0..eee8fb0 100644 --- a/Core/Bezier.pas +++ b/Core/Bezier.pas @@ -24,6 +24,7 @@ procedure BezierSolve(t: double; src: BezierPoints; w: BezierWeights; var soluti function BezierFunc(t: double; src: BezierPoints; w: BezierWeights): double; implementation + procedure BezierCopy(src: BezierPoints; var tgt: BezierPoints); var i, n: integer; @@ -32,6 +33,7 @@ implementation for i := 0 to n - 1 do tgt[i] := src[i]; end; + procedure BezierSetRect(var points: BezierPoints; flip: boolean; rect: BezierRect); var i, n: integer; @@ -47,6 +49,7 @@ implementation points[i].y := f * (rect.y1 - rect.y0) + rect.y0; end; end; + procedure BezierUnsetRect(var points: BezierPoints; flip: boolean; rect: BezierRect); var i, n: integer; @@ -84,6 +87,7 @@ implementation solution.x := nom_x / denom; solution.y := nom_y / denom; end; + function BezierFunc(t: double; src: BezierPoints; w: BezierWeights): double; var p: BezierPoint; diff --git a/Core/Chaotica.pas b/Core/Chaotica.pas index 7eb1db6..82cb195 100644 --- a/Core/Chaotica.pas +++ b/Core/Chaotica.pas @@ -2,8 +2,11 @@ unit Chaotica; interface -uses Global, RegularExpressionsCore, RegexHelper, Classes, SysUtils, XFormMan, Windows, - ShellAPI, Forms, ControlPoint, Translation; +uses Global, RegularExpressionsCore, RegexHelper, Classes, SysUtils, + Windows, ShellAPI, ControlPoint, Translation; + +const + export_flame = 'chaotica_export.flame'; function C_GetPathOf(filename: string; usex64: boolean): string; function C_SupportsDllPlugins(usex64: boolean): boolean; @@ -12,13 +15,11 @@ function C_IsVariationNative(name: string; usex64: boolean): boolean; function C_IsDllPluginInstalled(filename: string): boolean; procedure C_SyncDllPlugins; -procedure C_InstallVariation(name: string); procedure C_ExecuteChaotica(flamexml: string; plugins: TStringList; usex64: boolean); +//procedure C_InstallVariation(name: string); implementation -uses Main; - (* // AV: rewrote and moved to Global unit function CheckX64: Boolean; var @@ -99,19 +100,19 @@ begin blacklist := TStringList.Create; if not FileExists(ChaoticaPath + '\plugin_dll_blacklist.txt') then begin - blacklist.Add('avMobius.dll'); - blacklist.Add('Cross.dll'); - blacklist.Add('Epispiral.dll'); - blacklist.Add('EpispiralVariationPlugin.dll'); - blacklist.Add('FlowerVariationPlugin.dll'); - blacklist.Add('Lissajous.dll'); - blacklist.Add('Mandelbrot.dll'); - blacklist.Add('ShapeVariationPlugin.dll'); - blacklist.Add('slinky.dll'); - blacklist.Add('Spirograph.dll'); - blacklist.Add('Square.dll'); - blacklist.Add('Stretchy Pants.dll'); - blacklist.Add('Waffle.dll'); + blacklist.Add('avMobius.dll'); + blacklist.Add('Cross.dll'); + blacklist.Add('Epispiral.dll'); + blacklist.Add('EpispiralVariationPlugin.dll'); + blacklist.Add('FlowerVariationPlugin.dll'); + blacklist.Add('Lissajous.dll'); + blacklist.Add('Mandelbrot.dll'); + blacklist.Add('ShapeVariationPlugin.dll'); + blacklist.Add('slinky.dll'); + blacklist.Add('Spirograph.dll'); + blacklist.Add('Square.dll'); + blacklist.Add('Stretchy Pants.dll'); + blacklist.Add('Waffle.dll'); blacklist.SaveToFile(ChaoticaPath + '\plugin_dll_blacklist.txt'); end; @@ -182,7 +183,7 @@ begin end; //////////////////////////////////////////////////////////////////// - +(* procedure C_InstallVariation(name: string); var filename: string; @@ -195,6 +196,7 @@ begin CopyFile(PCHAR(filename), PCHAR(C_GetPathOf('plugins\' + ExtractFileName(filename), false)), false); end; +*) procedure C_SyncDllPlugins; var @@ -243,19 +245,17 @@ var begin fails := TStringList.Create; - {$ifdef Apo7X64} + {$ifdef CPUX64} fin_usex64 := true; {$else} - fin_usex64 := usex64 and CheckX64; // currently useless... + fin_usex64 := usex64; // currently useless... for i := 0 to plugins.Count - 1 do begin - name := GetFileNameOfVariation(plugins.Strings[i]); - if (name = '') then name := plugins.Strings[i]; + name := plugins.Strings[i]; fin_usex64 := fin_usex64 and C_IsVariationNative(name, usex64); end; for i := 0 to plugins.Count - 1 do begin - name := GetFileNameOfVariation(plugins.Strings[i]); - if (name = '') then name := plugins.Strings[i]; // assume built-in + name := plugins.Strings[i]; // assume built-in if not C_IsVariationNative(name, fin_usex64) then begin // not native -> try install if C_SupportsDllPlugins(fin_usex64) then // dll unsupported -> fail @@ -271,17 +271,18 @@ begin name := C_GetPathOf('chaotica.exe', fin_usex64); if (not FileExists(name)) then begin messagebox(0, PCHAR(TextByKey('main-status-nochaotica')), - PCHAR('Apophysis AV'), MB_ICONHAND); + 'Apophysis AV', MB_ICONHAND); + fails.Free; // AV: fixed possible memory leak Exit; end; if (fails.Count > 0) then begin messagebox(0, PCHAR(TextByKey('main-status-oldchaotica')), - PCHAR('Apophysis AV'), MB_ICONHAND or MB_OK); + 'Apophysis AV', MB_ICONHAND or MB_OK); end; - // TODO: add directory cleaning - fname := GetEnvironmentVariable('TEMP') + '\chaotica_export.flame'; + // TODO: add directory cleaning // <-- AV: done + fname := APPDATA + export_flame; // AV: moved into app folder txt := TStringList.Create; txt.Text := flamexml; @@ -290,11 +291,8 @@ begin txt.Free; fails.Free; - //if fin_usex64 then MessageBox(0, PCHAR('DBG:x64'), PCHAR(''), MB_OK) - //else MessageBox(0, PCHAR('DBG:x86'), PCHAR(''), MB_OK) ; - - ShellExecute(application.handle, PChar('open'), pchar(name), - PChar('"' + fname + '"'), PChar(ExtractFilePath(name)), SW_SHOWNORMAL); + ShellExecute(0, PChar('open'), pchar(name), PChar('"' + fname + '"'), + PChar(ExtractFilePath(name)), SW_SHOWNORMAL); end; end. diff --git a/Core/Global.pas b/Core/Global.pas index 8d37eff..c7e9a91 100644 --- a/Core/Global.pas +++ b/Core/Global.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -28,29 +28,12 @@ interface uses Windows, SysUtils, Classes, SyncObjs, Controls, Graphics, Math, - cmap, ControlPoint, Xform, CommDlg; + cmap, Xform, CommDlg; type - EFormatInvalid = class(Exception); - // AV: chanded the name to avoid conflicts with XForm - TMatrix2 = array[0..1, 0..1] of double; + TFileType = (ftApo, ftXML); // AV: moved here from ControlPoint -{ Weight manipulation } -{ Triangle transformations } -function triangle_area(t: TTriangle): double; -function transform_affine(const t: TTriangle; const Triangles: TTriangles): boolean; -function line_dist(x, y, x1, y1, x2, y2: double): double; -function dist(x1, y1, x2, y2: double): double; -procedure MultMatrix(var s: TMatrix2; const m: TMatrix2); -{ Parsing functions } -function GetVal(token: string): string; -function ReplaceTabs(str: string): string; -{ Palette and gradient functions } -//function GetGradient(FileName, Entry: string): string; { Misc } -function det(a, b, c, d: double): double; -function solve3(x1, x2, x1h, y1, y2, y1h, z1, z2, z1h: double; - var a, b, e: double): double; function OpenSaveFileDialog(Parent: TWinControl; const DefExt, Filter, @@ -63,66 +46,53 @@ function OpenSaveFileDialog(Parent: TWinControl; DoOpen: Boolean): Boolean; procedure LoadThumbnailPlaceholder(ThumbnailSize : integer); function GetEnvVarValue(const VarName: string): string; -function Round6(x: double): double; +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 Apo7X64} + {$ifdef CPUX64} APP_BUILD: string = ' - 64 bit'; {$else} APP_BUILD: string = ' - 32 bit'; {$endif} - MAX_TRANSFORMS: integer = 100; - prefilter_white: integer = 1024; - eps: double = 1E-10; - White_level = 200; - FT_BMP = 1; FT_PNG = 2; FT_JPG = 3; - //clyellow1 = TColor($17FCFF); - //clplum2 = TColor($ECA9E6); - //clSlateGray = TColor($837365); + // 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; -const - SingleBuffer : boolean = - {$ifdef Apo7X64} - false - {$else} - true - {$endif}; - var MainSeed: integer; - MainTriangles: TTriangles; // ControlPoint.TTriangles; - Transforms: integer; // Count of Tranforms + Transforms: smallint; // Count of Tranforms EnableFinalXform: boolean; - AppPath: string; // Path of application file + AppPath, AppData: string; // Path of application file OpenFile: string; // Name of currently open file - CanDrawOnResize: boolean; - PreserveWeights: boolean; + CanDrawOnResize: boolean; AlwaysCreateBlankFlame : boolean; - // StartupCheckForUpdates : boolean; - TBWidth1 : integer; - TBWidth2 : integer; - TBWidth3 : integer; - TBWidth4 : integer; - TBWidth5 : integer; + ThumbnailPlaceholder : TBitmap; WarnOnMissingPlugin : boolean; - EmbedThumbnails : boolean; RandomizeTemplates: boolean; LanguageFile : string; AvailableLanguages : TStringList; PluginPath : string; + (* + PreserveWeights: boolean; + StartupCheckForUpdates : boolean; + EmbedThumbnails : boolean; + *) - // AV: GUI Theme Stuff + { AV: GUI Theme Stuff } CurrentStyle: string; // theme-aware system colors WinColor, BrightColor, MidColor, TextColor: TColor; @@ -132,7 +102,7 @@ var UPRSampleDensity: integer; UPRFilterRadius: double; - UPROversample: integer; + UPROversample: byte; UPRAdjustDensity: boolean; UPRColoringIdent: string; UPRColoringFile: string; @@ -140,59 +110,58 @@ var UPRFormulaFile: string; UPRWidth: Integer; UPRHeight: Integer; - ImageFolder: string; UPRPath: string; // Name and folder of last UPR file - cmap_index: integer; // Index to current gradient - Variation: TVariation; // Current variation // ControlPoint.TVariation; - NumTries, TryLength: integer; // Settings for smooth palette - SmoothPaletteFile: string; { Editor } UseFlameBackground, UseTransformColors: boolean; HelpersEnabled: boolean; - EditorBkgColor, ReferenceTriangleColor: integer; - GridColor1, GridColor2, HelpersColor, FlipColor: integer; + EditorBkgColor, ReferenceTriangleColor: TColor; + GridColor1, GridColor2, HelpersColor, FlipColor: TColor; ExtEditEnabled, TransformAxisLock, RebuildXaosLinks: boolean; ShowAllXforms: boolean; EditorPreviewTransparency: integer; EnableEditorPreview: boolean; - AllowResetCoefs, AllowResetLinear: boolean; // AV + AllowResetCoefs, AllowResetLinear, UseTriangleSync: boolean; // AV { Display } - defSampleDensity, defPreviewDensity: Double; + defSampleDensity: Double; defGamma, defBrightness, defVibrancy, defContrast, // AV defFilterRadius, defGammaThreshold: Double; - defOversample: integer; + 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; - // renderBitsPerSample: integer; renderPath: string; - JPEGQuality: integer; - renderFileFormat: integer; - InternalBitsPerSample: integer; + renderFileFormat: byte; // integer; + EmbedFlame, SaveInFlame: boolean; // AV - NrTreads: Integer; - UseNrThreads: byte; // AV: currently holds Nr CPU cores + NrTreads: smallint; + UseNrThreads: smallint; // AV: currently holds Nr CPU cores - PNGTransparency: integer; + JPEGQuality: smallint; + PNGTransparency: byte; // integer; ShowTransparency: boolean; MainPreviewScale: double; ExtendMainPreview: boolean; - (* +(* + renderBitsPerSample: integer; + InternalBitsPerSample: integer; + StoreEXIF : boolean; StoreParamsEXIF : boolean; ExifAuthor : string; - *) +*) { Defaults } @@ -203,27 +172,23 @@ var ClassicListMode: boolean; ConfirmDelete: boolean; // Flag confirmation of entry deletion OldPaletteFormat: boolean; - ConfirmExit: boolean; - ConfirmStopRender: boolean; - ConfirmClearScript: 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; - defSmoothPaletteFile: string; + + { Settings for smooth palette } + SmoothPaletteFile, defSmoothPaletteFile: string; + NumTries, TryLength: integer; + ImageFolder: string; + BrowserPath: string; // Stored path of browser open dialog - EditPrevQual, MutatePrevQual, AdjustPrevQual: byte; // Integer; - ThumbPrevQual: byte; // AV - randMinTransforms, randMaxTransforms: integer; - mutantMinTransforms, mutantMaxTransforms: integer; - KeepBackground: boolean; - RandBackColor: integer; // AV - randGradient: Integer; - randGradientFile: string; - randColorBlend: byte; // AV - EqualStripes: boolean; + EditPrevQual, MutatePrevQual, AdjustPrevQual: byte; // AV: menu item index + ThumbPrevQual, AnimPrevQual: byte; // AV defFlameFile: string; defScriptFile: string; // AV SetEngLayout: boolean; // AV @@ -237,9 +202,15 @@ var ShowRenderStats, ShowRenderImage: boolean; LowerRenderPriority: boolean; - SymmetryType: integer; - SymmetryOrder: integer; - SymmetryNVars: integer; + { 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; @@ -248,23 +219,38 @@ var FlameEnumMode: byte; // AV { For random gradients } - MinNodes, MaxNodes, MinHue, MaxHue, MinSat, MaxSat, MinLum, MaxLum: integer; - //ReferenceMode: integer; + randGradient: shortint; + randGradientFile: string; + randColorBlend: byte; // AV + EqualStripes: boolean; + BatchSize: Integer; - // Compatibility: integer; //0 = original, 1 = Drave's + randMinTransforms, randMaxTransforms: smallint; + mutantMinTransforms, mutantMaxTransforms: smallint; + KeepBackground: boolean; + RandBackColor: TColor; // AV + + { Scripting } Favorites: TStringList; Script: string; ScriptPath: string; - // SheepServer, SheepNick, SheepURL, SheepPW, + flam3Path, helpPath: string; - ExportBatches, ExportOversample, ExportWidth, ExportHeight, ExportFileFormat: Integer; - ExportFilter, ExportDensity: Double; + ExportWidth, ExportHeight: Integer; + ExportOversample, ExportFileFormat: byte; // AV + ExportFilter, ExportDensity, ExportGammaTreshold: Double; ExportEstimator, ExportEstimatorMin, ExportEstimatorCurve: double; - ExportJitters: integer; - ExportGammaTreshold: 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; -// ResizeOnLoad: Boolean; ShowProgress: Boolean; defLibrary: string; LimitVibrancy: Boolean; @@ -275,12 +261,10 @@ var AutoOpenLog: Boolean; AutoSaveEnabled: Boolean; - AutoSaveFreq: integer; + AutoSaveFreq: byte; AutoSavePath: string; - LineCenterColor : integer; - LineThirdsColor : integer; - LineGRColor : integer; + LineCenterColor, LineThirdsColor, LineGRColor : TColor; EnableGuides : boolean; implementation @@ -290,14 +274,12 @@ var BufSize: Integer; // buffer size required for value begin // Get required buffer size (inc. terminal #0) - BufSize := GetEnvironmentVariable( - PChar(VarName), nil, 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); + GetEnvironmentVariable(PChar(VarName), PChar(Result), BufSize); end else // No such environment variable @@ -322,7 +304,8 @@ begin with ThumbnailPlaceholder.Canvas do begin Brush.Color := $000000; FillRect(Rect(0, 0, ThumbnailPlaceholder.Width, ThumbnailPlaceholder.Height)); - Draw(round(ThumbnailSize / 2 - pi_width / 2), round(ThumbnailSize / 2 - pi_height / 2), placeholderIcon); + Draw((ThumbnailSize - pi_width) shr 1, (ThumbnailSize - pi_height) shr 1, + placeholderIcon); end; placeholderIcon.Free; @@ -335,13 +318,6 @@ begin ((((clOne shr 16) and $ff) + ((clTwo shr 16) and $ff)) shr 1 ) shl 16; end; -{ IFS } - -function det(a, b, c, d: double): double; -begin - Result := (a * d - b * c); -end; - function Round6(x: double): double; // Really ugly, but it works begin @@ -351,281 +327,15 @@ begin Result := RoundTo(x, -6); end; -procedure MultMatrix(var s: TMatrix2; const m: TMatrix2); // AV: moved from Main -var - a, b, c, d, e, f, g, h: double; -begin - a := s[0, 0]; - b := s[0, 1]; - c := s[1, 0]; - d := s[1, 1]; - e := m[0, 0]; - f := m[0, 1]; - g := m[1, 0]; - h := m[1, 1]; -{ - [a, b][e ,f] [a*e+b*g, a*f+b*h] - [ ][ ] = [ ] - [c, d][g, h] [c*e+d*g, c*f+d*h] -} - s[0, 0] := a * e + b * g; - s[0, 1] := a * f + b * h; - s[1, 0] := c * e + d * g; - s[1, 1] := c * f + d * h; -end; - -function solve3(x1, x2, x1h, y1, y2, y1h, z1, z2, z1h: double; - var a, b, e: double): double; -var - det1: double; -begin - det1 := x1 * det(y2, 1.0, z2, 1.0) - x2 * det(y1, 1.0, z1, 1.0) - + 1 * det(y1, y2, z1, z2); - if (det1 = 0.0) then - begin - Result := det1; - EXIT; - end - else - begin - a := (x1h * det(y2, 1.0, z2, 1.0) - x2 * det(y1h, 1.0, z1h, 1.0) - + 1 * det(y1h, y2, z1h, z2)) / det1; - b := (x1 * det(y1h, 1.0, z1h, 1.0) - x1h * det(y1, 1.0, z1, 1.0) - + 1 * det(y1, y1h, z1, z1h)) / det1; - e := (x1 * det(y2, y1h, z2, z1h) - x2 * det(y1, y1h, z1, z1h) - + x1h * det(y1, y2, z1, z2)) / det1; - a := Round6(a); - b := Round6(b); - e := Round6(e); - Result := det1; - end; -end; - -function dist(x1, y1, x2, y2: double): double; -//var -// d2: double; -begin -(* - { From FDesign source - { float pt_pt_distance(float x1, float y1, float x2, float y2) } - d2 := (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); - if (d2 = 0.0) then - begin - Result := 0.0; - exit; - end - else - Result := sqrt(d2); -*) - - // --Z-- This is just amazing... :-\ - // Someone needed an 'FDesign source' - to compute distance between two points??!? - - Result := Hypot(x2-x1, y2-y1); -end; - -function line_dist(x, y, x1, y1, x2, y2: double): double; -var - a, b, e, c: double; -begin - if ((x = x1) and (y = y1)) then - a := 0.0 - else - a := sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); - if ((x = x2) and (y = y2)) then - b := 0.0 - else - b := sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); - if ((x1 = x2) and (y1 = y2)) then - e := 0.0 - else - e := sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - if ((a * a + e * e) < (b * b)) then - Result := a - else if ((b * b + e * e) < (a * a)) then - Result := b - else if (e <> 0.0) then - begin - c := (b * b - a * a - e * e) / (-2 * e); - if ((a * a - c * c) < 0.0) then - Result := 0.0 - else - Result := sqrt(a * a - c * c); - end - else - Result := a; -end; - -function transform_affine(const t: TTriangle; const Triangles: TTriangles): boolean; -var - ra, rb, rc, a, b, c: double; -begin - Result := True; - ra := dist(Triangles[-1].y[0], Triangles[-1].x[0], - Triangles[-1].y[1], Triangles[-1].x[1]); - rb := dist(Triangles[-1].y[1], Triangles[-1].x[1], - Triangles[-1].y[2], Triangles[-1].x[2]); - rc := dist(Triangles[-1].y[2], Triangles[-1].x[2], - Triangles[-1].y[0], Triangles[-1].x[0]); - a := dist(t.y[0], t.x[0], t.y[1], t.x[1]); - b := dist(t.y[1], t.x[1], t.y[2], t.x[2]); - c := dist(t.y[2], t.x[2], t.y[0], t.x[0]); - if (a > ra) then - Result := False - else if (b > rb) then - Result := False - else if (c > rc) then - Result := False - else if ((a = ra) and (b = rb) and (c = rc)) then - Result := False; -end; - -function triangle_area(t: TTriangle): double; -var - base, height: double; -begin - try - base := dist(t.x[0], t.y[0], t.x[1], t.y[1]); - height := line_dist(t.x[2], t.y[2], t.x[1], t.y[1], - t.x[0], t.y[0]); - if (base < 1.0) then - Result := height - else if (height < 1.0) then - Result := base - else - Result := 0.5 * base * height; - except on E: EMathError do - Result := 0; - end; -end; - -{ Parse } - -function GetVal(token: string): string; -var - p: integer; -begin - p := Pos('=', token); - Delete(Token, 1, p); - Result := Token; -end; - -function ReplaceTabs(str: string): string; -{Changes tab characters in a string to spaces} -var - i: integer; -begin - for i := 1 to Length(str) do - begin - if str[i] = #9 then - begin - Delete(str, i, 1); - Insert(#32, str, i); - end; - end; - Result := str; -end; - -(* -{ Palette and gradient functions } - -function RGBToColor(Pal: TMapPalette; index: integer): Tcolor; -begin - { Converts the RGB values from a palette index to the TColor type ... - could maybe change it to SHLs } - Result := (Pal.Blue[index] * 65536) + (Pal.Green[index] * 256) - + Pal.Red[index]; -end; - -procedure rgb2hsv(const rgb: array of double; out hsv: array of double); -var - maxval, minval: double; - del: double; -begin - Maxval := Max(rgb[0], Max(rgb[1], rgb[2])); - Minval := Min(rgb[0], Min(rgb[1], rgb[2])); - - hsv[2] := maxval; // v - - if (Maxval > 0) and (maxval <> minval) then begin - del := maxval - minval; - hsv[1] := del / Maxval; //s - - hsv[0] := 0; - if (rgb[0] > rgb[1]) and (rgb[0] > rgb[2]) then begin - hsv[0] := (rgb[1] - rgb[2]) / del; - end else if (rgb[1] > rgb[2]) then begin - hsv[0] := 2 + (rgb[2] - rgb[0]) / del; - end else begin - hsv[0] := 4 + (rgb[0] - rgb[1]) / del; - end; - - if hsv[0] < 0 then - hsv[0] := hsv[0] + 6; - - end else begin - hsv[0] := 0; - hsv[1] := 0; - end; -end; - -procedure hsv2rgb(const hsv: array of double; out rgb: array of double); -var - j: integer; - f, p, q, t, v: double; -begin - j := floor(hsv[0]); - f := hsv[0] - j; - v := hsv[2]; - p := hsv[2] * (1 - hsv[1]); - q := hsv[2] * (1 - hsv[1] * f); - t := hsv[2] * (1 - hsv[1] * (1 - f)); - - case j of - 0: begin rgb[0] := v; rgb[1] := t; rgb[2] := p; end; - 1: begin rgb[0] := q; rgb[1] := v; rgb[2] := p; end; - 2: begin rgb[0] := p; rgb[1] := v; rgb[2] := t; end; - 3: begin rgb[0] := p; rgb[1] := q; rgb[2] := v; end; - 4: begin rgb[0] := t; rgb[1] := p; rgb[2] := v; end; - 5: begin rgb[0] := v; rgb[1] := p; rgb[2] := t; end; - end; -end; - -function GetGradient(FileName, Entry: string): string; -var - FileStrings: TStringList; - GradStrings: TStringList; - i: integer; -begin - FileStrings := TStringList.Create; - GradStrings := TStringList.Create; - try - try - FileStrings.LoadFromFile(FileName); - for i := 0 to FileStrings.count - 1 do - if Pos(Entry + ' ', Trim(FileStrings[i])) = 1 then break; - GradStrings.Add(FileStrings[i]); - repeat - inc(i); - GradStrings.Add(FileStrings[i]); - until Pos('}', FileStrings[i]) <> 0; - GetGradient := GradStrings.Text; - except on exception do - Result := ''; - end; - finally - GradStrings.Free; - FileStrings.Free; - end; -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; @@ -633,6 +343,7 @@ begin Wow64Process := IsWow64Process(GetCurrentProcess, Wow64Process) and Wow64Process; Result := Wow64Process; +{$endif} end; function ReplaceStr(Str, SearchStr, ReplaceStr: string): string; @@ -650,36 +361,36 @@ var vI: Integer; vBuffer: String; vOn: Boolean; begin - Result:= TStringList.Create; - vBuffer:=''; - vOn:=true; - for vI:=1 to Length(fText) do + 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 + 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)); + 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:=''; + vBuffer := ''; end; if fQuotes then begin - if fText[vI]='"' then + if fText[vI] = '"' then begin - vOn:=Not(vOn); + vOn := Not(vOn); Continue; end; - if (fText[vI]<>fSep)or((fText[vI]=fSep)and(vOn=false)) then - vBuffer:=vBuffer+fText[vI]; + 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]; + if fText[vI] <> fSep then + vBuffer := vBuffer + fText[vI]; end; - if vBuffer<>'' then + if vBuffer <> '' then begin - if fTrim then vBuffer:=Trim(vBuffer); + if fTrim then vBuffer := Trim(vBuffer); Result.Add(vBuffer); end; end; diff --git a/Core/Translation.pas b/Core/Translation.pas index 8450110..7cbf7ca 100644 --- a/Core/Translation.pas +++ b/Core/Translation.pas @@ -1,6 +1,6 @@ { - Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + Apophysis "7X" Copyright (C) 2009-2013 Georg Kiehne + Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } unit Translation; @@ -13,9 +13,9 @@ procedure ListLanguages; procedure LanguageInfo(path: string; var name, localName: string); function LanguageAuthor(path: string): string; procedure Add(key, value: string); -procedure LoadLanguage(path:string); +procedure LoadLanguage(path: string); procedure LoadEnglish(); -function TextByKey(key:string):string; +function TextByKey(key: string):string; type TParser = class @@ -121,6 +121,7 @@ begin Add('common-keepaspect', 'Maintain aspect ratio'); Add('common-destination', 'Destination'); Add('common-filename', 'File name'); + Add('common-comment', 'Comment'); Add('common-browse', 'Browse...'); Add('common-quality', 'Quality'); Add('common-filterradius', 'Filter Radius'); @@ -155,7 +156,7 @@ begin Add('common-invalidformat', 'Invalid format.'); Add('common-confirmexit', 'Do you really want to exit? All unsaved data will be lost!'); Add('common-confirmdelete', 'Are you sure you want to permanently delete "%s"? '); - Add('common-confirmrename', 'After renaming "%s", all changes made to this flame can be lost. Do you want to continue?'); + Add('common-confirmselect', 'After new selection, all changes made to the current flame will be lost. Do you want to save its editing history?'); Add('common-deletecurrent', 'All changes made to the current flame will be lost!'); Add('common-dragpanelhint', 'Click and drag to change value'); Add('common-trace-title', 'Trace log'); @@ -198,12 +199,13 @@ begin Add('common-filter-templatefiles', 'Apophysis Template Library (*.template;*.flame)'); Add('common-filter-undofiles', 'Apophysis Undo Parameters (*.undo;*.apo)'); Add('common-filter-scriptfiles', 'Apophysis Script (*.aposcript;*.asc)'); - Add('common-filter-allimages', 'All images (*.bmp;*.dib;*.jpg;*.jpeg)'); + Add('common-filter-allimages', 'All images (*.bmp;*.dib;*.jpg;*.jpeg;*.png)'); Add('common-filter-bitmap', 'Windows Bitmap (*.bmp;*.dib)'); Add('common-filter-jpeg', 'JPEG (*.jpg;*.jpeg)'); Add('common-filter-png', 'Portable Network Graphics (*.png)'); Add('common-filter-allfiles', 'All files (*.*)'); Add('common-open-apoimage', 'Import Apophysis parameters from the image...'); + Add('common-selectimage', 'Select an image file...'); Add('common-favscriptadded', 'The script "%s" was added to your favourites list.'); Add('common-favscriptexists', 'The script "%s" already exists in your favourites list.'); Add('common-screenshot-saved', 'The screenshot "%s" was successfully saved in "%s" directory.'); @@ -246,6 +248,7 @@ begin Add('adjustment-tab-camera-ypos', 'Y-Position'); Add('adjustment-tab-camera-rotation', 'Rotation'); Add('adjustment-tab-camera-resetzoom', 'Reset zoom'); // AV + Add('adjustment-tab-camera-draw3daxes', 'Display coordinate axes in 3D-space'); // AV Add('adjustment-tab-rendering-title', 'Rendering'); Add('adjustment-tab-rendering-istransparent', 'Transparent'); Add('adjustment-tab-gradient-title', 'Gradient'); @@ -309,8 +312,9 @@ begin Add('adjustment-popup-gradient-smooth', 'Smooth Palette...'); Add('adjustment-popup-gradient-browser', 'Gradient Browser...'); Add('adjustment-popup-gradient-saveasugr', 'Save Gradient...'); - Add('adjustment-popup-gradient-saveasmap', 'Save as Map File...'); + Add('adjustment-popup-gradient-saveasmap', 'Save as Map file...'); Add('adjustment-popup-gradient-saveasdefault', 'Save as default'); + Add('adjustment-popup-gradient-saveasscript', 'Save as script file...'); Add('adjustment-popup-gradient-adjustfragment', 'Adjust color fragment...'); Add('editor-title', 'Transform Editor'); Add('editor-common-transform', 'Transform:'); @@ -319,15 +323,19 @@ begin Add('editor-common-finalxformlistitem', 'Final'); Add('editor-common-fromprefix', 'from %d'); Add('editor-common-toprefix', 'to %d'); + Add('editor-common-editcomment', 'Edit flame comment...'); Add('editor-tab-variations-title', 'Variations'); Add('editor-tab-variations-name', 'Name'); Add('editor-tab-variations-value', 'Value'); Add('editor-tab-variations-search', 'Search:'); // AV + Add('editor-tab-variations-searchhint', 'Type a variation name...'); // AV Add('editor-tab-variations-order', 'Edit the Order...'); // AV Add('editor-tab-variations-orderhint', 'Adjust the order of variations for the chosen transform'); // AV Add('editor-tab-variations-togglehideunused', ' Hide unused variations'); Add('editor-tab-variations-toggleshowall', ' Show all variations'); // AV Add('editor-tab-variations-togglefavourites', ' Favourite variations'); // AV + Add('editor-tab-variations-toggle3d', ' 3D-aware variations'); // AV + Add('editor-tab-variations-toggledc', ' Direct coloring variations'); // AV Add('editor-tab-variables-title', 'Variables'); Add('editor-tab-variables-name', 'Name'); Add('editor-tab-variables-value', 'Value'); @@ -369,10 +377,13 @@ begin Add('editor-tab-triangle-transformshint', ' Hotkey A - apply to all vectors, hotkey X - apply to OX-vector only, hotkey Y - apply to OY-vector only, hotkey O - apply to O-vector only'); Add('editor-tab-triangle-coordinates', 'Coordinates'); Add('editor-tab-triangle-menuhint', 'Adjust the transformation tools...'); + Add('editor-tab-triangle-syncall', 'Apply operations to all triangles'); Add('editor-tab-triangle-pivot1x', 'Pivot point abscissa in the chosen coordinate system'); Add('editor-tab-triangle-pivot1y', 'Pivot point ordinate in the chosen coordinate system'); Add('editor-tab-triangle-pivot2x', 'Second point abscissa in the chosen coordinate system'); Add('editor-tab-triangle-pivot2y', 'Second point ordinate in the chosen coordinate system'); + Add('editor-tab-triangle-enablesync', 'Synchronize operations for selected triangles'); + Add('editor-tab-triangle-disablesync', 'Synchronization for triangles disabled'); Add('editor-tab-transform-title', 'Transform'); Add('editor-tab-transform-reset', 'Reset transform'); Add('editor-tab-transform-resethint', 'Reset all vectors to default position'); @@ -445,7 +456,9 @@ begin Add('editor-toolbar-calcsin', 'Calculate sine of the value'); Add('editor-toolbar-calctan', 'Calculate tangent of the value'); Add('editor-toolbar-usedegrees', 'Use degrees'); + Add('editor-toolbar-calcexpression', 'Calculate math expression...'); Add('editor-toolbar-showchaos', 'Show chaotic transitions structure...'); + Add('editor-toolbar-savestate', 'Save current flame into the opened file'); Add('editor-popup-panel-autozoom', 'Zoom automatically'); Add('editor-popup-panel-toggleextendededit', 'Toggle extended edit mode'); Add('editor-popup-panel-locktransformaxes', 'Lock transform axes'); @@ -459,8 +472,10 @@ begin Add('editor-popup-transform-resetflip', 'Reset reflection'); Add('editor-popup-transform-copycoords', 'Copy triangle coordinates'); Add('editor-popup-transform-pastecoords', 'Paste triangle coordinates'); - Add('editor-popup-transform-copywhole', 'Copy whole transform'); + Add('editor-popup-transform-copywhole', 'Copy selected transform(s)'); Add('editor-popup-transform-pastewhole', 'Paste transform(s)'); + Add('editor-popup-transform-copyvars', 'Copy variations with parameters'); + Add('editor-popup-transform-pastevars', 'Paste variations and parameters'); Add('editor-popup-transform-resetentiretriangle', 'Reset triangle'); Add('editor-popup-chaos-rebuildlinks', 'Rebuild chaos links'); Add('editor-popup-chaos-clearall', 'Clear all current modifiers (reset to zero)'); @@ -475,6 +490,8 @@ begin Add('editor-popup-chaos-container', 'Add container transform'); Add('editor-popup-chaos-keepweight', 'Inherit original weights'); Add('editor-popup-chaos-invert', 'Invert current settings'); + Add('editor-popup-chaos-copy', 'Copy current weight modifiers'); + Add('editor-popup-chaos-paste', 'Apply saved modifiers to transform(s)'); Add('editor-popup-triangle-rotateall', 'Rotate all vectors'); Add('editor-popup-triangle-rotatex', 'Rotate only X-axis'); Add('editor-popup-triangle-rotatey', 'Rotate only Y-axis'); @@ -488,7 +505,6 @@ begin Add('editor-popup-triangle-invertstep', 'Invert current Move step'); Add('editor-popup-triangle-arcsin', 'Calculate arcsin of the scale factor'); Add('editor-popup-triangle-display', 'Display internally modified values'); - // Add('editor-status-zoomformat', 'Zoom: %f'); Add('editor-status-xformat', 'X: %f'); Add('editor-status-yformat', 'Y: %f'); Add('editor-status-rotateformat', 'Rotate: %3.2f° Inner angle: %3.2f°'); @@ -506,6 +522,7 @@ begin Add('editor-status-warnscale', 'Current scale factor is out of range! The value inserted into the "Scale" field must be less than 100 percents.'); Add('editor-status-warninvert', 'The affine determinant is too small for this operation.'); Add('editor-status-nonumfield', 'No active numeric field found. Please select a numeric field before opening the menu.'); + Add('editor-status-formula', 'Type the math formula: '); Add('export-title', 'Export to flam3'); Add('export-paramoptions-title', 'Parameter options'); Add('export-paramoptions-bufferdepth', 'Buffer depth'); @@ -531,7 +548,7 @@ begin Add('postprocess-title', 'Post-process render'); Add('postprocess-save', 'Save'); Add('postprocess-fittowindow', 'Fit to window'); - Add('render-title', 'Render flame'); + Add('render-title', 'Render flame to disk'); Add('render-common-gotofolder', 'Open target folder...'); Add('render-tab-settings-title', 'Settings'); Add('render-tab-output-title', 'Output'); @@ -587,8 +604,10 @@ begin Add('render-status-log-largepng-message2', 'PNG format with extreme high-resolution images is not recommended!'); Add('render-status-log-largepng-message3', 'To avoid slowdown (and possible memory problems) use BMP file format instead.'); Add('render-status-confirmstop', 'Do you want to stop the current render?'); + Add('render-status-stop', 'Cancel current rendering'); Add('render-status-dosnapshot', 'Do snapshot'); Add('render-status-dosnapshothint', 'Save current state as a picture'); + Add('render-status-showimage', 'Show the image state...'); Add('messages-title', 'Messages'); Add('messages-openautomatically', 'Automatically open this window'); Add('mutation-title', 'Mutation'); @@ -609,12 +628,15 @@ begin Add('options-tab-general-bufferdepth', 'Buffer depth '); Add('options-tab-general-jpegquality', 'JPEG quality '); Add('options-tab-general-pngtransparency', 'PNG transparency '); + Add('options-tab-general-notifications', 'Notifications'); + Add('options-tab-general-defaults', 'Defaults'); Add('options-tab-general-showextendedstatistics', 'Show extended render statistics '); Add('options-tab-general-showrenderimage', 'Show the rendered image '); Add('options-tab-general-confirmdelete', 'Confirm deleting flames '); Add('options-tab-general-confirmexit', 'Confirm exit '); Add('options-tab-general-confirmrenderstop', 'Confirm stop rendering '); Add('options-tab-general-confirmclearscript', 'Confirm clear script '); + Add('options-tab-general-confirmresetundo', 'Confirm reset editing history '); Add('options-tab-general-oldgradientformat', 'Use old gradient format '); Add('options-tab-general-templaterandcolor', 'Randomize gradient for templates '); Add('options-tab-general-alwaysblankflame', 'Disable templates '); @@ -641,6 +663,7 @@ begin Add('options-tab-general-playsound', 'Play sound '); Add('options-tab-general-soundfile', 'Sound file: '); Add('options-tab-general-playhint', 'Play'); + Add('options-tab-general-createanimdir', 'Create a new folder for frames'); Add('options-tab-general-autoflatten', 'Apply flattening to old flames'); Add('options-tab-general-pluginpath', 'Plugin folder '); Add('options-tab-editor-title', 'Editor '); @@ -660,6 +683,7 @@ begin Add('options-tab-editor-previewtransparency', 'Transparency'); Add('options-tab-editor-resetcoefs', 'Reset affine values by double-click'); Add('options-tab-editor-resetlinear', 'Reset linear when other variation is set'); + Add('options-tab-editor-synctriangles', 'Allow synchronize triangles'); Add('options-tab-display-title', 'Display '); Add('options-tab-display-rendering', 'Rendering '); Add('options-tab-display-previewdensity', 'Preview density '); @@ -852,6 +876,7 @@ begin Add('main-menu-view-imagesize', 'Image size'); Add('main-menu-view-messages', 'Messages'); Add('main-menu-view-curves', 'Curves'); + Add('main-menu-view-animator', 'Animator'); Add('main-menu-flame-title', 'Flame'); Add('main-menu-flame-reset', 'Reset location'); Add('main-menu-flame-randomize', 'Randomize all parameters'); @@ -972,6 +997,7 @@ begin Add('main-toolbar-mutation', 'Mutation | Show randomly generated modifications of the current flame'); Add('main-toolbar-quality', 'Rendering quality | Set flame quality (density) for the main preview window'); Add('main-toolbar-imagesize', 'Image size | Change the image size'); + Add('main-toolbar-animator', 'Animator | Show animation editor'); Add('main-toolbar-messages', 'Messages | Show error messages'); Add('main-toolbar-options', 'Settings | Change Apophysis default settings'); Add('main-toolbar-editscript', 'Edit script | Edit the script code'); @@ -1006,6 +1032,49 @@ begin Add('varorder-byindex', 'Default order'); Add('varorder-byindexhint', 'Restore the default variation order in Transform Editor'); Add('varorder-noselected', 'Active variation not found. Please, select the variation to move.'); + Add('formula-wrongargscount', 'Invalid number of arguments to %s: expected %d, received %d.'); + Add('formula-wrongdatatype', 'The parameter must be a number.'); + Add('formula-outofrange', 'The value must be in range [-1, 1].'); + Add('formula-unsigned', 'The value must be positive.'); + Add('formula-cannotevaluate', 'Cannot evaluate the mathematical expression.'); + Add('animate-title', 'Animate flame'); + Add('animate-general', 'General'); + Add('animate-animation', 'Animation'); + Add('animate-output', 'Output settings'); + Add('animate-duration', 'Duration'); + Add('animate-fps', 'Frames per second'); + Add('animate-parameters', 'Animation parameters'); + Add('animate-outflame', 'Output flame file'); + Add('animate-prefix', 'Name prefix'); + Add('animate-frame', 'Frame'); + Add('animate-preview', 'Animation preview'); + Add('animate-save', 'Save'); + Add('animate-stop', 'Stop'); + Add('animate-playhint', 'Play animation'); + Add('animate-stophint', 'Stop current animation'); + Add('animate-type', 'Animation type'); + Add('animate-showframes', 'Show generated frames'); + Add('animate-currentflame', ' (Current flame)'); + Add('animate-status-generating', 'Generating frame %d of %d...'); + Add('animate-status-finished', 'Frame generation finished.'); + Add('animate-status-changeflame', 'Initial and final frames must be different.'); + Add('animate-status-stopped', 'Frame generation is interrupted.'); + Add('animate-kind-rotateflame', 'Rotate flame'); + Add('animate-kind-rotatereference', 'Rotate reference triangle'); + Add('animate-kind-rotatehue', 'Change gradient hue'); + Add('animate-kind-rotatepalette', 'Rotate color gradient'); + Add('animate-kind-rotatecamera', 'Rotate 3D camera'); + Add('animate-kind-morph1', 'Morphing (interpolation: cosine, RGB)'); + Add('animate-kind-morph2', 'Morphing (interpolation: cosine, HSV)'); + Add('animate-kind-morph3', 'Morphing (interpolation: linear, RGB)'); + Add('animate-kind-morph4', 'Morphing (interpolation: linear, HSV)'); + Add('animate-render', 'Render all frames after generation'); + Add('animate-resetlocation', 'Calculate flame location for each frame'); + Add('animate-graphicext', 'Graphic extension'); + Add('animate-initflame', 'Initial flame'); + Add('animate-finalflame', 'Initial flame'); + Add('animate-savehint', 'Save all animated frames to hard disk'); + Add('animate-invertbg', 'Invert background color'); end; procedure Add(key, value: string); @@ -1087,6 +1156,7 @@ begin self.parentTagnames.Add(self.currentTagname); self.currentTagname := TagName; end; + procedure TParser.ListXmlScannerEndTag(Sender: TObject; TagName: string); var lastIndex : integer; begin @@ -1116,7 +1186,7 @@ procedure TParser.ListXmlScannerContent(Sender: TObject; Content: string); const root: string = 'stringtable'; var key, tn: string; i: integer; begin - for i:=0 to self.parentTagnames.Count - 1 do begin + for i := 0 to self.parentTagnames.Count - 1 do begin tn := self.parentTagnames.Strings[i]; if not (tn = '') and not (tn = root) then key := key + tn + '-'; end; diff --git a/Core/XFormMan.pas b/Core/XFormMan.pas index c434648..fd06289 100644 --- a/Core/XFormMan.pas +++ b/Core/XFormMan.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,19 +27,13 @@ unit XFormMan; interface uses - BaseVariation, SysUtils, Forms, Windows; + BaseVariation, SysUtils, System.Generics.Collections; const NRLOCVAR = 36; var NumBuiltinVars: integer; -type - TFNToVN = record - FileName: string; - VarName: string; - end; - function NrVar: integer; function Varnames(const index: integer): String; procedure RegisterVariation(Variation: TVariationLoader; supports3D, supportsDC : boolean); @@ -49,11 +43,9 @@ function GetNrVariableNames: integer; function GetVariableNameAt(const Index: integer): string; function GetVariationIndex(const str: string): integer; function GetVariationIndexFromVariableNameIndex(const Index: integer): integer; -procedure VarSupports(index : integer; var supports3D : boolean; var supportsDC : boolean); -procedure InitializeXFormMan; -procedure DestroyXFormMan; -procedure RegisterVariationFile(filename, name: string); -function GetFileNameOfVariation(name: string): string; +function VarSupports3D(index: smallint): boolean; // AV +function VarSupportsDC(index: smallint): boolean; // AV +procedure FillVarNamesList; // AV implementation @@ -61,23 +53,22 @@ uses Classes; var - VariationList: TList; - VariableNames: TStringlist; - loaderNum : integer; + VariationList: TList; // AV: changed to generic type + VariationNames: TStringList; // AV + VariableNames: TStringList; Variable2VariationIndex : array of integer; - FNToVNList : array of TFNToVN; - FNToVNCount: integer; + Vars3D: array of boolean; + VarsDC: array of boolean; procedure InitializeXFormMan; begin - VariationList := TList.Create; - VariableNames := TStringlist.create; + VariationList := TList.Create; // AV: changed to generic type + VariationNames := TStringList.Create; // AV + VariableNames := TStringList.create; SetLength(Variable2VariationIndex,0); - SetLength(FNToVNList, 0); - FNToVNCount := 0; end; -procedure VarSupports(index : integer; var supports3D : boolean; var supportsDC : boolean); +procedure FillVarsSupport; // AV const supports3D_arr: array[0..NRLOCVAR-1] of boolean = ( true, //'linear', @@ -162,38 +153,50 @@ const false, //'pyramid' false // polar2 ); -var - varl : TVariationLoader; +var i: word; begin - - if (index >= NRLOCVAR) then begin - supports3D := TVariationLoader(VariationList.Items[index - NRLOCVAR]).supports3D; - supportsDC := TVariationLoader(VariationList.Items[index - NRLOCVAR]).supportsDC; - end else begin - supports3D := supports3D_arr[index]; - supportsDC := supportsDC_arr[index]; + SetLength(Vars3D, VariationNames.Count); + SetLength(VarsDC, VariationNames.Count); + for i := 0 to NRLOCVAR-1 do + begin + Vars3D[i] := supports3D_arr[i]; + VarsDC[i] := supportsDC_arr[i]; + end; + for i := 0 to VariationList.Count - 1 do + begin + Vars3D[i + NRLOCVAR] := VariationList[i].Supports3D; + VarsDC[i + NRLOCVAR] := VariationList[i].SupportsDC; end; end; +function VarSupports3D(index: smallint): boolean; +begin + Result := Vars3D[index]; // AV: added precalc +end; + +function VarSupportsDC(index: smallint): boolean; +begin + Result := VarsDC[index]; // AV: added precalc +end; + +{ ///////////////////////////////////////////////////////////////////////// } procedure DestroyXFormMan; var i: integer; begin + VariationNames.Free; // AV VariableNames.Free; // The registered variation loaders are owned here, so we must free them. for i := 0 to VariationList.Count-1 do - TVariationLoader(VariationList[i]).Free; + VariationList[i].Free; VariationList.Free; - - Finalize(Variable2VariationIndex); - Finalize(FNToVNList); end; /////////////////////////////////////////////////////////////////////////////// -function NrVar: integer; +function NrVar: integer; // AV: reduce Nr of calc since we use it thousand times begin - Result := NRLOCVAR + VariationList.Count; + Result := VariationNames.Count; // NRLOCVAR + VariationList.Count; end; /////////////////////////////////////////////////////////////////////////////// @@ -206,7 +209,9 @@ begin Result := Variable2VariationIndex[Index]; end; -function Varnames(const index: integer): String; +{ ////////////////////////////////////////////////////////////////////////// } + +procedure FillVarNamesList; // AV: this method used once at startup const cvarnames: array[0..NRLOCVAR-1] of string = ( 'linear', @@ -216,23 +221,10 @@ const 'swirl', 'horseshoe', 'polar', -// 'handkerchief', -// 'heart', 'disc', 'spiral', 'hyperbolic', 'diamond', -// 'ex', -// 'julia', -// 'bent', -// 'waves', -// 'fisheye', -// 'popcorn', -// 'exponential', -// 'power', -// 'cosine', -// 'rings', -// 'fan', 'eyefish', 'bubble', 'cylinder', @@ -241,48 +233,51 @@ const 'gaussian_blur', 'zblur', 'blur3D', - 'pre_blur', 'pre_zscale', 'pre_ztranslate', 'pre_rotate_x', 'pre_rotate_y', - 'zscale', 'ztranslate', 'zcone', - 'post_rotate_x', 'post_rotate_y', - 'post_mirror_x', 'post_mirror_y', 'post_mirror_z', - 'hemisphere', 'cross', 'pyramid', 'polar2' ); +var i: integer; begin - if Index < NRLOCVAR then - Result := cvarnames[Index] + for i := 0 to High(cvarnames) do + VariationNames.Add(cvarnames[i]); + for i := 0 to VariationList.Count - 1 do + VariationNames.Add(VariationList[i].GetName); + + VariationList.TrimExcess; + + FillVarsSupport; // 3D and DC +end; + +function Varnames(const index: integer): string; // AV: totally rewritten +begin + if (index >= 0) and (index < VariationNames.Count) then + Result := VariationNames[index] else - Result := TVariationLoader(VariationList[Index - NRLOCVAR]).GetName; + Result := ''; end; -/////////////////////////////////////////////////////////////////////////////// -function GetVariationIndex(const str: string): integer; -var - i: integer; +function GetVariationIndex(const str: string): integer; // AV: totally rewritten begin - i := NRVAR-1; - while (i >= 0) and (Varnames(i) <> str) do Dec(i); - Result := i; + Result := VariationNames.IndexOf(str); end; /////////////////////////////////////////////////////////////////////////////// - +(* procedure RegisterVariationFile(filename, name: string); begin FNToVNCount := FNToVNCount + 1; @@ -302,13 +297,14 @@ begin end; Result := ''; end; +*) procedure RegisterVariation(Variation: TVariationLoader; supports3D, supportsDC : boolean); var i: integer; prevNumVariables:integer; begin - OutputDebugString(PChar(Variation.GetName)); + // OutputDebugString(PChar(Variation.GetName)); VariationList.Add(Variation); Variation.Supports3D := supports3D; @@ -318,7 +314,7 @@ begin setLength(Variable2VariationIndex, prevNumVariables + Variation.GetNrVariables); for i := 0 to Variation.GetNrVariables - 1 do begin VariableNames.Add(Variation.GetVariableNameAt(i)); - Variable2VariationIndex[prevNumVariables + i] := NrVar-1; + Variable2VariationIndex[prevNumVariables + i] := NRLOCVAR + VariationList.Count - 1; //NrVar-1; end; end; @@ -331,7 +327,8 @@ end; /////////////////////////////////////////////////////////////////////////////// function GetRegisteredVariation(const Index: integer): TVariationLoader; begin - Result := TVariationLoader(VariationList[Index]); + // AV: no more unsafe type casting here since we use generics! + Result := VariationList[Index]; end; /////////////////////////////////////////////////////////////////////////////// diff --git a/Flame/ControlPoint.pas b/Flame/ControlPoint.pas index 45f502e..d6d40db 100644 --- a/Flame/ControlPoint.pas +++ b/Flame/ControlPoint.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,27 +27,30 @@ unit ControlPoint; interface //{$define VAR_STR} +//{$define GAUSSIAN_DOF} uses - Classes, Windows, Cmap, XForm, XFormMan, Binary, - SysUtils, math, ZLib, Bezier; + Classes, Windows, Cmap, XForm, XFormMan, Binary, SysUtils, + Math, Bezier (* {$ifdef CPUX86}, AsmRandom {$endif} *); const SUB_BATCH_SIZE = 10000; PROP_TABLE_SIZE = 1024; PREFILTER_WHITE = (1 shl 26); - FILTER_CUTOFF = 1.8; + FILTER_CUTOFF = 1.8; // AV: maybe move it to ImageMaker? BRIGHT_ADJUST = 2.3; //FUSE = 15; // AV: moved to Global since it became a variable + vRandom = -1; // AV: index of randomly chosen variation for random flames + type - TCoefsArray= array[0..2, 0..1] of double; - pCoefsArray= ^TCoefsArray; + TTriangle = record x: array[0..2] of double; y: array[0..2] of double; end; TTriangles = array[-1..NXFORMS] of TTriangle; + TSPoint = record x: double; y: double; @@ -55,34 +58,25 @@ type TSRect = record Left, Top, Right, Bottom: double; end; + +{ TMapPalette = record Red: array[0..255] of byte; Green: array[0..255] of byte; Blue: array[0..255] of byte; end; + TColorMaps = record Identifier: string; UGRFile: string; end; - pPixArray = ^TPixArray; - TPixArray = array[0..1279, 0..1023, 0..3] of integer; - pPreviewPixArray = ^TPreviewPixArray; - TPreviewPixArray = array[0..159, 0..119, 0..3] of integer; - TFileType = (ftIfs, ftFla, ftXML); - -type //? - PLongintArray = ^TLongintArray; - TLongintArray = array[0..8192] of Longint; +} type - TVariation = (vLinear, vCustom, vRandom = 1000); // AV: fixed outdated values -type TPointsArray = array of TCPpoint; TPointsXYArray = array of TXYpoint; - - P2Cpoint = ^T2Cpoint; - T2CPointsArray = array of T2Cpoint; + //T2CPointsArray = array of T2Cpoint; TControlPoint = class public @@ -102,21 +96,20 @@ type xform: array[0..NXFORMS] of TXForm; noLinearFix: boolean; - variation: TVariation; cmap: TColorMap; cmapindex: integer; - time: double; + time: double; // AV: is used for interpolation Fbrightness: double; // 1.0 = normal contrast: double; // 1.0 = normal gamma: double; Width: integer; Height: integer; spatial_oversample: integer; - name, nick, url: string; + name: string; center: array[0..1] of double; // camera center vibrancy: double; // blend between color algs (0=old,1=new) hue_rotation: double; // applies to cmap, 0-1 - background: array[0..3] of Integer; // Changed to integers so no conversion needed - mt + background: array[0..3] of smallint; // Changed to integers so no conversion needed - mt zoom: double; // effects ppu and sample density pixels_per_unit: double; // and scale spatial_filter_radius: double; // variance of gaussian @@ -127,21 +120,28 @@ type actual_density: extended; // for incomplete renders nbatches: integer; // this much color resolution. but making it too high induces clipping white_level: integer; - cmap_inter: integer; // if this is true, then color map interpolates one entry - // at a time with a bright edge - symmetry: integer; - pulse: array[0..1, 0..1] of double; // [i][0]=magnitute [i][1]=frequency */ - wiggle: array[0..1, 0..1] of double; // frequency is /minute, assuming 30 frames/s */ + + FAngle: Double; + symmetry: integer; // color speed estimator, estimator_min, estimator_curve: double; // density estimator. - jitters: integer; + jitters: integer; // <-- AV: deprecated gamma_threshold: double; enable_de : boolean; used_plugins : TStringList; + comment: string; // AV: holds user's comment on flame -// PropTable: array of TXForm; - FAngle: Double; - //FTwoColorDimensions: Boolean; + { + pulse: array[0..1, 0..1] of double; // [i][0]=magnitute [i][1]=frequency */ + wiggle: array[0..1, 0..1] of double; // frequency is /minute, assuming 30 frames/s */ + cmap_inter: integer; // if this is true, then color map interpolates one entry + // at a time with a bright edge + variation: TVariation; // <-- AV: deprecated + nick, url: string; // <-- AV: deprecated + PropTable: array of TXForm; // <-- AV: declared in TXform unit + FTwoColorDimensions: Boolean; + xdata : string; + } procedure FillUsedPlugins; @@ -150,8 +150,10 @@ type CameraMatrix: array[0..2, 0..2] of double; DofCoef: double; + {$ifdef GAUSSIAN_DOF} gauss_rnd: array [0..3] of double; gauss_N: integer; + {$endif} sinPitch, cosPitch, sinRoll, cosRoll, sinYaw, cosYaw: double; @@ -169,13 +171,15 @@ type function getppux: double; function getppuy: double; + procedure PreCalcBounds(var maxx, minx, maxy, miny: double); // AV + procedure DirectCopy_AV(const cp1: TControlPoint); + function GetBrightness: double; procedure SetBrightness(br: double); function GetRelativeGammaThreshold: double; procedure SetRelativeGammaThreshold(gtr: double); public - xdata : string; procedure SaveToStringlist(sl: TStringlist); procedure SaveToFile(Filename: string); @@ -183,12 +187,9 @@ type procedure ParseString(aString: string); procedure ParseStringList(sl: TStringlist); - procedure RandomCP(min: integer = 2; max: integer = NXFORMS; calc: boolean = true); - procedure RandomCP1; procedure CalcBoundbox; function BlowsUp(NrPoints: integer): boolean; - - procedure SetVariation(vari: TVariation); + procedure Clear; procedure InterpolateX(cp1, cp2: TControlPoint; Tm: double); @@ -199,8 +200,8 @@ type procedure Prepare; - function Clone: TControlPoint; - procedure Copy(cp1: TControlPoint; KeepSizes: boolean = false; nt: byte = NXFORMS); // AV + function Clone: TControlPoint; // AV: rewritten + procedure Copy(cp1: TControlPoint; KeepSizes: boolean = false); // AV: rewritten function HasFinalXForm: boolean; @@ -212,10 +213,6 @@ type procedure GetTriangle(var Triangle: TTriangle; const n: integer); procedure GetPostTriangle(var Triangle: TTriangle; const n: integer); - procedure EqualizeWeights; - procedure NormalizeWeights; - procedure RandomizeWeights; - procedure ComputeWeights(Triangles: TTriangles; t: integer); procedure NormalizeProbabilities; // AV procedure CalculateWeights; // AV procedure CalculateColorSpeed; // AV @@ -243,96 +240,65 @@ type function add_symmetry_to_control_point(var cp: TControlPoint; sym: integer): integer; procedure tile_control_point(var cp: TControlPoint; sym: integer); + function CalcUPRMagn(const cp: TControlPoint): double; -procedure FillVarDisturb; function CalcBinaryFlameSize(cp: TControlPoint): integer; +procedure PrepareToInterpolation(var SourceCp, TargetCp: TControlPoint); // AV + +{ Math operations } +function line_dist(x, y, x1, y1, x2, y2: double): double; +function dist(x1, y1, x2, y2: double): double; +function det(a, b, c, d: double): double; +function solve3(x1, x2, x1h, y1, y2, y1h, z1, z2, z1h: double; + var a, b, e: double): double; + +// AV: moved specific variables from Global here due to often name-space conflicts +var + MainTriangles: TTriangles; + Variation: integer; // Current variation implementation -uses global; - -var - var_distrib: array of integer; - mixed_var_distrib: array of integer; +uses Global; { TControlPoint } -function sign(n: double): double; -begin - if n < 0 then Result := -1 - else if n > 0 then Result := 1 - else Result := 0; -end; - procedure TControlPoint.FillUsedPlugins; var - i, j, k, f : integer; + i, j, f : integer; v : double; - s : String; + s : string; begin used_plugins.Clear; - f := -1; - if self.finalXformEnabled then f := 0; + if self.finalXformEnabled then // AV + f := Min(NumXForms, NXFORMS) + else + f := Min(NumXForms - 1, NXFORMS); - for i := 0 to Min(NumXForms+f, NXFORMS) do + for i := 0 to f do with xform[i] do begin for j := 0 to NRVAR - 1 do begin v := self.xform[i].GetVariation(j); + s := Varnames(j); if (v <> 0) and // uses variation - (used_plugins.IndexOf(Varnames(j)) < 0) // not listed yet - then begin - used_plugins.Add(Varnames(j)); - s := s + Varnames(j) + ' on TX #' + IntToStr(i + 1) + #13#10; - end; + (used_plugins.IndexOf(s) < 0) // not listed yet + then used_plugins.Add(s); end; end; - // Faulty... - (* - for i := 0 to NumXforms-1 do begin - for j := NumBuiltinVars to xform[i].NumVariations-1 do begin - v := self.xform[i].GetVariation(j); - if (v = 0) then continue; - s := Varnames(j); - k := used_plugins.IndexOf(s); - if (k < 0) or (k >= used_plugins.Count) then - used_plugins.Add(s); - end; - end; - if finalXformEnabled then begin - for j := NumBuiltinVars to self.finalXform.NumVariations-1 do begin - v := self.finalXform.GetVariation(j); - s := Varnames(j); - if (v = 0) then continue; - k := used_plugins.IndexOf(s); - if (k < 0) or (k >= used_plugins.Count) then - used_plugins.Add(s); - end; - end; - *) end; constructor TControlPoint.Create; var - i: Integer; + i: word; begin - for i := 0 to NXFORMS do begin + for i := 0 to NXFORMS do xform[i] := TXForm.Create; - end; + invalidXform := TXForm.Create; soloXform := -1; - pulse[0][0] := 0; - pulse[0][1] := 60; - pulse[1][0] := 0; - pulse[1][1] := 60; - - wiggle[0][0] := 0; - wiggle[0][1] := 60; - wiggle[1][0] := 0; - wiggle[1][1] := 60; - background[0] := 0; background[1] := 0; background[2] := 0; @@ -361,23 +327,21 @@ begin vibrancy := 1; contrast := 1; Fbrightness := 1; - hue_rotation := 1; // AV + gamma_threshold := 0.01; sample_density := 50; zoom := 0; - nbatches := 1; - - white_level := 200; - + estimator := 9.0; estimator_min := 0.0; estimator_curve := 0.4; enable_de := false; jitters := 1; - gamma_threshold := 0.01; - - //FTwoColorDimensions := False; - + nbatches := 1; + + white_level := 200; + hue_rotation := 1; // AV + finalXformEnabled := false; Transparency := false; @@ -389,12 +353,27 @@ begin cameraDOF := 0; used_plugins := TStringList.Create; + comment := ''; + + { + pulse[0][0] := 0; + pulse[0][1] := 60; + pulse[1][0] := 0; + pulse[1][1] := 60; + + wiggle[0][0] := 0; + wiggle[0][1] := 60; + wiggle[1][0] := 0; + wiggle[1][1] := 60; + xdata := ''; + FTwoColorDimensions := False; + } end; destructor TControlPoint.Destroy; var - i: Integer; + i: word; begin for i := 0 to NXFORMS do xform[i].Free; @@ -495,11 +474,13 @@ begin CameraMatrix[1, 2] := cosPitch * sinRoll * sinYaw + sinPitch * cosYaw; CameraMatrix[2, 2] := cosPitch * cosRoll; DofCoef := 0.1 * CameraDOF; + {$ifdef GAUSSIAN_DOF} gauss_rnd[0] := random; gauss_rnd[1] := random; gauss_rnd[2] := random; gauss_rnd[3] := random; gauss_N := 0; + {$endif} if (CameraDOF <> 0) then begin if (CameraRoll = 0) then @@ -546,10 +527,10 @@ begin for i := 0 to NrPoints - 1 do begin xf := xf.PropTable[Random(PROP_TABLE_SIZE)]; xf.NextPointXY(px,py); - if (xf.transOpacity = 0) or + if (xf.transOpacity = 0) or ((xf.transOpacity < 1) and (random > xf.transOpacity)) then - pPoint^.x := 1e300 // MaxDouble // hack - else begin + pPoint^.x := 1e300 // MaxDouble // hack + else begin pPoint^.X := px; pPoint^.Y := py; end; @@ -560,7 +541,7 @@ begin for i := 0 to NrPoints - 1 do begin xf := xf.PropTable[Random(PROP_TABLE_SIZE)]; xf.NextPointXY(px,py); - if (xf.transOpacity = 0) or // AV + if (xf.transOpacity = 0) or // AV ((xf.transOpacity < 1) and (random > xf.transOpacity)) then // AV pPoint^.x := 1e300 // MaxDouble // hack else begin @@ -608,7 +589,7 @@ begin pPoint^.x := 1e300 // MaxDouble // hack else begin - finalXform.NextPointTo(p, pPoint^); + finalXform.NextPointTo(p, pPoint^); ProjectionFunc(pPoint); end; Inc(pPoint); @@ -687,7 +668,6 @@ begin z := CameraMatrix[1,2] * pPoint^.y + cosPitch * z; zr := 1 - cameraPersp * z; -//{$define GAUSSIAN_DOF} {$ifdef GAUSSIAN_DOF} asm fld qword ptr [eax + gauss_rnd] @@ -855,6 +835,8 @@ begin end; function TControlPoint.BlowsUp(NrPoints: integer): boolean; +const + limit = 1E10; // AV var i, n: Integer; px, py: double; @@ -890,6 +872,39 @@ begin Inc(CurrentPoint); // random CPs don't use finalXform... end; + + // It is possible that the transformation will grow very large but remain below the overflow line + minx := limit; //1E10; + maxx := -limit; //-1E10; + miny := limit; //1E10; + maxy := -limit; //-1E10; + for i := 0 to n-1 do begin + // AV: rewrote the block to fix the crash + if InRange(Points[i].x, -limit, limit) then + begin + minx := min(minx, Points[i].x); + maxx := max(maxx, Points[i].x); + end + else + begin + minx := -limit; + maxx := limit; + end; + if InRange(Points[i].y, -limit, limit) then + begin + miny := min(miny, Points[i].y); + maxy := max(maxy, Points[i].y); + end + else + begin + miny := -limit; + maxy := limit; + end; + end; + + if ((Maxx - MinX) > 1000) or ((Maxy - Miny) > 1000) then + Result := True; + except on EMathError do begin Result := True; @@ -897,20 +912,6 @@ begin end; end; - // It is possible that the transformation will grow very large but remain below the overflow line - minx := 1E10; - maxx := -1E10; - miny := 1E10; - maxy := -1E10; - for i := 0 to n-1 do begin - minx := min(minx, Points[i].x); - maxx := max(maxx, Points[i].x); - miny := min(miny, Points[i].y); - maxy := max(maxy, Points[i].y); - end; - - if ((Maxx - MinX) > 1000) or ((Maxy - Miny) > 1000) then - Result := True; end; procedure TControlPoint.ParseString(aString: string); @@ -1055,7 +1056,7 @@ begin Inc(ParsePos);curvePoints[i][3].y := StrToFloat(ParseValues[ParsePos]); Inc(ParsePos);curveWeights[i][3] := StrToFloat(ParseValues[ParsePos]); end; - end else if AnsiCompareText(CurrentToken, 'pulse') = 0 then begin + end {else if AnsiCompareText(CurrentToken, 'pulse') = 0 then begin Inc(ParsePos); pulse[0, 0] := StrToFloat(ParseValues[ParsePos]); Inc(ParsePos); @@ -1073,7 +1074,7 @@ begin wiggle[1, 0] := StrToFloat(ParseValues[ParsePos]); Inc(ParsePos); wiggle[1, 1] := StrToFloat(ParseValues[ParsePos]); - end else if AnsiCompareText(CurrentToken, 'pixels_per_unit') = 0 then begin + end} else if AnsiCompareText(CurrentToken, 'pixels_per_unit') = 0 then begin Inc(ParsePos); pixels_per_unit := StrToFloat(ParseValues[ParsePos]); end else if AnsiCompareText(CurrentToken, 'spatial_filter_radius') = 0 then begin @@ -1094,14 +1095,14 @@ begin end else if AnsiCompareText(CurrentToken, 'cmap') = 0 then begin Inc(ParsePos); cmapindex := StrToInt(ParseValues[ParsePos]); - end else if AnsiCompareText(CurrentToken, 'cmap_inter') = 0 then begin + end {else if AnsiCompareText(CurrentToken, 'cmap_inter') = 0 then begin Inc(ParsePos); cmap_inter := StrToInt(ParseValues[ParsePos]); end else if AnsiCompareText(CurrentToken, 'palette') = 0 then begin // Inc(ParsePos); // cmapindex := StrToInt(ParseValues[ParsePos]); OutputDebugString(Pchar('NYI import Palette')); - end else if AnsiCompareText(CurrentToken, 'density') = 0 then begin + end} else if AnsiCompareText(CurrentToken, 'density') = 0 then begin Inc(ParsePos); xform[CurrentXForm].Density := StrToFloat(ParseValues[ParsePos]); end else if AnsiCompareText(CurrentToken, 'color') = 0 then begin @@ -1238,7 +1239,7 @@ begin FormatSettings.DecimalSeparator := OldDecimalSperator; end; - +(* procedure TControlPoint.SetVariation(vari: TVariation); var i, j, v: integer; @@ -1298,7 +1299,6 @@ begin GetCmap(cmapindex, hue_rotation, cmap); time := 0.0; -//nrXforms := xform_distrib[random(13)]; nrXforms := random(Max - (Min - 1)) + Min; FillVarDisturb; @@ -1334,10 +1334,6 @@ begin xform[i].SetVariation(j, 0); end; - {for j := 0 to NRVAR - 1 do begin - xform[i].SetVariation(j, 0); - end; } // AV: why do we do it twice? - if rv < 0 then begin if VarPossible then begin repeat @@ -1352,8 +1348,7 @@ begin xform[i].SetVariation(rv, 1); end; - if calc then - CalcBoundbox; + if calc then CalcBoundbox; end; procedure TControlPoint.RandomCP1; @@ -1362,31 +1357,27 @@ var begin RandomCP; for i := 0 to NXFORMS - 1 do begin - for j := 0 to NRVAR - 1 do begin + for j := 1 to NRVAR - 1 do xform[i].SetVariation(j, 0); - end; xform[i].SetVariation(0, 1); end; CalcBoundbox; end; +*) -procedure TControlPoint.CalcBoundbox; +procedure TControlPoint.PreCalcBounds(var maxx, minx, maxy, miny: double); const limit = 50; // AV var Points: TPointsArray; // AV: fixed - was TPointsXYArray; i, j: integer; - deltax, minx, maxx: double; + deltax, deltay: double; cntminx, cntmaxx: integer; - deltay, miny, maxy: double; cntminy, cntmaxy: integer; LimitOutSidePoints: integer; begin -// RandSeed := 1234567; - try SetLength(Points, SUB_BATCH_SIZE); - Prepare; IterateXYC(SUB_BATCH_SIZE, points); // AV: fixed - was IterateXY LimitOutSidePoints := Round(0.05 * SUB_BATCH_SIZE); @@ -1487,6 +1478,15 @@ begin Height / abs(maxy - miny)) else pixels_per_unit := 10; +end; + +procedure TControlPoint.CalcBoundbox; +var + minx, maxx, miny, maxy: double; +begin + try + Prepare; + PreCalcBounds(maxx, minx, maxy, miny); // AV except on EMathError do begin // default center[0] := 0; @@ -1497,134 +1497,14 @@ begin end; function CalcUPRMagn(const cp: TControlPoint): double; -const - limit = 50; // AV var - Points: TPointsXYArray; - i, j: integer; - deltax, minx, maxx: double; - cntminx, cntmaxx: integer; - deltay, miny, maxy: double; - cntminy, cntmaxy: integer; - LimitOutSidePoints: integer; + minx, maxx, miny, maxy: double; xLength, yLength: double; begin try - SetLength(Points, SUB_BATCH_SIZE); - cp.iterateXY(SUB_BATCH_SIZE, Points); + cp.PreCalcBounds(maxx, minx, maxy, miny); // AV - LimitOutSidePoints := Round(0.05 * SUB_BATCH_SIZE); - - minx := limit; // AV // 1E99; - maxx := -limit; // AV // -1E99; - miny := limit; // AV // 1E99; - maxy := -limit; // AV // -1E99; - { // AV: commented out - for i := 0 to SUB_BATCH_SIZE - 1 do begin - minx := min(minx, Points[i].x); - maxx := max(maxx, Points[i].x); - miny := min(miny, Points[i].y); - maxy := max(maxy, Points[i].y); - end; - } - for i := 0 to SUB_BATCH_SIZE - 1 do begin // AV - if InRange(Points[i].x, -limit, limit) then - begin - minx := min(minx, Points[i].x); - maxx := max(maxx, Points[i].x); - end - else - begin - minx := -limit; - maxx := limit; - end; - if InRange(Points[i].y, -limit, limit) then - begin - miny := min(miny, Points[i].y); - maxy := max(maxy, Points[i].y); - end - else - begin - miny := -limit; - maxy := limit; - end; - end; - - deltax := (maxx - minx) * 0.25; - maxx := (maxx + minx) / 2; - minx := maxx; - - deltay := (maxy - miny) * 0.25; - maxy := (maxy + miny) / 2; - miny := maxy; - - for j := 0 to 10 do begin - cntminx := 0; - cntmaxx := 0; - cntminy := 0; - cntmaxy := 0; - { // AV: commented out - for i := 0 to SUB_BATCH_SIZE - 1 do begin - if (Points[i].x < minx) then Inc(cntminx); - if (Points[i].x > maxx) then Inc(cntmaxx); - if (Points[i].y < miny) then Inc(cntminy); - if (Points[i].y > maxy) then Inc(cntmaxy); - end; - } - for i := 0 to SUB_BATCH_SIZE - 1 do begin // AV - if InRange(Points[i].x, -limit, limit) then - begin - if (Points[i].x < minx) then Inc(cntminx); - if (Points[i].x > maxx) then Inc(cntmaxx); - end; - if InRange(Points[i].y, -limit, limit) then - begin - if (Points[i].y < miny) then Inc(cntminy); - if (Points[i].y > maxy) then Inc(cntmaxy); - end; - end; - - if (cntMinx < LimitOutSidePoints) then begin - minx := minx + deltax; - end else begin - minx := minx - deltax; - end; - - if (cntMaxx < LimitOutSidePoints) then begin - maxx := maxx - deltax; - end else begin - maxx := maxx + deltax; - end; - - deltax := deltax / 2; - - if (cntMiny < LimitOutSidePoints) then begin - miny := miny + deltay; - end else begin - miny := miny - deltay; - end; - - if (cntMaxy < LimitOutSidePoints) then begin - maxy := maxy - deltay; - end else begin - maxy := maxy + deltay; - end; - - deltay := deltay / 2; - end; - - if ((maxx - minx) > 1000) or - ((maxy - miny) > 1000) then - raise EMathError.Create('Flame area too large'); - - cp.center[0] := (minx + maxx) / 2; - cp.center[1] := (miny + maxy) / 2; - if ((maxx - minx) > 0.001) and ((maxy - miny) > 0.001) then - cp.pixels_per_unit := 0.7 * Min(cp.width / (maxx - minx), cp.height / (maxy - miny)) - else - cp.pixels_per_unit := 10; - - // Calculate magn for UPRs + // Calculate magn for UPRs xLength := maxx - minx; yLength := maxy - miny; if xLength >= yLength then @@ -1646,15 +1526,88 @@ begin end; end; -// AV: this one from mine is used only for scripting, the original method was left for mutants +procedure PrepareToInterpolation(var SourceCp, TargetCp: TControlPoint); // AV +var + i, j: integer; + t, ns, nt, maxt: smallint; + vs, vt: double; + vn: string; +begin + { reset linear variation on (temporary) invisible xforms } + ns := SourceCp.NumXForms; + nt := TargetCp.NumXForms; + if ns > nt then begin + for j := nt + 1 to ns - 1 do + TargetCp.xform[j].SetVariation(0, 0); + maxt := ns; // max number of actually used xforms + end + else if nt > ns then begin + for j := ns + 1 to nt - 1 do + SourceCp.xform[j].SetVariation(0, 0); + maxt := nt; + end + else // if nt = ns then + maxt := nt; + + { adjust (temporary unused) variable values } + for t := 0 to maxt do + for i := 0 to GetNrVariableNames - 1 do + begin + j := GetVariationIndexFromVariableNameIndex(i); + vs := SourceCp.xform[t].GetVariation(j); + vt := TargetCp.xform[t].GetVariation(j); + if (vs <> 0) and (vt = 0) then + begin + vn := GetVariableNameAt(i); + SourceCp.xform[t].GetVariable(vn, vs); + TargetCp.xform[t].SetVariable(vn, vs); + end + else if (vt <> 0) and (vs = 0) then + begin + vn := GetVariableNameAt(i); + TargetCp.xform[t].GetVariable(vn, vt); + SourceCp.xform[t].SetVariable(vn, vt); + end; + end; + + { adjust final transforms } + if (SourceCp.finalXformEnabled or TargetCp.finalXformEnabled) + and (nt <> ns) then // otherwise it's already done + begin + for i := 0 to GetNrVariableNames - 1 do + begin + j := GetVariationIndexFromVariableNameIndex(i); + vs := SourceCp.xform[ns].GetVariation(j); + vt := TargetCp.xform[nt].GetVariation(j); + if (vs <> 0) and (vt = 0) then + begin + vn := GetVariableNameAt(i); + SourceCp.xform[ns].GetVariable(vn, vs); + TargetCp.xform[nt].SetVariable(vn, vs); + end + else if (vt <> 0) and (vs = 0) then + begin + vn := GetVariableNameAt(i); + TargetCp.xform[nt].GetVariable(vn, vt); + SourceCp.xform[ns].SetVariable(vn, vt); + end; + end; + end; + + { AV: improve visibility of mid-frames } + SourceCp.NormalizeProbabilities; + TargetCp.NormalizeProbabilities; +end; + +// AV: this one from mine is used for scripting, the original method was left for mutants only procedure TControlPoint.InterpolateAll(cp1, cp2: TControlPoint; Tm: double; it: integer); var - result: TControlPoint; c0, c1, k: double; i, j: integer; numTX, numTX1, numTX2: word; r, s, t: array[0..2] of double; - v1, v2: double; + v1, v2, t1, t2: double; + f1, f2: boolean; function AngOpt(ang0, ang1: double): double; var delta: double; @@ -1666,24 +1619,40 @@ var end; begin - if (it > 3) or (it < 0) then Exit; - if (cp2.time - cp1.time) > 1E-6 then + if (it > 3) or (it < 0) then exit; + + t1 := cp1.time; + t2 := cp2.time; + + if (tm = t1) then + begin + self.Copy(cp1); + exit; + end + else if (tm = t2) then + begin + self.Copy(cp2); + width := cp1.width; + height := cp1.height; + exit; + end; + + if (t2 - t1) > 1E-6 then begin if (it < 2) then begin // 0 or 1: cosine interpolation - k := (cp2.time - tm) / (cp2.time - cp1.time); - c0 := (1 - cos(pi*k))* 0.5; + k := (t2 - tm) / (t2 - t1); + c0 := (1 - cos(pi * k)) * 0.5; end else // 2 or 3: linear interpolation - c0:=(cp2.time - tm) / (cp2.time - cp1.time); + c0 := (t2 - tm) / (t2 - t1); c1 := 1 - c0; end else begin c0 := 1; c1 := 0; end; - Result := TControlPoint.Create; - Result.time := Tm; - + self.time := Tm; + if Odd(it) then // 1 or 3: hsv interpolation for i := 0 to 255 do begin @@ -1699,179 +1668,182 @@ begin t[1] := c0 * s[1] + c1 * t[1]; t[2] := c0 * s[2] + c1 * t[2]; hsv2rgb(t, r); - Result.cmap[i][0] := Round(255 * r[0]); - Result.cmap[i][1] := Round(255 * r[1]); - Result.cmap[i][2] := Round(255 * r[2]); + cmap[i][0] := Round(255 * r[0]); + cmap[i][1] := Round(255 * r[1]); + cmap[i][2] := Round(255 * r[2]); end else // 0 or 2: rgb interpolation for i := 0 to 255 do begin - Result.cmap[i][0] := Round(c0 * cp1.cmap[i][0] + c1 * cp2.cmap[i][0]); - Result.cmap[i][1] := Round(c0 * cp1.cmap[i][1] + c1 * cp2.cmap[i][1]); - Result.cmap[i][2] := Round(c0 * cp1.cmap[i][2] + c1 * cp2.cmap[i][2]); + cmap[i][0] := Round(c0 * cp1.cmap[i][0] + c1 * cp2.cmap[i][0]); + cmap[i][1] := Round(c0 * cp1.cmap[i][1] + c1 * cp2.cmap[i][1]); + cmap[i][2] := Round(c0 * cp1.cmap[i][2] + c1 * cp2.cmap[i][2]); end; - Result.cmapindex := -1; + self.cmapindex := -1; - Result.Fbrightness := c0 * cp1.Fbrightness + c1 * cp2.Fbrightness; - Result.contrast := c0 * cp1.contrast + c1 * cp2.contrast; - Result.gamma := c0 * cp1.gamma + c1 * cp2.gamma; - Result.vibrancy := c0 * cp1.vibrancy + c1 * cp2.vibrancy; - Result.gamma_threshold := c0 * cp1.gamma_threshold + c1 * cp2.gamma_threshold; - Result.width := cp1.width; - Result.height := cp1.height; - Result.spatial_oversample := Round(c0 * cp1.spatial_oversample + c1 * cp2.spatial_oversample); - Result.center[0] := c0 * cp1.center[0] + c1 * cp2.center[0]; - Result.center[1] := c0 * cp1.center[1] + c1 * cp2.center[1]; - Result.FAngle := c0 * cp1.FAngle + c1 * AngOpt(cp1.FAngle, cp2.FAngle); - Result.pixels_per_unit := c0 * cp1.pixels_per_unit + c1 * cp2.pixels_per_unit; - Result.background[0] := Round(c0 * cp1.background[0] + c1 * cp2.background[0]); - Result.background[1] := Round(c0 * cp1.background[1] + c1 * cp2.background[1]); - Result.background[2] := Round(c0 * cp1.background[2] + c1 * cp2.background[2]); - Result.spatial_filter_radius := c0 * cp1.spatial_filter_radius + c1 * cp2.spatial_filter_radius; - Result.sample_density := c0 * cp1.sample_density + c1 * cp2.sample_density; - Result.zoom := c0 * cp1.zoom + c1 * cp2.zoom; - Result.nbatches := Round(c0 * cp1.nbatches + c1 * cp2.nbatches); - Result.white_level := Round(c0 * cp1.white_level + c1 * cp2.white_level); - Result.finalXformEnabled := cp1.finalXformEnabled or cp2.finalXformEnabled; + Fbrightness := c0 * cp1.Fbrightness + c1 * cp2.Fbrightness; + contrast := c0 * cp1.contrast + c1 * cp2.contrast; + gamma := c0 * cp1.gamma + c1 * cp2.gamma; + vibrancy := c0 * cp1.vibrancy + c1 * cp2.vibrancy; + gamma_threshold := c0 * cp1.gamma_threshold + c1 * cp2.gamma_threshold; + width := cp1.width; + height := cp1.height; + spatial_oversample := Round(c0 * cp1.spatial_oversample + c1 * cp2.spatial_oversample); + center[0] := c0 * cp1.center[0] + c1 * cp2.center[0]; + center[1] := c0 * cp1.center[1] + c1 * cp2.center[1]; + FAngle := c0 * cp1.FAngle + c1 * AngOpt(cp1.FAngle, cp2.FAngle); + pixels_per_unit := c0 * cp1.pixels_per_unit + c1 * cp2.pixels_per_unit; + background[0] := Round(c0 * cp1.background[0] + c1 * cp2.background[0]); + background[1] := Round(c0 * cp1.background[1] + c1 * cp2.background[1]); + background[2] := Round(c0 * cp1.background[2] + c1 * cp2.background[2]); + spatial_filter_radius := c0 * cp1.spatial_filter_radius + c1 * cp2.spatial_filter_radius; + sample_density := c0 * cp1.sample_density + c1 * cp2.sample_density; + zoom := c0 * cp1.zoom + c1 * cp2.zoom; + nbatches := Round(c0 * cp1.nbatches + c1 * cp2.nbatches); + // white_level := Round(c0 * cp1.white_level + c1 * cp2.white_level); { AV: global 3D-parameters} - Result.cameraPitch := c0 * cp1.cameraPitch + c1 * AngOpt(cp1.cameraPitch, cp2.cameraPitch); - Result.cameraYaw := c0 * cp1.cameraYaw + c1 * AngOpt(cp1.cameraYaw, cp2.cameraYaw); - Result.cameraRoll := c0 * cp1.cameraRoll + c1 * AngOpt(cp1.cameraRoll, cp2.cameraRoll); - Result.cameraPersp := c0 * cp1.cameraPersp + c1 * cp2.cameraPersp; - Result.cameraZpos := c0 * cp1.cameraZpos + c1 * cp2.cameraZpos; - Result.cameraDOF := c0 * cp1.cameraDOF + c1 * cp2.cameraDOF; + cameraPitch := c0 * cp1.cameraPitch + c1 * AngOpt(cp1.cameraPitch, cp2.cameraPitch); + cameraYaw := c0 * cp1.cameraYaw + c1 * AngOpt(cp1.cameraYaw, cp2.cameraYaw); + cameraRoll := c0 * cp1.cameraRoll + c1 * AngOpt(cp1.cameraRoll, cp2.cameraRoll); + cameraPersp := c0 * cp1.cameraPersp + c1 * cp2.cameraPersp; + cameraZpos := c0 * cp1.cameraZpos + c1 * cp2.cameraZpos; + cameraDOF := c0 * cp1.cameraDOF + c1 * cp2.cameraDOF; for i := 0 to 3 do begin - // Result.pulse[i div 2][i mod 2] := c0 * cp1.pulse[i div 2][i mod 2] + c1 * cp2.pulse[i div 2][i mod 2]; - // Result.wiggle[i div 2][i mod 2] := c0 * cp1.wiggle[i div 2][i mod 2] + c1 * cp2.wiggle[i div 2][i mod 2]; - Result.curvePoints[i][0].x := c0 * cp1.curvePoints[i][0].x + c1 * cp2.curvePoints[i][0].x; - Result.curvePoints[i][0].y := c0 * cp1.curvePoints[i][0].y + c1 * cp2.curvePoints[i][0].y; - Result.curveWeights[i][0] := c0 * cp1.curveWeights[i][0] + c1 * cp2.curveWeights[i][0]; - Result.curvePoints[i][1].x := c0 * cp1.curvePoints[i][1].x + c1 * cp2.curvePoints[i][1].x; - Result.curvePoints[i][1].y := c0 * cp1.curvePoints[i][1].y + c1 * cp2.curvePoints[i][1].y; - Result.curveWeights[i][1] := c0 * cp1.curveWeights[i][1] + c1 * cp2.curveWeights[i][1]; - Result.curvePoints[i][2].x := c0 * cp1.curvePoints[i][2].x + c1 * cp2.curvePoints[i][2].x; - Result.curvePoints[i][2].y := c0 * cp1.curvePoints[i][2].y + c1 * cp2.curvePoints[i][2].y; - Result.curveWeights[i][2] := c0 * cp1.curveWeights[i][2] + c1 * cp2.curveWeights[i][2]; - Result.curvePoints[i][3].x := c0 * cp1.curvePoints[i][2].x + c1 * cp2.curvePoints[i][2].x; - Result.curvePoints[i][3].y := c0 * cp1.curvePoints[i][3].y + c1 * cp2.curvePoints[i][3].y; - Result.curveWeights[i][3] := c0 * cp1.curveWeights[i][3] + c1 * cp2.curveWeights[i][3]; + curvePoints[i][0].x := c0 * cp1.curvePoints[i][0].x + c1 * cp2.curvePoints[i][0].x; + curvePoints[i][0].y := c0 * cp1.curvePoints[i][0].y + c1 * cp2.curvePoints[i][0].y; + curveWeights[i][0] := c0 * cp1.curveWeights[i][0] + c1 * cp2.curveWeights[i][0]; + curvePoints[i][1].x := c0 * cp1.curvePoints[i][1].x + c1 * cp2.curvePoints[i][1].x; + curvePoints[i][1].y := c0 * cp1.curvePoints[i][1].y + c1 * cp2.curvePoints[i][1].y; + curveWeights[i][1] := c0 * cp1.curveWeights[i][1] + c1 * cp2.curveWeights[i][1]; + curvePoints[i][2].x := c0 * cp1.curvePoints[i][2].x + c1 * cp2.curvePoints[i][2].x; + curvePoints[i][2].y := c0 * cp1.curvePoints[i][2].y + c1 * cp2.curvePoints[i][2].y; + curveWeights[i][2] := c0 * cp1.curveWeights[i][2] + c1 * cp2.curveWeights[i][2]; + curvePoints[i][3].x := c0 * cp1.curvePoints[i][2].x + c1 * cp2.curvePoints[i][2].x; + curvePoints[i][3].y := c0 * cp1.curvePoints[i][3].y + c1 * cp2.curvePoints[i][3].y; + curveWeights[i][3] := c0 * cp1.curveWeights[i][3] + c1 * cp2.curveWeights[i][3]; end; numTX1 := cp1.NumXForms; numTX2 := cp2.NumXForms; numTX := max(numTX1, numTX2); // actual xforms including final - if Result.finalXformEnabled then + f1 := cp1.FinalXformEnabled; // cp1.hasFinalXform; + f2 := cp2.FinalXformEnabled; // cp2.hasFinalXform; + + if f1 or f2 then begin - - if cp1.finalXformEnabled then - begin - if numTX1 < numTX then - begin - cp1.xform[numTX].Assign(cp1.xform[numTX1]); - cp1.xform[numTX1].Clear; + if f1 then + begin + if numTX1 < numTX then + begin + cp1.xform[numTX].Assign(cp1.xform[numTX1]); + cp1.xform[numTX1].Clear; + cp1.xform[numTX1].SetVariation(0,0); + end; + end + else + cp1.xform[numTX].symmetry := 1; + + if f2 then + begin + if numTX2 < numTX then + begin + cp2.xform[numTX].Assign(cp2.xform[numTX2]); + cp2.xform[numTX2].Clear; + cp2.xform[numTX2].SetVariation(0,0); + end; + end + else + cp2.xform[numTX].symmetry := 1; + + // final XForm + finalXformEnabled := True; + xform[numTX].color := c0 * cp1.xform[numTX].color + c1 * cp2.xform[numTX].color; + xform[numTX].symmetry := c0 * cp1.xform[numTX].symmetry + c1 * cp2.xform[numTX].symmetry; + xform[numTX].pluginColor := c0 * cp1.xform[numTX].pluginColor + c1 * cp2.xform[numTX].pluginColor; + xform[numTX].ifs.Assign(cp2.xform[numTX].ifs); // AV: target variation order + for j := 0 to NrVar-1 do begin + v1 := cp1.xform[numTX].GetVariation(j); + v2 := cp2.xform[numTX].GetVariation(j); + if v1 = v2 then + xform[numTX].SetVariation(j, v1) + else + xform[numTX].SetVariation(j, c0 * v1 + c1 * v2); end; - end - else - cp1.xform[numTX].symmetry := 1; - - if cp2.finalXformEnabled then - begin - if numTX2 < numTX then - begin - cp2.xform[numTX].Assign(cp2.xform[numTX2]); - cp2.xform[numTX2].Clear; - end; - end - else - cp2.xform[numTX].symmetry := 1; - - // final XForm - Result.xform[numTX].color := c0 * cp1.xform[numTX].color + c1 * cp2.xform[numTX].color; - Result.xform[numTX].symmetry := c0 * cp1.xform[numTX].symmetry + c1 * cp2.xform[numTX].symmetry; - Result.xform[numTX].pluginColor := c0 * cp1.xform[numTX].pluginColor + c1 * cp2.xform[numTX].pluginColor; - Result.xform[numTX].ifs.Assign(cp2.xform[numTX].ifs); // AV: target variation order - for j := 0 to NrVar-1 do - Result.xform[numTX].SetVariation(j, c0 * cp1.xform[numTX].GetVariation(j) + c1 * cp2.xform[numTX].GetVariation(j)); - for j:= 0 to GetNrVariableNames-1 do begin - cp1.xform[numTX].GetVariable(GetVariableNameAt(j), v1); - cp2.xform[numTX].GetVariable(GetVariableNameAt(j), v2); - v1 := c0 * v1 + c1 * v2; - Result.xform[numTX].SetVariable(GetVariableNameAt(j), v1); + for j:= 0 to GetNrVariableNames-1 do begin + cp1.xform[numTX].GetVariable(GetVariableNameAt(j), v1); + cp2.xform[numTX].GetVariable(GetVariableNameAt(j), v2); + if v1 <> v2 then v1 := c0 * v1 + c1 * v2; + xform[numTX].SetVariable(GetVariableNameAt(j), v1); + end; + for j := 0 to 2 do begin + xform[numTX].c[j, 0] := c0 * cp1.xform[numTX].c[j, 0] + c1 * cp2.xform[numTX].c[j, 0]; + xform[numTX].c[j, 1] := c0 * cp1.xform[numTX].c[j, 1] + c1 * cp2.xform[numTX].c[j, 1]; + xform[numTX].p[j, 0] := c0 * cp1.xform[numTX].p[j, 0] + c1 * cp2.xform[numTX].p[j, 0]; + xform[numTX].p[j, 1] := c0 * cp1.xform[numTX].p[j, 1] + c1 * cp2.xform[numTX].p[j, 1]; + end; + end + else begin + finalXformEnabled := False; + xform[numTX].symmetry := 1; end; - for j := 0 to 2 do begin - Result.xform[numTX].c[j, 0] := c0 * cp1.xform[numTX].c[j, 0] + c1 * cp2.xform[numTX].c[j, 0]; - Result.xform[numTX].c[j, 1] := c0 * cp1.xform[numTX].c[j, 1] + c1 * cp2.xform[numTX].c[j, 1]; - Result.xform[numTX].p[j, 0] := c0 * cp1.xform[numTX].p[j, 0] + c1 * cp2.xform[numTX].p[j, 0]; - Result.xform[numTX].p[j, 1] := c0 * cp1.xform[numTX].p[j, 1] + c1 * cp2.xform[numTX].p[j, 1]; - end; - end else - Result.xform[numTX].symmetry := 1; - + // regular xforms for i := 0 to numTX-1 do begin - Result.xform[i].density := c0 * cp1.xform[i].density + c1 * cp2.xform[i].density; - Result.xform[i].color := c0 * cp1.xform[i].color + c1 * cp2.xform[i].color; - Result.xform[i].symmetry := c0 * cp1.xform[i].symmetry + c1 * cp2.xform[i].symmetry; - Result.xform[i].transOpacity := c0 * cp1.xform[i].transOpacity + c1 * cp2.xform[i].transOpacity; - Result.xform[i].pluginColor := c0 * cp1.xform[i].pluginColor + c1 * cp2.xform[i].pluginColor; + xform[i].density := c0 * cp1.xform[i].density + c1 * cp2.xform[i].density; + xform[i].color := c0 * cp1.xform[i].color + c1 * cp2.xform[i].color; + xform[i].symmetry := c0 * cp1.xform[i].symmetry + c1 * cp2.xform[i].symmetry; + xform[i].transOpacity := c0 * cp1.xform[i].transOpacity + c1 * cp2.xform[i].transOpacity; + xform[i].pluginColor := c0 * cp1.xform[i].pluginColor + c1 * cp2.xform[i].pluginColor; for j := 0 to numTX - 1 do - Result.xform[i].modWeights[j] := c0 * cp1.xform[i].modWeights[j] + c1 * cp2.xform[i].modWeights[j]; + self.xform[i].modWeights[j] := c0 * cp1.xform[i].modWeights[j] + c1 * cp2.xform[i].modWeights[j]; - Result.xform[i].ifs.Assign(cp2.xform[i].ifs); // AV: target variation order - for j := 0 to NrVar-1 do - Result.xform[i].SetVariation(j, c0 * cp1.xform[i].GetVariation(j) + c1 * cp2.xform[i].GetVariation(j)); + xform[i].ifs.Assign(cp2.xform[i].ifs); // AV: target variation order + for j := 0 to NrVar-1 do begin + v1 := cp1.xform[i].GetVariation(j); + v2 := cp2.xform[i].GetVariation(j); + if v1 = v2 then + xform[i].SetVariation(j, v1) + else + xform[i].SetVariation(j, c0 * v1 + c1 * v2); + end; for j:= 0 to GetNrVariableNames-1 do begin cp1.xform[i].GetVariable(GetVariableNameAt(j), v1); cp2.xform[i].GetVariable(GetVariableNameAt(j), v2); - v1 := c0 * v1 + c1 * v2; - Result.xform[i].SetVariable(GetVariableNameAt(j), v1); + if v1 <> v2 then v1 := c0 * v1 + c1 * v2; + xform[i].SetVariable(GetVariableNameAt(j), v1); end; // interpol matrices for j := 0 to 2 do begin - Result.xform[i].c[j, 0] := c0 * cp1.xform[i].c[j, 0] + c1 * cp2.xform[i].c[j, 0]; - Result.xform[i].c[j, 1] := c0 * cp1.xform[i].c[j, 1] + c1 * cp2.xform[i].c[j, 1]; - Result.xform[i].p[j, 0] := c0 * cp1.xform[i].p[j, 0] + c1 * cp2.xform[i].p[j, 0]; - Result.xform[i].p[j, 1] := c0 * cp1.xform[i].p[j, 1] + c1 * cp2.xform[i].p[j, 1]; + xform[i].c[j, 0] := c0 * cp1.xform[i].c[j, 0] + c1 * cp2.xform[i].c[j, 0]; + xform[i].c[j, 1] := c0 * cp1.xform[i].c[j, 1] + c1 * cp2.xform[i].c[j, 1]; + xform[i].p[j, 0] := c0 * cp1.xform[i].p[j, 0] + c1 * cp2.xform[i].p[j, 0]; + xform[i].p[j, 1] := c0 * cp1.xform[i].p[j, 1] + c1 * cp2.xform[i].p[j, 1]; end; end; - if Result.NumXForms < numTX then - begin - Result.xform[Result.NumXForms].Assign(Result.xform[numTX]); - Result.xform[numTX].Clear; - end; - if numTX1 < numTX then begin cp1.xform[numTX1].Assign(cp1.xform[numTX]); cp1.xform[numTX].Clear; end; - if numTX2 < Result.NumXForms then + if numTX2 < numTX then begin cp2.xform[numTX2].Assign(cp2.xform[numTX]); cp2.xform[numTX].Clear; end; - - Copy(Result, false, numTX); - cmap := Result.cmap; - result.free; end; procedure TControlPoint.InterpolateX(cp1, cp2: TControlPoint; Tm: double); var - result: TControlPoint; c0, c1: double; i, j: integer; - r, s, t: array[0..2] of double; v1, v2: double; -// totvar: double; - {z,rhtime: double;} - nXforms1, nXforms2: integer; + nXforms1, nXmax: integer; begin if (cp2.time - cp1.time) > 1E-6 then begin c0 := (cp2.time - tm) / (cp2.time - cp1.time); @@ -1881,8 +1853,9 @@ begin c1 := 0; end; - Result := TControlPoint.Create; - Result.time := Tm; + // AV: replaced all useless copying into temporary Result variable + // by direct assignments to self ControlPoint instance + self.time := Tm; { // AV: since from now this is used only for mutants, we can skip it if cp1.cmap_inter = 0 then @@ -1904,30 +1877,30 @@ begin Result.cmap[i][2] := Round(255 * r[2]); end; } - Result.cmap := cp1.cmap; // AV - Result.cmapindex := -1; + cmap := cp1.cmap; // AV + cmapindex := -1; - Result.Fbrightness := c0 * cp1.Fbrightness + c1 * cp2.Fbrightness; - Result.contrast := c0 * cp1.contrast + c1 * cp2.contrast; - Result.gamma := c0 * cp1.gamma + c1 * cp2.gamma; - Result.vibrancy := c0 * cp1.vibrancy + c1 * cp2.vibrancy; - Result.gamma_threshold := c0 * cp1.gamma_threshold + c1 * cp2.gamma_threshold; - Result.width := cp1.width; - Result.height := cp1.height; - Result.spatial_oversample := Round(c0 * cp1.spatial_oversample + c1 * cp2.spatial_oversample); - Result.center[0] := c0 * cp1.center[0] + c1 * cp2.center[0]; - Result.center[1] := c0 * cp1.center[1] + c1 * cp2.center[1]; - Result.FAngle := c0 * cp1.FAngle + c1 * cp2.FAngle; - Result.pixels_per_unit := c0 * cp1.pixels_per_unit + c1 * cp2.pixels_per_unit; + Fbrightness := c0 * cp1.Fbrightness + c1 * cp2.Fbrightness; + contrast := c0 * cp1.contrast + c1 * cp2.contrast; + gamma := c0 * cp1.gamma + c1 * cp2.gamma; + vibrancy := c0 * cp1.vibrancy + c1 * cp2.vibrancy; + gamma_threshold := c0 * cp1.gamma_threshold + c1 * cp2.gamma_threshold; + width := cp1.width; + height := cp1.height; + spatial_oversample := Round(c0 * cp1.spatial_oversample + c1 * cp2.spatial_oversample); + center[0] := c0 * cp1.center[0] + c1 * cp2.center[0]; + center[1] := c0 * cp1.center[1] + c1 * cp2.center[1]; + FAngle := c0 * cp1.FAngle + c1 * cp2.FAngle; + pixels_per_unit := c0 * cp1.pixels_per_unit + c1 * cp2.pixels_per_unit; { // AV: since from now this is used only for mutants, we can skip it Result.background[0] := c0 * cp1.background[0] + c1 * cp2.background[0]; Result.background[1] := c0 * cp1.background[1] + c1 * cp2.background[1]; Result.background[2] := c0 * cp1.background[2] + c1 * cp2.background[2]; } - Result.spatial_filter_radius := c0 * cp1.spatial_filter_radius + c1 * cp2.spatial_filter_radius; - Result.sample_density := c0 * cp1.sample_density + c1 * cp2.sample_density; - Result.zoom := c0 * cp1.zoom + c1 * cp2.zoom; - Result.nbatches := Round(c0 * cp1.nbatches + c1 * cp2.nbatches); + spatial_filter_radius := c0 * cp1.spatial_filter_radius + c1 * cp2.spatial_filter_radius; + sample_density := c0 * cp1.sample_density + c1 * cp2.sample_density; + zoom := c0 * cp1.zoom + c1 * cp2.zoom; + nbatches := Round(c0 * cp1.nbatches + c1 * cp2.nbatches); { Result.white_level := Round(c0 * cp1.white_level + c1 * cp2.white_level); for i := 0 to 3 do begin @@ -1935,11 +1908,12 @@ begin Result.wiggle[i div 2][i mod 2] := c0 * cp1.wiggle[i div 2][i mod 2] + c1 * cp2.wiggle[i div 2][i mod 2]; end; } - Result.cameraPitch := c0 * cp1.cameraPitch; // AV - Result.cameraYaw := c0 * cp1.cameraYaw; // AV - Result.cameraRoll := c0 * cp1.cameraRoll; // AV + cameraPitch := c0 * cp1.cameraPitch; // AV + cameraYaw := c0 * cp1.cameraYaw; // AV + cameraRoll := c0 * cp1.cameraRoll; // AV // save finalxform from mut(il)ation ;) + { nXforms1 := cp1.NumXForms; if cp1.HasFinalXForm then begin @@ -1967,42 +1941,60 @@ begin cp2.xform[NXFORMS].Clear; cp2.xform[NXFORMS].symmetry := 1; end; - - for i := 0 to NXFORMS do + } + nXforms1 := cp1.NumXForms; + nXmax := cp2.NumXForms; + nXmax := max(nxForms1, nXmax); + // AV: since we don't change final xforms, we can speed up the calculations + for i := 0 to nXmax - 1 do begin - Result.xform[i].density := c0 * cp1.xform[i].density + c1 * cp2.xform[i].density; - // AV: since we don't change final xforms, we can speed up the calculations - if Result.xform[i].density = 0.0 then break; - Result.xform[i].color := c0 * cp1.xform[i].color + c1 * cp2.xform[i].color; - Result.xform[i].symmetry := c0 * cp1.xform[i].symmetry + c1 * cp2.xform[i].symmetry; - Result.xform[i].transOpacity := c0 * cp1.xform[i].transOpacity + c1; // AV + xform[i].density := c0 * cp1.xform[i].density + c1 * cp2.xform[i].density; + xform[i].color := c0 * cp1.xform[i].color + c1 * cp2.xform[i].color; + xform[i].symmetry := c0 * cp1.xform[i].symmetry + c1 * cp2.xform[i].symmetry; + xform[i].transOpacity := c0 * cp1.xform[i].transOpacity + c1; // AV - for j := 0 to NrVar-1 do - Result.xform[i].SetVariation(j, c0 * cp1.xform[i].GetVariation(j) + c1 * cp2.xform[i].GetVariation(j)); + for j := 0 to NrVar-1 do begin + //xform[i].SetVariation(j, c0 * cp1.xform[i].GetVariation(j) + c1 * cp2.xform[i].GetVariation(j)); + v1 := cp1.xform[i].GetVariation(j); + v2 := cp2.xform[i].GetVariation(j); + if v1 = v2 then + xform[i].SetVariation(j, v1) + else + xform[i].SetVariation(j, c0 * v1 + c1 * v2); + end; for j:= 0 to GetNrVariableNames-1 do begin cp1.xform[i].GetVariable(GetVariableNameAt(j), v1); cp2.xform[i].GetVariable(GetVariableNameAt(j), v2); - v1 := c0 * v1 + c1 * v2; - Result.xform[i].SetVariable(GetVariableNameAt(j), v1); + if v1 <> v2 then v1 := c0 * v1 + c1 * v2; // AV + xform[i].SetVariable(GetVariableNameAt(j), v1); end; // interpol matrix for j := 0 to 2 do begin - Result.xform[i].c[j, 0] := c0 * cp1.xform[i].c[j, 0] + c1 * cp2.xform[i].c[j, 0]; - Result.xform[i].c[j, 1] := c0 * cp1.xform[i].c[j, 1] + c1 * cp2.xform[i].c[j, 1]; + xform[i].c[j, 0] := c0 * cp1.xform[i].c[j, 0] + c1 * cp2.xform[i].c[j, 0]; + xform[i].c[j, 1] := c0 * cp1.xform[i].c[j, 1] + c1 * cp2.xform[i].c[j, 1]; // AV - Result.xform[i].p[j, 0] := c0 * cp1.xform[i].p[j, 0] + c1 * cp2.xform[i].p[j, 0]; - Result.xform[i].p[j, 1] := c0 * cp1.xform[i].p[j, 1] + c1 * cp2.xform[i].p[j, 1]; + xform[i].p[j, 0] := c0 * cp1.xform[i].p[j, 0] + c1 * cp2.xform[i].p[j, 0]; + xform[i].p[j, 1] := c0 * cp1.xform[i].p[j, 1] + c1 * cp2.xform[i].p[j, 1]; end; end; + finalXformEnabled := cp1.finalXformEnabled; // finalxform was supposed to be mutate-able too, but somehow it's always - // getting confused by random-generated mutatns :-\ - if Result.NumXForms < NXFORMS then + // getting confused by random-generated mutants :-\ + + if cp1.HasFinalXForm then begin + xform[nXmax].Assign(cp1.xform[nXforms1]); + if nXforms1 < nXmax then // reset color speed of cp1's final transform + xform[nXforms1].symmetry := 0; + end + else + xform[nXmax].Symmetry := 1; + { + if NumXForms < NXFORMS then begin - Result.xform[Result.NumXForms].Assign(cp1.xform[NXFORMS]); //result.xform[NXFORMS]); - Result.xform[NXFORMS].Clear; + xform[NumXForms].Assign(cp1.xform[NXFORMS]); + xform[NXFORMS].Clear; end; - Result.finalXformEnabled := cp1.finalXformEnabled; // restore finalxforms in source CPs if nXforms1 < NXFORMS then @@ -2015,10 +2007,7 @@ begin cp2.xform[nXforms2].Assign(cp2.xform[NXFORMS]); cp2.xform[NXFORMS].Clear; end; - - Copy(Result, false, max(nxForms1, nxForms2)); // AV: added 2 parameters - cmap := Result.cmap; - result.free; + } end; procedure TControlPoint.SaveToFile(Filename: string); @@ -2088,8 +2077,8 @@ begin // sl.add(format('nbatches %d white_level %d background %f %f %f', - changed to integers - mt sl.add(format('nbatches %d white_level %d background %d %d %d', [nbatches, white_level, background[0], background[1], background[2]])); - sl.add(format('brightness %f gamma %f contrast %f vibrancy %f gamma_threshold %f hue_rotation %f cmap_inter %d', - [Fbrightness * BRIGHT_ADJUST, gamma, contrast, vibrancy, gamma_threshold, hue_rotation, cmap_inter])); // AV: added contrast + sl.add(format('brightness %f gamma %f contrast %f vibrancy %f gamma_threshold %f hue_rotation %f', {cmap_inter %d',} + [Fbrightness * BRIGHT_ADJUST, gamma, contrast, vibrancy, gamma_threshold, hue_rotation {, cmap_inter}])); // AV: added contrast sl.add(format('finalxformenabled %d', [ifthen(finalxformenabled, 1, 0)])); sl.add(format('soloxform %d', [soloXform])); @@ -2198,12 +2187,12 @@ var handle: File; begin // I'm a bit ashamed but this hack has do to it for now... - AssignFile(handle, GetEnvironmentVariable('TEMP') + '\CalcBinaryFlameSizeTemp.bin'); + AssignFile(handle, AppData + 'CalcBinaryFlameSizeTemp.bin'); ReWrite(handle, HIB_BLOCKSIZE); cp.SaveToBinary(handle); Result := FileSize(handle) * HIB_BLOCKSIZE; CloseFile(handle); - DeleteFile(GetEnvironmentVariable('TEMP') + '\CalcBinaryFlameSizeTemp.bin'); + DeleteFile(AppData + 'CalcBinaryFlameSizeTemp.bin'); (*// CP data Result := 224; @@ -2258,12 +2247,16 @@ begin DoubleToBlock(block, 0, cameraPitch); DoubleToBlock(block, 8, cameraYaw); BlockWrite(handle, block, 1); -// AV TODO: cam_roll, contrast and var_order - DoubleToBlock(block, 0, cameraPersp); + + DoubleToBlock(block, 0, cameraRoll); // AV DoubleToBlock(block, 8, cameraZpos); BlockWrite(handle, block, 1); + + DoubleToBlock(block, 0, cameraPersp); + DoubleToBlock(block, 8, cameraDOF); + BlockWrite(handle, block, 1); - DoubleToBlock(block, 0, cameraDOF); + DoubleToBlock(block, 0, contrast); // AV DoubleToBlock(block, 8, spatial_filter_radius); BlockWrite(handle, block, 1); @@ -2271,19 +2264,19 @@ begin DoubleToBlock(block, 8, gamma_threshold); BlockWrite(handle, block, 1); - Int32ToBlock(block, 0, cmapindex); + //Int32ToBlock(block, 0, cmapindex);// TODO: replace Int32ToBlock(block, 4, spatial_oversample); Int32ToBlock(block, 8, Width); Int32ToBlock(block, 12, Height); BlockWrite(handle, block, 1); Int32ToBlock(block, 0, nbatches); - Int32ToBlock(block, 4, cmap_inter); + //Int32ToBlock(block, 4, cmap_inter); // TODO: replace Int32ToBlock(block, 8, ifthen(finalxformenabled, 1, 0)); Int32ToBlock(block, 12, soloXform); BlockWrite(handle, block, 1); - Int32ToBlock(block, 0, white_level); + //Int32ToBlock(block, 0, white_level); // TODO: replace Int32ToBlock(block, 4, background[0]); Int32ToBlock(block, 8, background[1]); Int32ToBlock(block, 12, background[2]); @@ -2305,6 +2298,7 @@ begin Int32ToBlock(block, 4, nvariables); Int32ToBlock(block, 8, nchaos); +// AV TODO: var_order str := ''; for i := 0 to nvariations-1 do str := str + VarNames(i) + #0; @@ -2375,8 +2369,79 @@ begin end; end; +procedure TControlPoint.DirectCopy_AV(const cp1: TControlPoint); // AV +var + i, j: smallint; +begin + self.name := cp1.name; + self.time := cp1.time; + + if cp1.cmapindex >= 0 then cmapindex := cp1.cmapindex; + hue_rotation := cp1.hue_rotation; // AV + cmap := cp1.cmap; + + zoom := cp1.zoom; + Fangle := cp1.FAngle; + cameraPitch := cp1.cameraPitch; + cameraYaw := cp1.cameraYaw; + cameraRoll := cp1.cameraRoll; + cameraPersp := cp1.cameraPersp; + cameraZpos := cp1.cameraZpos; + cameraDOF := cp1.cameraDOF; + + Width := cp1.Width; + Height := cp1.Height; + + center[0]:= cp1.center[0]; + center[1]:= cp1.center[1]; + pixels_per_unit := cp1.pixels_per_unit; + + background[0] := cp1.background[0]; + background[1] := cp1.background[1]; + background[2] := cp1.background[2]; + + for i := 0 to 3 do + for j := 0 to 3 do begin + curveWeights[i,j] := cp1.curveWeights[i,j]; + curvePoints[i,j].x := cp1.curvePoints[i,j].x; + curvePoints[i,j].y := cp1.curvePoints[i,j].y; + end; + + spatial_oversample := cp1.spatial_oversample; + spatial_filter_radius := cp1.spatial_filter_radius; + sample_density := cp1.sample_density; + + nbatches := cp1.nbatches; + //white_level := cp1.white_level; // <-- AV: it's const for now + //jitters := cp1.jitters; //<-- AV: currently unused + //Transparency := cp1.Transparency; // <-- do this? + + brightness := cp1.brightness; + gamma := cp1.gamma; + gamma_threshold := cp1.gamma_threshold; + contrast := cp1.contrast; // AV + vibrancy := cp1.vibrancy; + + finalXformEnabled := cp1.finalXformEnabled; + soloXform := cp1.soloXform; + + estimator := cp1.estimator; + estimator_min := cp1.estimator_min; + estimator_curve := cp1.estimator_curve; + enable_de := cp1.enable_de; + + comment := cp1.comment; // AV + + // used_plugins := cp1.used_plugins; // <<--- fixed memory leak // AV + used_plugins.Clear; // AV: that's how we must copy strings: + used_plugins.AddStrings(cp1.used_plugins); + + for i := 0 to NXFORMS do // was: NXFORMS-1 + xform[i].assign(cp1.xform[i]); +end; function TControlPoint.Clone: TControlPoint; +(* var i, j: integer; sl: TStringList; @@ -2397,7 +2462,8 @@ begin Result.estimator_min := estimator_min; Result.estimator_curve := estimator_curve; Result.enable_de := enable_de; - Result.xdata := xdata; + // Result.xdata := xdata; + Result.comment := comment; // AV Result.Background[0] := background[0]; Result.Background[1] := background[1]; @@ -2419,22 +2485,31 @@ begin Result.xform[i].assign(xform[i]); sl.Free; + *) +begin + Result := TControlPoint.Create; + Result.DirectCopy_AV(self); // AV + Result.Transparency := Transparency; end; -procedure TControlPoint.Copy(cp1: TControlPoint; KeepSizes: boolean = false; nt: byte = NXFORMS); +procedure TControlPoint.Copy(cp1: TControlPoint; KeepSizes: boolean = false); var - i, j: integer; - sl: TStringList; + //i, j: integer; + //sl: TStringList; w, h: integer; begin w := Width; h := Height; Clear; + DirectCopy_AV(cp1); // AV: made it faster than ever! + + if KeepSizes then AdjustScale(w, h); + (* sl := TStringList.Create; // --Z-- this is quite a weird and unoptimal way to copy things: - cp1.SaveToStringlist(sl); + cp1.SaveToStringlist(sl); // <-- AV: so we must optimize it ;-) ParseStringlist(sl); Fangle := cp1.FAngle; @@ -2452,7 +2527,8 @@ begin estimator_curve := cp1.estimator_curve; enable_de := cp1.enable_de; // used_plugins := cp1.used_plugins; // <<--- fixed memory leak // AV - xdata := cp1.xdata; + // xdata := cp1.xdata; + comment := cp1.comment; // AV background[0] := cp1.background[0]; background[1] := cp1.background[1]; @@ -2480,6 +2556,7 @@ begin finalXformEnabled := cp1.finalXformEnabled; sl.Free; + *) end; procedure TControlPoint.ParseStringList(sl: TStringlist); @@ -2502,7 +2579,7 @@ begin cmapindex := -1; hue_rotation := 1; // AV zoom := 0; - xdata := ''; + comment := ''; // AV for i := 0 to NXFORMS do xform[i].Clear; FinalXformEnabled := false; soloxform := -1; @@ -2515,14 +2592,9 @@ begin curvePoints[i][3].x := 1.00; curvePoints[i][3].y := 1.00; curveWeights[i][3] := 1; end; - try - if (used_plugins <> nil) then + if (used_plugins <> nil) then used_plugins.Clear; // else used_plugins := TStringlist.Create; // AV: now it's not needed - except - // hack - // used_plugins := TStringList.Create; // AV: now it's not needed - end; end; function TControlPoint.HasFinalXForm: boolean; @@ -2540,42 +2612,22 @@ begin end; function add_symmetry_to_control_point(var cp: TControlPoint; sym: integer): integer; -const - sym_distrib: array[0..14] of integer = ( - -4, -3, - -2, -2, -2, - -1, -1, -1, - 2, 2, 2, - 3, 3, - 4, 4 - ); var i, j, k: integer; a: double; begin result := 0; if (0 = sym) then - if (random(1) <> 0) then - sym := sym_distrib[random(14)] - else if (random(32) <> 0) then // not correct - sym := random(13) - 6 - else - sym := random(51) - 25; + sym := random(13) - 6; if (1 = sym) or (0 = sym) then - begin - result := 0; - exit; - end; + Exit(0); // AV - for i := 0 to NXFORMS - 1 do - if (cp.xform[i].density = 0.0) then break; + i := cp.NumXForms; // AV + + if (i + abs(sym)>= NXFORMS) then // AV: take into account additional xforms + Exit(0); - if (i = NXFORMS) then - begin - result := 0; - exit; - end; cp.symmetry := sym; if (sym < 0) then @@ -2585,7 +2637,7 @@ begin cp.xform[i].SetVariation(0, 1.0); for j := 1 to NRVAR - 1 do cp.xform[i].SetVariation(j, 0.0); - cp.xform[i].color := 1.0; + cp.xform[i].color := 1.0; // AV: why if color_speed = 1?! cp.xform[i].c[0][0] := -1.0; cp.xform[i].c[0][1] := 0.0; cp.xform[i].c[1][0] := 0.0; @@ -2600,9 +2652,7 @@ begin a := 2 * PI / sym; -// for (k = 1; (k < sym)&&(i < NXFORMS); k + + ) { k := 1; -// while (k < sym) and (i < NXFORMS) do while (k < sym) and (i < SymmetryNVars) do begin cp.xform[i].density := 1.0; @@ -2611,17 +2661,12 @@ begin for j := 1 to NRVAR - 1 do cp.xform[i].SetVariation(j, 0); if sym < 3 then - cp.xform[i].color := 0 + cp.xform[i].color := 0 // AV: why if color_speed = 1?! else cp.xform[i].color := (k - 1) / (sym - 2); - if cp.xform[i].color > 1 then - begin -// ShowMessage('Color value larger than 1'); - repeat - cp.xform[i].color := cp.xform[i].color - 1 - until cp.xform[i].color <= 1; - end; + while cp.xform[i].color > 1 do // AV: why if color_speed = 1?! + cp.xform[i].color := cp.xform[i].color - 1; cp.xform[i].c[0][0] := cos(k * a); cp.xform[i].c[0][1] := sin(k * a); @@ -2636,13 +2681,13 @@ begin end; end; -procedure tile_control_point(var cp: TControlPoint; sym: integer); -var k, i, j: integer; +procedure tile_control_point(var cp: TControlPoint; sym: integer); // AV +var + k, i, j: smallint; t, cost, sint: double; begin - for k := 0 to NXFORMS - 1 do - if (cp.xform[k].density = 0.0) then break; - if (k = NXFORMS) then exit; + k := cp.NumXForms; + if (k > NXFORMS - 5) then exit; case sym of 1: @@ -2699,7 +2744,97 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// + //*************************************************************** + +function det(a, b, c, d: double): double; +begin + Result := (a * d - b * c); +end; + +function solve3(x1, x2, x1h, y1, y2, y1h, z1, z2, z1h: double; + var a, b, e: double): double; +var + det1: double; +begin + det1 := x1 * det(y2, 1.0, z2, 1.0) - x2 * det(y1, 1.0, z1, 1.0) + + 1 * det(y1, y2, z1, z2); + if (det1 = 0.0) then + begin + Result := det1; + EXIT; + end + else + begin + a := (x1h * det(y2, 1.0, z2, 1.0) - x2 * det(y1h, 1.0, z1h, 1.0) + + 1 * det(y1h, y2, z1h, z2)) / det1; + b := (x1 * det(y1h, 1.0, z1h, 1.0) - x1h * det(y1, 1.0, z1, 1.0) + + 1 * det(y1, y1h, z1, z1h)) / det1; + e := (x1 * det(y2, y1h, z2, z1h) - x2 * det(y1, y1h, z1, z1h) + + x1h * det(y1, y2, z1, z2)) / det1; + a := Round6(a); + b := Round6(b); + e := Round6(e); + Result := det1; + end; +end; + +function dist(x1, y1, x2, y2: double): double; +//var +// d2: double; +begin +(* + { From FDesign source + { float pt_pt_distance(float x1, float y1, float x2, float y2) } + d2 := (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + if (d2 = 0.0) then + begin + Result := 0.0; + exit; + end + else + Result := sqrt(d2); +*) + + // --Z-- This is just amazing... :-\ + // Someone needed an 'FDesign source' - to compute distance between two points??!? + + Result := Hypot(x2-x1, y2-y1); +end; + +function line_dist(x, y, x1, y1, x2, y2: double): double; +var + a, b, e, c: double; +begin + if ((x = x1) and (y = y1)) then + a := 0.0 + else + a := sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); + if ((x = x2) and (y = y2)) then + b := 0.0 + else + b := sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); + if ((x1 = x2) and (y1 = y2)) then + e := 0.0 + else + e := sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + if ((a * a + e * e) < (b * b)) then + Result := a + else if ((b * b + e * e) < (a * a)) then + Result := b + else if (e <> 0.0) then + begin + c := (b * b - a * a - e * e) / (-2 * e); + if ((a * a - c * c) < 0.0) then + Result := 0.0 + else + Result := sqrt(a * a - c * c); + end + else + Result := a; +end; + +//**************************************************************************// + procedure TControlPoint.ZoomtoRect(R: TSRect); var scale, ppu: double; @@ -2720,7 +2855,6 @@ begin pixels_per_unit := pixels_per_unit * Width / abs(r.Right - r.Left); end; -/////////////////////////////////////////////////////////////////////////////// procedure TControlPoint.ZoomOuttoRect(R: TSRect); var ppu: double; @@ -2740,7 +2874,6 @@ begin center[1] := center[1] - sin(FAngle) * dx - cos(FAngle) * dy; end; -/////////////////////////////////////////////////////////////////////////////// procedure TControlPoint.ZoomIn(Factor: double); var scale: double; @@ -2751,7 +2884,6 @@ begin Zoom := Log2(Scale); end; -/////////////////////////////////////////////////////////////////////////////// procedure TControlPoint.MoveRect(R: TSRect); var scale: double; @@ -2769,13 +2901,13 @@ begin center[1] := center[1] + sin(FAngle) * dx + cos(FAngle) * dy ; end; -/////////////////////////////////////////////////////////////////////////////// procedure TControlPoint.Rotate(Angle: double); begin FAngle := FAngle + Angle; end; -/////////////////////////////////////////////////////////////////////////////// +{//////////////////////////////////////////////////////////////////////////////} + function TControlPoint.getppux: double; begin result := pixels_per_unit * power(2, zoom) @@ -2786,7 +2918,7 @@ begin result := pixels_per_unit * power(2, zoom) end; -/////////////////////////////////////////////////////////////////////////////// +{/////////////////////////////////////////////////////////////////////////////} function TControlPoint.GetBrightness: double; begin Result := Fbrightness; @@ -2800,7 +2932,7 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// +{//////////////////////////////////////////////////////////////////////////////} function TControlPoint.GetRelativeGammaThreshold: double; begin if Fbrightness <> 0 then @@ -2814,7 +2946,8 @@ begin gamma_threshold := gtr * Fbrightness; end; -/////////////////////////////////////////////////////////////////////////////// +{//////////////////////////////////////////////////////////////////////////////} +(* var vdfilled: boolean = False; @@ -2845,15 +2978,15 @@ begin vdfilled := true; end; - -/////////////////////////////////////////////////////////////////////////////// + *) +{////////////////////////////////////////////////////////////////////////////} // // --Z-- cp-specific functions moved here from MainForm // function TControlPoint.NumXForms: integer; var - i: integer; + i: smallint; begin //... Result := NXFORMS; @@ -2870,13 +3003,14 @@ end; function TControlPoint.TrianglesFromCP(var Triangles: TTriangles): integer; { Sets up the triangles from the IFS code } var - i, j: integer; - temp_x, temp_y, xset, yset: double; - left, top, bottom, right: double; + i, j: smallint; + //temp_x, temp_y, xset, yset: double; + //left, top, bottom, right: double; begin - top := 0; bottom := 0; right := 0; left := 0; Result := NumXForms; { + top := 0; bottom := 0; right := 0; left := 0; + if ReferenceMode > 0 then begin for i := 0 to Result-1 do @@ -2954,15 +3088,9 @@ begin Triangles[j].y[i] := -Triangles[j].y[i]; end; -procedure TControlPoint.EqualizeWeights; -var - t, i: integer; -begin - t := NumXForms; - for i := 0 to t - 1 do - xform[i].density := 0.5; -end; +//************ Weight distribution utils *************************// +(* // AV: we have the save methods in RndFlame module procedure TControlPoint.NormalizeWeights; var i: integer; @@ -2978,14 +3106,6 @@ begin xform[i].Density := xform[i].Density / td; end; -procedure TControlPoint.RandomizeWeights; -var - i: integer; -begin - for i := 0 to Transforms - 1 do - xform[i].Density := Random; -end; - procedure TControlPoint.ComputeWeights(Triangles: TTriangles; t: integer); // Caclulate transform weight from triangle areas var @@ -3004,6 +3124,7 @@ begin end; //? cp1.NormalizeWeights; end; +*) procedure TControlPoint.NormalizeProbabilities; // AV: useful for matematicians, useless for other people :) @@ -3026,61 +3147,58 @@ end; procedure TControlPoint.CalculateWeights; // AV: Calculate transform weight from its affine determinants var - i: integer; - deta, detp: double; + i: smallint; + deta: double; begin for i := 0 to NumXForms - 1 do begin with xform[i] do - begin - deta := c[0][0] * c[1][1] - c[0][1] * c[1][0]; - detp := p[0][0] * p[1][1] - p[0][1] * p[1][0]; - end; - - deta := abs(deta * detp); + deta := abs(detC * detP); if (deta < 1E-6) then deta := 1E-6; - xform[i].Density := deta; + + xform[i].density := deta; end; end; -procedure TControlPoint.CalculateColorSpeed; +procedure TControlPoint.CalculateColorSpeed; // AV: experimental method var - i: integer; - maxw, sumw, w0, d: double; + i, t: smallint; + maxw, sumw, w0: double; eqw: boolean; begin - if Transforms = 1 then exit; // single xform + t := NumXForms; + if t = 1 then exit; // single xform eqw := True; w0 := xform[0].density; - maxw := w0; sumw := 0; - for i := 0 to Transforms - 1 do + maxw := w0; sumw := w0; + for i := 1 to t - 1 do begin sumw := sumw + xform[i].density; if (xform[i].density > maxw) then maxw := xform[i].density; if eqw then if (xform[i].density <> w0) then eqw := False; end; - + if (not eqw) then - for i := 0 to Transforms - 1 do + for i := 0 to t - 1 do begin with xform[i] do begin - if (GetVariation(0) = 1) then // if affine - begin - d := abs(c[0,0]*c[1,1] - c[0,1]*c[1,0]); // contraction factor - symmetry := min(d, 1); - end + if (GetVariation(0) = 1) then // if affine - check contraction factor + symmetry := min(abs(detC), 1) else if (density > 0.01) then symmetry := 0.85 * density / maxw else symmetry := -1; end; end - else // equal weights - for i := 0 to Transforms - 1 do - xform[i].symmetry := 0; + else // equal weights + for i := 0 to t - 1 do + with xform[i] do + symmetry := min(abs(detC * detP), 0.85); end; +//*********************************************************************// + procedure TControlPoint.GetFromTriangles(const Triangles: TTriangles; const t: integer); var i: integer; diff --git a/Flame/RndFlame.pas b/Flame/RndFlame.pas index d7a432b..b54fd15 100644 --- a/Flame/RndFlame.pas +++ b/Flame/RndFlame.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -26,9 +26,13 @@ unit RndFlame; interface uses - ControlPoint, Xform; + ControlPoint; -function RandomFlame(SourceCP: TControlPoint= nil; algorithm: integer = 0): TControlPoint; +function RandomFlame(SourceCP: TControlPoint = nil; algorithm: integer = 0): TControlPoint; + +// AV: made the following public to get rid of duplicated code +procedure SetVariation(cp: TControlPoint); +procedure RandomVariation(cp: TControlPoint); implementation @@ -75,83 +79,6 @@ begin end; end; *) -function CreatePalette(strng: string): TColorMap; -{ Loads a palette from a gradient string } -var - Strings: TStringList; - index, i: integer; - Tokens: TStringList; - Indices, Colors: TStringList; - a, b: integer; -begin - Strings := TStringList.Create; - Tokens := TStringList.Create; - Indices := TStringList.Create; - Colors := TStringList.Create; - try - try - Strings.Text := strng; - if Pos('}', Strings.Text) = 0 then raise EFormatInvalid.Create('No closing brace'); - if Pos('{', Strings[0]) = 0 then raise EFormatInvalid.Create('No opening brace.'); - GetTokens(ReplaceTabs(strings.text), tokens); - Tokens.Text := Trim(Tokens.text); - i := 0; - while (Pos('}', Tokens[i]) = 0) and (Pos('opacity:', Lowercase(Tokens[i])) = 0) do - begin - if Pos('index=', LowerCase(Tokens[i])) <> 0 then - Indices.Add(GetVal(Tokens[i])) - else if Pos('color=', LowerCase(Tokens[i])) <> 0 then - Colors.Add(GetVal(Tokens[i])); - inc(i) - end; - for i := 0 to 255 do - begin - Result[i][0] := 0; - Result[i][1] := 0; - Result[i][2] := 0; - end; - if Indices.Count = 0 then raise EFormatInvalid.Create('No color info'); - for i := 0 to Indices.Count - 1 do - begin - try - index := StrToInt(Indices[i]); - while index < 0 do inc(index, 400); - index := Round(Index * (255 / 399)); - indices[i] := IntToStr(index); - assert(index>=0); - assert(index<256); - Result[index][0] := StrToInt(Colors[i]) mod 256; - Result[index][1] := trunc(StrToInt(Colors[i]) / 256) mod 256; - Result[index][2] := trunc(StrToInt(Colors[i]) / 65536); - except - end; - end; - i := 1; - repeat - a := StrToInt(Trim(Indices[i - 1])); - b := StrToInt(Trim(Indices[i])); - RGBBlend(a, b, Result); - inc(i); - until i = Indices.Count; - if (Indices[0] <> '0') or (Indices[Indices.Count - 1] <> '255') then - begin - a := StrToInt(Trim(Indices[Indices.Count - 1])); - b := StrToInt(Trim(Indices[0])) + 256; - RGBBlend(a, b, Result); - end; - except on EFormatInvalid do - begin -// Result := False; - end; - end; - finally - Tokens.Free; - Strings.Free; - Indices.Free; - Colors.Free; - end; -end; - procedure GetGradientFileGradientsNames(const filename: string; var NamesList: TStringList); var i, p: integer; @@ -225,7 +152,53 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// +{ ****************** Triangle transformations ******************************* } + +function transform_affine(const t: TTriangle; const Triangles: TTriangles): boolean; +var + ra, rb, rc, a, b, c: double; +begin + Result := True; + ra := dist(Triangles[-1].y[0], Triangles[-1].x[0], + Triangles[-1].y[1], Triangles[-1].x[1]); + rb := dist(Triangles[-1].y[1], Triangles[-1].x[1], + Triangles[-1].y[2], Triangles[-1].x[2]); + rc := dist(Triangles[-1].y[2], Triangles[-1].x[2], + Triangles[-1].y[0], Triangles[-1].x[0]); + a := dist(t.y[0], t.x[0], t.y[1], t.x[1]); + b := dist(t.y[1], t.x[1], t.y[2], t.x[2]); + c := dist(t.y[2], t.x[2], t.y[0], t.x[0]); + if (a > ra) then + Result := False + else if (b > rb) then + Result := False + else if (c > rc) then + Result := False + else if ((a = ra) and (b = rb) and (c = rc)) then + Result := False; +end; + +function triangle_area(t: TTriangle): double; +var + base, height: double; +begin + try + base := dist(t.x[0], t.y[0], t.x[1], t.y[1]); + height := line_dist(t.x[2], t.y[2], t.x[1], t.y[1], + t.x[0], t.y[0]); + if (base < 1.0) then + Result := height + else if (height < 1.0) then + Result := base + else + Result := 0.5 * base * height; + except on E: EMathError do + Result := 0; + end; +end; + +{ ************************************************************************** } + procedure RandomVariation(cp: TControlPoint); { Randomise variation parameters } var @@ -236,26 +209,23 @@ begin RandSeed := MainSeed; VarPossible := false; - for j := 0 to NRVAR - 1 do begin - VarPossible := VarPossible or Variations[j]; - end; + for j := 0 to NRVAR - 1 do + if Variations[j] then begin // AV: make it faster! + VarPossible := True; + break; + end; + if not VarPossible then Variations[0] := True; // AV for i := 0 to cp.NumXForms - 1 do begin for j := 0 to NRVAR - 1 do cp.xform[i].SetVariation(j, 0); - if VarPossible then begin - repeat - a := random(NRVAR); - until Variations[a]; - - repeat - b := random(NRVAR); - until Variations[b]; - end else begin - a := 0; - b := 0; - end; + repeat + a := random(NRVAR); + until Variations[a]; + repeat + b := random(NRVAR); + until Variations[b]; if (a = b) then begin cp.xform[i].SetVariation(a, 1); @@ -278,7 +248,7 @@ begin for i := 0 to cp.NumXForms - 1 do begin for j := 0 to NRVAR - 1 do cp.xform[i].SetVariation(j, 0); - cp.xform[i].SetVariation(integer(Variation), 1); + cp.xform[i].SetVariation(Variation, 1); end; end; @@ -414,16 +384,17 @@ begin end; /////////////////////////////////////////////////////////////////////////////// +(* procedure RandomWeights(var cp1: TControlPoint); { Randomizes xform weights } var i: integer; begin - for i := 0 to Transforms - 1 do + for i := 0 to cp1.NumXForms - 1 do // AV: was Transforms - 1 cp1.xform[i].Density := random; NormalizeWeights(cp1); end; - +*) /////////////////////////////////////////////////////////////////////////////// function RandomFlame(SourceCP: TControlPoint; algorithm: integer): TControlPoint; var @@ -444,22 +415,25 @@ begin inc(MainSeed); RandSeed := MainSeed; transforms := random(Max - (Min - 1)) + Min; + repeat try inc(MainSeed); RandSeed := MainSeed; - Result.clear; - Result.RandomCP(transforms, transforms, false); - Result.SetVariation(Variation); - inc(MainSeed); - RandSeed := MainSeed; + Result.Clear; + for i := 0 to Transforms - 1 do // AV: set starting non-zero weights... + Result.xform[i].density := 0.5; + // AV: we don't really need to randomize the same flame twice... + //Result.RandomCP(transforms, transforms, false); + //Result.SetVariation(Variation); // AV: deprecated! + SetVariation(Result); // AV: replaced old method from ControlPoint case algorithm of 1: rnd := 0; 2: rnd := 7; 3: rnd := 9; else - if (Variation = vLinear) or (Variation = vRandom) then + if (Variation = 0 {vLinear}) or (Variation = vRandom) then rnd := random(10) else rnd := 9; @@ -479,11 +453,11 @@ begin Result.xform[i].c[1, 1] := 1; Result.xform[i].c[2, 0] := 0; Result.xform[i].c[2, 1] := 0; - Result.xform[i].color := 0; } - Result.xform[i].symmetry := 0; + Result.xform[i].color := 0; + // AV: this will be done with SetVariation method! Result.xform[i].SetVariation(0, 1); for j := 1 to NRVAR - 1 do - Result.xform[i].SetVariation(j, 0); + Result.xform[i].SetVariation(j, 0); } // AV: hundred of useless calculations {Result.xform[i].Translate(random * 2 - 1, random * 2 - 1); Result.xform[i].Rotate(random * 360); @@ -491,6 +465,7 @@ begin Result.xform[i].Scale(random * 0.8 + 0.2) else Result.xform[i].Scale(random * 0.4 + 0.6); } + Result.xform[i].symmetry := 0; if i > 0 then s := random * 0.8 + 0.2 else @@ -512,7 +487,8 @@ begin Result.xform[i].c[2, 0] := random * 2 - 1; Result.xform[i].c[2, 1] := random * 2 - 1; if Random(2) = 0 then - Result.xform[i].Multiply(1, random - 0.5, random - 0.5, 1); + Result.xform[i].Multiply(Result.xform[i].c, + 1, random - 0.5, random - 0.5, 1); if Random(2) = 1 then begin @@ -529,7 +505,7 @@ begin Result.xform[i].p[2,1] := random * 2 - 1; end; end; - SetVariation(Result); + //SetVariation(Result); end; 7, 8: begin @@ -559,20 +535,31 @@ begin Result.xform[i].c[2][0] := random * 2 - 1; Result.xform[i].c[2][1] := random * 2 - 1; end; + + { // AV: the following was (or will be) done! for i := 0 to NXFORMS-1 do Result.xform[i].density := 0; for i := 0 to Transforms - 1 do Result.xform[i].density := 1 / Transforms; SetVariation(Result); + } end; 9: begin - for i := 0 to NXFORMS-1 do + { // AV: the following was (or will be) done! + for i := 0 to NXFORMS-1 do Result.xform[i].density := 0; for i := 0 to Transforms - 1 do Result.xform[i].density := 1 / Transforms; + } + for i := 0 to Transforms - 1 do begin // AV + Result.xform[i].RandomizeCoefs(Result.xform[i].c); + if Random(4) = 1 then + Result.xform[i].RandomizeCoefs(Result.xform[i].p); + end; end; end; // case Result.TrianglesFromCp(Triangles); + if Random(2) > 0 then ComputeWeights(Result, Triangles, transforms) else @@ -628,8 +615,6 @@ begin Result.background[2] := 0; end; Result.zoom := 0; - //Result.Nick := SheepNick; - //Result.URl := SheepURL; Result.xform[Result.NumXForms].Clear; Result.xform[Result.NumXForms].symmetry := 1; diff --git a/Flame/XForm.pas b/Flame/XForm.pas index 8576909..b13e4dd 100644 --- a/Flame/XForm.pas +++ b/Flame/XForm.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -31,8 +31,7 @@ unit XForm; interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} XFormMan, BaseVariation, Classes; @@ -60,27 +59,33 @@ type end; PXYpoint = ^TXYpoint; + { T2Cpoint = record x, y, c1, c2: double; end; + P2Cpoint = ^T2Cpoint; TMatrix = array[0..2, 0..2] of double; + } -{$ifdef Apo7X64} -{$else} +// AV: rewrote all asm-code from Apo7X to make it work properly again +{$ifdef CPUX86} {$define _ASM_} {$endif} type + TCoefsArray = array[0..2, 0..1] of double; // AV: moved from ControlPoint + //pCoefsArray = ^TCoefsArray; + TXForm = class public - c: array[0..2, 0..1] of double; // the coefs to the affine part of the function - p: array[0..2, 0..1] of double; // post-transform coefs! - density: double; // prob is this function is chosen - color: double; // color coord for this function. 0 - 1 - color2: double; // Second color coord for this function. 0 - 1 - vc: double; // Calculated color to be passed to the plugin + c: TCoefsArray; // the coefs to the affine part of the function + p: TCoefsArray; // post-transform coefs! + density: double; // prob is this function is chosen + color: double; // color coord for this function. 0 - 1 + color2: double; // Second color coord for this function. 0 - 1 + vc: double; // Calculated color to be passed to the plugin symmetry: double; c00, c01, c10, c11, c20, c21: double; // unnecessary duplicated variables p00, p01, p10, p11, p20, p21: double; // :-) @@ -104,7 +109,6 @@ type FTx, FTy: double; // must remain in this order FPx, FPy: double; // some asm code relies on this - FTz, FPz: double; // 3d hack FAngle: double; @@ -153,7 +157,7 @@ type procedure Blur3D; // vars[18] procedure PreBlur; // vars[19] - procedure PreZScale; // vars[2] + procedure PreZScale; // vars[20] procedure PreZTranslate; // vars[21] procedure PreRotateX; // vars[22] procedure PreRotateY; // vars[23] @@ -175,8 +179,8 @@ type procedure Pyramid; // vars[34] procedure Polar2; // vars[35] - function Mul33(const M1, M2: TMatrix): TMatrix; - function Identity: TMatrix; + //function Mul33(const M1, M2: TMatrix): TMatrix; + //function Identity: TMatrix; procedure BuildFunctionlist; procedure AddRegVariations; @@ -193,12 +197,16 @@ type procedure NextPoint(var CPpoint: TCPpoint); procedure NextPointTo(var CPpoint, ToPoint: TCPpoint); procedure NextPointXY(var px, py: double); - procedure NextPoint2C(var p: T2CPoint); + //procedure NextPoint2C(var p: T2CPoint); - procedure Rotate(const degrees: double); - procedure Translate(const x, y: double); - procedure Multiply(const a, b, c, d: double); - procedure Scale(const s: double); + // AV: extended all following methods for post-coefs support + procedure Rotate(var t: TCoefsArray; const degrees: double); + procedure Translate(var t: TCoefsArray; const x, y: double); + procedure Multiply(var t: TCoefsArray; const k, l, m, n: double); + procedure Scale(var t: TCoefsArray; const s: double); + procedure RandomizeCoefs(var t: TCoefsArray); // AV: for random flames + function detC: double; inline; + function detP: double; inline; procedure GetVariable(const name: string; var Value: double); procedure SetVariable(const name: string; var Value: double); @@ -254,7 +262,7 @@ var i: Integer; begin AddRegVariations; BuildFunctionlist; - SetLength(vars, NRLOCVAR + Length(FRegVariations)); + SetLength(vars, NrVar); // <-- AV // NRLOCVAR + Length(FRegVariations)); // AV: set default variations order ifs := TStringList.Create; for i := 0 to NrVar-1 do ifs.Add(Varnames(i)); @@ -308,6 +316,7 @@ var CalculateAngle, CalculateSinCos, CalculateLength: boolean; mode: double; vn: string; + UsedVars: TStringList; begin c00 := c[0][0]; c01 := c[0][1]; @@ -347,31 +356,33 @@ begin // CalculateLength := False; CalculateSinCos := (vars[8] <> 0.0) or (vars[10] <> 0.0); + UsedVars := TStringList.Create; + // Pre- variations - for i := 0 to NrVar - 1 do + for vn in ifs do + begin + v := GetVariationIndex(vn); + if (vars[v] <> 0.0) then begin - v := GetVariationIndex(ifs[i]); - if (vars[v] <> 0.0) then + UsedVars.Add(vn); // AV: remember all used variations in the right order + if (LeftStr(vn, 4) = 'pre_') or (vn = 'flatten') then // AV: flatten became pre_ begin - vn := ifs[i]; - if (LeftStr(vn, 4) = 'pre_') or (vn = 'flatten') then // AV: flatten became pre_ + FCalcFunctionList[FNrFunctions] := FFunctionList[v]; + Inc(FNrFunctions); + end + // AV: added some universal variations + else if (vn = 'affine3D') or (vn = 'trianglecrop') or (vn = 'projective') + or (vn = 'spherecrop') then + begin + GetVariable(vn + '_mode', mode); + if (mode = 0) then begin FCalcFunctionList[FNrFunctions] := FFunctionList[v]; Inc(FNrFunctions); - end - // AV: added some universal variations - else if (vn = 'affine3D') or (vn = 'trianglecrop') - or (vn = 'projective') or (vn = 'spherecrop') then - begin - GetVariable(vn + '_mode', mode); - if (mode = 0) then - begin - FCalcFunctionList[FNrFunctions] := FFunctionList[v]; - Inc(FNrFunctions); - end; end; end; end; + end; // Precalc must be called after pre- vars if CalculateAngle or CalculateSinCos then @@ -386,53 +397,47 @@ begin end; // Normal variations - for i := 0 to NrVar - 1 do + for vn in UsedVars do // AV: iterate through used variations only begin - v := GetVariationIndex(ifs[i]); - if (vars[v] <> 0.0) then + if (LeftStr(vn, 4) = 'pre_') or (LeftStr(vn, 5) = 'post_') or (vn = 'flatten') + then continue + else if (vn = 'affine3D') or (vn = 'trianglecrop') or (vn = 'projective') + or (vn = 'spherecrop') then begin - vn := ifs[i]; - if (LeftStr(vn, 4) = 'pre_') or - (LeftStr(vn, 5) = 'post_') or - (vn = 'flatten') then continue; - if (vn = 'affine3D') or (vn = 'trianglecrop') - or (vn = 'projective') or (vn = 'spherecrop') then - begin - GetVariable(vn + '_mode', mode); - if (mode <> 1) then continue; - end; - - FCalcFunctionList[FNrFunctions] := FFunctionList[v]; - Inc(FNrFunctions); + GetVariable(vn + '_mode', mode); + if (mode <> 1) then continue; end; + + v := GetVariationIndex(vn); + FCalcFunctionList[FNrFunctions] := FFunctionList[v]; + Inc(FNrFunctions); end; // Post- variations - for i := 0 to NrVar - 1 do + for vn in UsedVars do // AV: iterate through used variations only begin - v := GetVariationIndex(ifs[i]); - if (vars[v] <> 0.0) then + if (LeftStr(vn, 5) = 'post_') then + begin + v := GetVariationIndex(vn); + FCalcFunctionList[FNrFunctions] := FFunctionList[v]; + Inc(FNrFunctions); + end + // AV: added some universal variations + else if (vn = 'affine3D') or (vn = 'trianglecrop') or (vn = 'projective') + or (vn = 'spherecrop') then + begin + GetVariable(vn + '_mode', mode); + if (mode = 2) then begin - vn := ifs[i]; - if (LeftStr(vn, 5) = 'post_') then - begin - FCalcFunctionList[FNrFunctions] := FFunctionList[v]; - Inc(FNrFunctions); - end - // AV: added some universal variations - else if (vn = 'affine3D') or (vn = 'trianglecrop') - or (vn = 'projective') or (vn = 'spherecrop') then - begin - GetVariable(ifs[i] + '_mode', mode); - if (mode = 2) then - begin - FCalcFunctionList[FNrFunctions] := FFunctionList[v]; - Inc(FNrFunctions); - end; - end; + v := GetVariationIndex(vn); + FCalcFunctionList[FNrFunctions] := FFunctionList[v]; + Inc(FNrFunctions); end; + end; end; + UsedVars.Free; + polar_vpi := vars[6]/pi; disc_vpi := vars[7]/pi; polar2_vpi := vars[35]/pi; @@ -624,7 +629,7 @@ end; procedure TXForm.Flatten; begin // FPz := 0; - // AV: changed to pre_mode + // AV: changed to pre_mode for compatibility with "3D-Hack" flames FTz := 0; end; @@ -1607,10 +1612,11 @@ begin ToPoint.c := ToPoint.c + pluginColor * (vc - ToPoint.c); ToPoint.x := FPx; ToPoint.y := FPy; - ToPoint.z := FPz; //? + ToPoint.z := FPz; end; /////////////////////////////////////////////////////////////////////////////// +(* procedure TXForm.NextPoint2C(var p: T2CPoint); var i: Integer; @@ -1631,7 +1637,7 @@ begin p.x := FPx; p.y := FPy; end; - +*) /////////////////////////////////////////////////////////////////////////////// procedure TXForm.NextPointXY(var px, py: double); var @@ -1651,6 +1657,75 @@ begin py := FPy; end; +//************ Math utils ***************************************// + +function TXForm.detC; +begin + Result := c[0,0] * c[1,1] - c[0,1] * c[1,0]; +end; + +function TXForm.detP; +begin + Result := p[0,0] * p[1,1] - p[0,1] * p[1,0]; +end; + +//************ Matrix multiplication ***************************************// + +procedure TXForm.Multiply(var t: TCoefsArray; const k, l, m, n: double); // AV +var + ta, tb, tc, td: double; +begin + ta := t[0, 0]; + tb := -t[1, 0]; + tc := -t[0, 1]; + td := t[1, 1]; + +{ + [a, b][e ,f] [a*e+b*g, a*f+b*h] + [ ][ ] = [ ] + [c, d][g, h] [c*e+d*g, c*f+d*h] +} + + t[0, 0] := ta * k + tc * l; + t[0, 1] := -(ta * m + tc * n); + t[1, 0] := -(tb * k + td * l); + t[1, 1] := tb * m + td * n; +end; + +procedure TXForm.Rotate(var t: TCoefsArray; const degrees: double); // AV +var + v, sv, cv: double; +begin + v := DegToRad(degrees); + SinCos(v, sv, cv); + Multiply(t, cv, -sv, sv, cv); +end; + +procedure TXForm.Scale(var t: TCoefsArray; const s: double); +begin + t[0, 0] := t[0, 0] * s; + t[0, 1] := t[0, 1] * s; + t[1, 0] := t[1, 0] * s; + t[1, 1] := t[1, 1] * s; +end; + +procedure TXForm.Translate(var t: TCoefsArray; const x, y: double); +begin + t[2,0] := t[2,0] + x; + t[2,1] := t[2,1] - y; // AV: notice the sign here +end; + +procedure TXForm.RandomizeCoefs(var t: TCoefsArray); // AV +begin + t[0][0] := 2 * random - 1; + t[0][1] := 2 * random - 1; + t[1][0] := 2 * random - 1; + t[1][1] := 2 * random - 1; + t[2][0] := 4 * random - 2; + t[2][1] := 4 * random - 2; +end; + +(* /////////////////////////////////////////////////////////////////////////////// { @@ -1676,7 +1751,6 @@ begin result[2, 2] := M1[2][0] * M2[0][2] + M1[2][1] * M2[1][2] + M1[2][2] * M2[2][2]; // AV: fixed indices end; -/////////////////////////////////////////////////////////////////////////////// function TXForm.Identity: TMatrix; var i, j: integer; @@ -1690,6 +1764,7 @@ begin end; /////////////////////////////////////////////////////////////////////////////// + procedure TXForm.Rotate(const degrees: double); var r: double; @@ -1718,7 +1793,6 @@ begin c[2, 1] := Matrix[1][2]; end; -/////////////////////////////////////////////////////////////////////////////// procedure TXForm.Translate(const x, y: double); var Matrix, M1: TMatrix; @@ -1743,7 +1817,6 @@ begin c[2, 1] := Matrix[1][2]; end; -/////////////////////////////////////////////////////////////////////////////// procedure TXForm.Multiply(const a, b, c, d: double); var Matrix, M1: TMatrix; @@ -1769,7 +1842,6 @@ begin Self.c[2, 1] := Matrix[1][2]; end; -/////////////////////////////////////////////////////////////////////////////// procedure TXForm.Scale(const s: double); var Matrix, M1: TMatrix; @@ -1792,7 +1864,7 @@ begin c[2, 0] := Matrix[0][2]; c[2, 1] := Matrix[1][2]; end; - +*) /////////////////////////////////////////////////////////////////////////////// destructor TXForm.Destroy; var @@ -1811,7 +1883,9 @@ end; /////////////////////////////////////////////////////////////////////////////// procedure TXForm.BuildFunctionlist; begin - SetLength(FFunctionList, NrVar + Length(FRegVariations)); + // AV: why NRVAR is used here? maybe NRLOCVAR instead? + //SetLength(FFunctionList, NrVar + Length(FRegVariations)); + SetLength(FFunctionList, NrVar); // <-- AV: reduced the length to actually used //fixed FFunctionList[0] := Linear3D; @@ -1835,7 +1909,7 @@ begin FFunctionList[18] := Blur3D; FFunctionList[19] := PreBlur; - FFunctionList[20] := PreZScale; // AV: index 20 is used by auto_pre_zscale option + FFunctionList[20] := PreZScale; // AV: index is used by auto-pre_zscale option FFunctionList[21] := PreZTranslate; FFunctionList[22] := PreRotateX; FFunctionList[23] := PreRotateY; @@ -1922,11 +1996,11 @@ begin result := Format(' 0 then result := result + format('symmetry="%g" ', [symmetry]); - ////// AV: write variation order + // AV: write variation order strvar := ''; - for i := 0 to nrvar - 1 do begin - if vars[GetVariationIndex(ifs[i])] <> 0 then - strvar := strvar + ifs[i] + #32; + for Name in ifs do begin + if vars[GetVariationIndex(Name)] <> 0 then + strvar := strvar + Name + #32; end; if (strvar <> '') and (pos(#32, strvar) < length(strvar)) then Result := Result + format('var_order="%s" ', [strvar]); @@ -1937,9 +2011,8 @@ begin Result := Result + varnames(i) + format('="%g" ', [vars[i]]); end; *) - for i := 0 to nrvar - 1 do // AV: write in correct order + for Name in ifs do // AV: write in correct order begin - Name := ifs[i]; Value := vars[GetVariationIndex(Name)]; if Value <> 0 then Result := Result + Name + format('="%g" ', [Value]); @@ -1993,11 +2066,11 @@ begin result := Format(' 0 then result := result + format('symmetry="%g" ', [symmetry]); - ////// AV: write variation order + // AV: write variation order strvar := ''; - for i := 0 to nrvar - 1 do begin - if vars[GetVariationIndex(ifs[i])] <> 0 then - strvar := strvar + ifs[i] + #32; + for Name in ifs do begin + if vars[GetVariationIndex(Name)] <> 0 then + strvar := strvar + Name + #32; end; if (strvar <> '') and (pos(#32, strvar) < length(strvar)) then Result := Result + format('var_order="%s" ', [strvar]); @@ -2008,9 +2081,8 @@ begin Result := Result + varnames(i) + format('="%g" ', [vars[i]]); end; *) - for i := 0 to nrvar - 1 do // AV: write in correct order + for Name in ifs do // AV: write in correct order begin - Name := ifs[i]; Value := vars[GetVariationIndex(Name)]; if Value <> 0 then Result := Result + Name + format('="%g" ', [Value]); diff --git a/Forms/About.dfm b/Forms/About.dfm index 2b00115..1814af3 100644 --- a/Forms/About.dfm +++ b/Forms/About.dfm @@ -5216,11 +5216,11 @@ object AboutForm: TAboutForm StyleElements = [seClient, seBorder] end object Label24: TLabel - Left = 24 + Left = 16 Top = 55 - Width = 100 + Width = 136 Height = 13 - Caption = 'Copyright '#169' 2021' + Caption = 'Copyright '#169' 2021- 2022' Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 @@ -5236,12 +5236,12 @@ object AboutForm: TAboutForm Shape = bsBottomLine end object lblAuthor: TLabel - Left = 145 + Left = 165 Top = 54 Width = 86 Height = 13 Cursor = crHandPoint - Hint = 'https://www.donationalerts.com/r/fract_alice' + Hint = 'https://www.youtube.com/channel/UCX-fyv7NmSg2OaprPvxLTlQ/featured' Caption = 'Alice V. Koryagina' Font.Charset = DEFAULT_CHARSET Font.Color = clBlack @@ -5341,7 +5341,7 @@ object AboutForm: TAboutForm Top = 50 Width = 57 Height = 16 - Caption = 'v 1.0.1.0' + Caption = 'v 1.0.2.0' Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -15 diff --git a/Forms/Adjust.dfm b/Forms/Adjust.dfm index 5cfa560..a00f1db 100644 --- a/Forms/Adjust.dfm +++ b/Forms/Adjust.dfm @@ -170,7 +170,7 @@ object AdjustForm: TAdjustForm Top = 181 Width = 451 Height = 155 - ActivePage = TabGradient + ActivePage = TabCamera Anchors = [akLeft, akRight, akBottom] Images = MainForm.Buttons TabOrder = 1 @@ -365,10 +365,23 @@ object AdjustForm: TAdjustForm TabOrder = 12 OnClick = btResetZoomClick end + object chkDisplay3DAxes: TCheckBox + Left = 128 + Top = 105 + Width = 310 + Height = 17 + Caption = 'Display 3D axes' + TabOrder = 13 + OnClick = chkDisplay3DAxesClick + end end object TabRendering: TTabSheet Caption = 'Rendering' ImageIndex = 35 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 DesignSize = ( 443 126) @@ -406,7 +419,7 @@ object AdjustForm: TAdjustForm Height = 15 Anchors = [akLeft, akTop, akRight] LargeChange = 10 - Max = 500 + Max = 1000 Min = 100 PageSize = 0 Position = 500 @@ -630,6 +643,10 @@ object AdjustForm: TAdjustForm object TabGradient: TTabSheet Caption = 'Gradient' ImageIndex = 11 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 DesignSize = ( 443 126) @@ -948,7 +965,7 @@ object AdjustForm: TAdjustForm Left = 115 Top = 83 Width = 210 - Height = 21 + Height = 20 BevelInner = bvLowered BevelOuter = bvRaised Style = csOwnerDrawFixed @@ -1128,10 +1145,14 @@ object AdjustForm: TAdjustForm object TabSize: TTabSheet Caption = 'Image Size' ImageIndex = 14 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object gbSize: TGroupBox Left = 1 Top = 5 - Width = 188 + Width = 189 Height = 105 Caption = 'Size in pixels' Font.Charset = DEFAULT_CHARSET @@ -1142,21 +1163,8 @@ object AdjustForm: TAdjustForm ParentFont = False TabOrder = 0 DesignSize = ( - 188 + 189 105) - object lblRatio: TLabel - Left = 5 - Top = 78 - Width = 56 - Height = 13 - Caption = 'Aspect ratio' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentFont = False - end object pnlWidth: TPanel Left = 4 Top = 19 @@ -1204,7 +1212,7 @@ object AdjustForm: TAdjustForm object txtHeight: TComboBox Left = 91 Top = 45 - Width = 78 + Width = 79 Height = 21 Anchors = [akLeft, akTop, akRight] Font.Charset = DEFAULT_CHARSET @@ -1230,7 +1238,7 @@ object AdjustForm: TAdjustForm object txtWidth: TComboBox Left = 91 Top = 19 - Width = 78 + Width = 79 Height = 21 Anchors = [akLeft, akTop, akRight] Font.Charset = DEFAULT_CHARSET @@ -1251,8 +1259,8 @@ object AdjustForm: TAdjustForm '1280') end object cbAspectRatio: TComboBox - Left = 70 - Top = 75 + Left = 74 + Top = 71 Width = 113 Height = 21 Style = csDropDownList @@ -1276,6 +1284,28 @@ object AdjustForm: TAdjustForm '16 : 10' '21 : 9 ') end + object lblRatio: TPanel + Left = 4 + Top = 71 + Width = 70 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Aspect ratio' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 5 + OnDblClick = DragPanelDblClick + OnMouseDown = DragPanelMouseDown + OnMouseMove = DragPanelMouseMove + OnMouseUp = DragPanelMouseUp + end end object gbPresets: TGroupBox Left = 194 @@ -1507,6 +1537,10 @@ object AdjustForm: TAdjustForm object TabCurves: TTabSheet Caption = 'Curves' ImageIndex = 69 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object CurvesPanel: TPanel Left = 3 Top = 1 @@ -1938,6 +1972,10 @@ object AdjustForm: TAdjustForm Caption = 'Save as Map file...' OnClick = SaveasMapfile1Click end + object SaveAsScript: TMenuItem + Caption = 'Save as Script file...' + OnClick = SaveAsScriptClick + end object N6: TMenuItem Caption = '-' end diff --git a/Forms/Adjust.pas b/Forms/Adjust.pas index 7608862..c457b47 100644 --- a/Forms/Adjust.pas +++ b/Forms/Adjust.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,19 +27,12 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ExtCtrls, ComCtrls, Buttons, Menus, AppEvnts, CurvesControl, + StdCtrls, ExtCtrls, ComCtrls, Buttons, Menus, CurvesControl, ControlPoint, Cmap, RenderingInterface, Translation; const WM_UPDATE_PARAMS = WM_APP + 5439; -const - PixelCountMax = 32768; - -type - pRGBTripleArray = ^TRGBTripleArray; - TRGBTripleArray = array[0..PixelCountMax - 1] of TRGBTriple; - type TAdjustForm = class(TForm) QualityPopup: TPopupMenu; @@ -190,7 +183,6 @@ type N13: TMenuItem; mnuLuminance: TMenuItem; cbAspectRatio: TComboBox; - lblRatio: TLabel; AdjustColorFragment: TMenuItem; N14: TMenuItem; mnuSepia: TMenuItem; @@ -207,12 +199,13 @@ type SmoothizeSelected: TMenuItem; btResetZoom: TButton; btnMenu: TButton; // AV: changed from TSpeedButton for auto-drawing the arrow + SaveAsScript: TMenuItem; + lblRatio: TPanel; + chkDisplay3DAxes: TCheckBox; // AV procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); procedure DrawPreview; -// procedure btnOKClick(Sender: TObject); -// procedure btnCancelClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure mnuLowQualityClick(Sender: TObject); procedure mnuMediumQualityClick(Sender: TObject); @@ -231,20 +224,6 @@ type procedure txtVibrancyExit(Sender: TObject); procedure scrollCameraScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); -(* - procedure scrollCenterXScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); - procedure scrollCenterYScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); - procedure scrollGammaScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); - procedure scrollBrightnessScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); - procedure scrollVibrancyScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); - procedure scrollAngleScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); -*) procedure scrollVibrancyScroll(Sender: TObject); procedure scrollGammaChange(Sender: TObject); procedure scrollBrightnessChange(Sender: TObject); @@ -398,6 +377,8 @@ type procedure txtContrastKeyPress(Sender: TObject; var Key: Char); procedure SmoothizeSelectedClick(Sender: TObject); procedure btResetZoomClick(Sender: TObject); + procedure SaveAsScriptClick(Sender: TObject); + procedure chkDisplay3DAxesClick(Sender: TObject); private CurvesControl: TCurvesControl; Resetting: boolean; @@ -472,8 +453,8 @@ procedure HSVToRGB(H, S, V: real; var Rb, Gb, Bb: integer); implementation uses - RndFlame, Main, cmapdata, Math, Browser, Editor, Global, - Save, Mutate, ClipBrd, GradientHlpr, Registry, Curves, ColorRangeForm; + RndFlame, Main, cmapdata, Math, Browser, Editor, Global, // Curves, + Save, Mutate, ClipBrd, GradientHlpr, Registry, ColorRangeForm; {$R *.DFM} @@ -494,8 +475,8 @@ begin tbWeightLeft.Position := Round(CurvesControl.WeightLeft * 10); tbWeightRight.Position := Round(CurvesControl.WeightRight * 10); - pw := PrevPnl.Width -2; - ph := PrevPnl.Height -2; + pw := PrevPnl.Width - 2; + ph := PrevPnl.Height - 2; if (cp.width / cp.height) > (PrevPnl.Width / PrevPnl.Height) then begin PreviewImage.Width := pw; @@ -572,7 +553,6 @@ begin if EditForm.Visible then EditForm.UpdateDisplay; if MutateForm.Visible then MutateForm.UpdateDisplay; - if CurvesForm.Visible then CurvesForm.SetCp(cp); if bBgOnly then MainForm.tbShowAlphaClick(Self) @@ -585,17 +565,97 @@ var i: integer; Row: pRGBTripleArray; BitMap: TBitMap; + +procedure Draw3DAxes; // AV +const + w = 60; // default axis length +var + Origin, EndPoint, Rot: TPoint; + sinPitch, cosPitch, sinRoll, cosRoll, sinYaw, cosYaw: double; + sinA, cosA: double; + DoRotate: boolean; +begin + SinCos(cp.cameraPitch, sinPitch, cosPitch); + SinCos(cp.cameraRoll, sinRoll, cosRoll); + SinCos(-cp.cameraYaw, sinYaw, cosYaw); + + if cp.FAngle <> 0 then + begin + SinCos(cp.FAngle, sinA, cosA); + DoRotate := True; + end + else + DoRotate := False; + + Origin.X := BM.Width shr 1; + Origin.Y := BM.Height shr 1; + + with BM.Canvas do + begin + Pen.Width := 2; + Font.Color := clBlack; // clWhite; + + // X - axis + Pen.Color := clRed; + Brush.Color := clRed; + EndPoint.X := Round(cosRoll * cosYaw * w); + EndPoint.Y := Round((sinPitch * sinRoll * cosYaw + cosPitch * sinYaw) * w); + if DoRotate then + begin + Rot.X := Round(EndPoint.X * cosA + EndPoint.Y * sinA); + Rot.Y := Round(-EndPoint.X * sinA + EndPoint.Y * cosA); + EndPoint := Rot; + end; + MoveTo(Origin.X, Origin.Y); + LineTo(Origin.X + EndPoint.X, Origin.Y + EndPoint.Y); + TextOut(PenPos.X - 2, PenPos.Y - 2, 'X'); + + // Y - axis + Pen.Color := clBlue; + Brush.Color := clBlue; + EndPoint.X := Round(-cosRoll * sinYaw * w); + EndPoint.Y := Round((-sinPitch * sinRoll * sinYaw + cosPitch * cosYaw) * w); + if DoRotate then + begin + Rot.X := Round(EndPoint.X * cosA + EndPoint.Y * sinA); + Rot.Y := Round(-EndPoint.X * sinA + EndPoint.Y * cosA); + EndPoint := Rot; + end; + MoveTo(Origin.X, Origin.Y); + LineTo(Origin.X + EndPoint.X, Origin.Y + EndPoint.Y); + TextOut(PenPos.X - 2, PenPos.Y - 2, 'Y'); + + // Z - axis + Pen.Color := clGreen; + Brush.Color := clGreen; + EndPoint.X := Round(sinRoll * w); + EndPoint.Y := Round(-sinPitch * cosRoll * w); + if DoRotate then + begin + Rot.X := Round(EndPoint.X * cosA + EndPoint.Y * sinA); + Rot.Y := Round(-EndPoint.X * sinA + EndPoint.Y * cosA); + EndPoint := Rot; + end; + MoveTo(Origin.X, Origin.Y); + LineTo(Origin.X + EndPoint.X, Origin.Y + EndPoint.Y); + TextOut(PenPos.X - 2, PenPos.Y - 2, 'Z'); + end; +end; + begin if Resetting then exit; Render.Stop; -// AdjustScale(cp, PreviewImage.Width, PreviewImage.Height); + cp.sample_density := PreviewDensity; cp.spatial_oversample := defOversample; cp.spatial_filter_radius := defFilterRadius; Render.SetCP(cp); Render.Render; BM.Assign(Render.GetImage); + + if chkDisplay3DAxes.Checked then Draw3DAxes; // AV + PreviewImage.Picture.Graphic := bm; if mnuInstantPreview.Checked then PreviewImage.Refresh; @@ -678,9 +738,9 @@ begin pnlYPos.Caption := TextByKey('adjustment-tab-camera-ypos'); pnlAngle.Caption := TextByKey('adjustment-tab-camera-rotation'); btResetZoom.Caption := TextByKey('adjustment-tab-camera-resetzoom'); + chkDisplay3DAxes.Caption := TextByKey('adjustment-tab-camera-draw3daxes'); btResetZoom.Hint := TextByKey('adjustment-hint-resetzoom'); TabRendering.Caption := TextByKey('adjustment-tab-rendering-title'); - //chkTransparent.Caption := TextByKey('adjustment-tab-rendering-istransparent'); TabGradient.Caption := TextByKey('adjustment-tab-gradient-title'); mnuRotate.Caption := TextByKey('adjustment-tab-gradient-moderotate'); mnuHue.Caption := TextByKey('adjustment-tab-gradient-modehue'); @@ -723,6 +783,7 @@ begin SaveGradient1.Caption := TextByKey('adjustment-popup-gradient-saveasugr'); SaveasMapfile1.Caption := TextByKey('adjustment-popup-gradient-saveasmap'); mnuSaveAsDefault.Caption := TextByKey('adjustment-popup-gradient-saveasdefault'); + SaveAsScript.Caption := TextByKey('adjustment-popup-gradient-saveasscript'); btnMenu.Caption := TextByKey('adjustment-tab-gradient-moderotate'); Red1.Caption := TextByKey('adjustment-tab-curves-red'); Green1.Caption := TextByKey('adjustment-tab-curves-green'); @@ -806,6 +867,7 @@ begin Registry.WriteInteger('Left', AdjustForm.Left); Registry.WriteBool('InstantPreview', mnuInstantPreview.Checked); Registry.WriteBool('ResizeMain', chkResizeMain.Checked); + Registry.WriteBool('Display3DAxes', chkDisplay3DAxes.Checked); // AV end; finally Registry.Free; @@ -841,12 +903,14 @@ begin mnuInstantPreview.Checked := Registry.ReadBool('InstantPreview'); if Registry.ValueExists('ResizeMain') then chkResizeMain.Checked := Registry.ReadBool('ResizeMain'); + if Registry.ValueExists('Display3DAxes') then // AV + chkDisplay3DAxes.Checked := Registry.ReadBool('Display3DAxes'); Registry.CloseKey; end; if Registry.OpenKey('Software\' + APP_NAME + '\ImageSizePresets', False) then begin - for i:=1 to 3 do begin + for i := 1 to 3 do begin strx:='Preset' + IntToStr(i) + 'Left'; stry:='Preset' + IntToStr(i) + 'Top'; strw:='Preset' + IntToStr(i) + 'Width'; @@ -861,9 +925,7 @@ begin end; Preset[i].Left := MainForm.Left; Preset[i].Top := MainForm.Top; - // Preset[i].Width := 512; - // Preset[i].Height := 384; - // AV: them different by default + // AV: make them different by default case i of 1: begin Preset[1].Width := 512; @@ -881,7 +943,7 @@ begin end; end else begin - for i:=1 to 3 do begin + for i := 1 to 3 do begin Preset[i].Left := MainForm.Left; Preset[i].Top := MainForm.Top; end; @@ -943,6 +1005,11 @@ begin DrawPreview; end; +procedure TAdjustForm.chkDisplay3DAxesClick(Sender: TObject); // AV +begin + DrawPreview; // show or hide coordinate axes +end; + procedure TAdjustForm.txtZoomEnter(Sender: TObject); begin EditBoxValue := txtZoom.Text; @@ -1183,38 +1250,6 @@ begin if ScrollCode = scEndScroll then UpdateFlame; end; -(* -procedure TAdjustForm.scrollCenterXScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then UpdateFlame; -end; - -procedure TAdjustForm.scrollCenterYScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then UpdateFlame; -end; - -procedure TAdjustForm.scrollGammaScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then UpdateFlame; -end; - -procedure TAdjustForm.scrollBrightnessScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then UpdateFlame; -end; - -procedure TAdjustForm.scrollVibrancyScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then UpdateFlame; -end; - *) - procedure TAdjustForm.scrollVibrancyScroll(Sender: TObject); begin cp.Vibrancy := ScrollVibrancy.Position / 100; @@ -1381,7 +1416,6 @@ begin if EditForm.visible then EditForm.UpdateDisplay; if MutateForm.Visible then MutateForm.UpdateDisplay; - if CurvesForm.Visible then CurvesForm.SetCp(MainCp); if mnuInstantPreview.Checked then DrawPreview; @@ -1413,7 +1447,8 @@ begin end; CloseFile(MapFile); except - on EInOutError do Application.MessageBox(PChar(Format(TextByKey('common-genericopenerror'), [FileName])), 'Apophysis', 16); + on EInOutError do + raise Exception.CreateFmt(TextByKey('common-genericopenerror'), [FileName]); // AV end; end; @@ -2048,6 +2083,42 @@ begin SaveMap(SaveDialog.Filename); end; +procedure TAdjustForm.SaveAsScriptClick(Sender: TObject); +var + gradstr: TStringList; + fn, s: string; + i: word; +begin + SaveDialog.InitialDir := AppPath + 'Scripts'; + SaveDialog.FileName := 'Palette_' + IntToStr(cmbPalette.ItemIndex) + '.asc'; + SaveDialog.DefaultExt := 'asc'; + SaveDialog.Filter := Format('%s|*.aposcript;*.asc|%s|*.*', + [TextByKey('common-filter-scriptfiles'), + TextByKey('common-filter-allfiles')]); + if SaveDialog.Execute then + begin + fn := SaveDialog.FileName; + gradstr := TStringList.Create; + try + gradstr.Add('procedure SetCustomPalette;'); + gradstr.Add('begin'); + gradstr.Add(' with Flame do begin'); + for i := 0 to 255 do + gradstr.Add(Format(' Gradient[%d,0] := %d; Gradient[%0:d,1] := %2:d; Gradient[%0:d,2] := %3:d;', + [i, Palette[i][0], palette[i][1], palette[i][2]])); + gradstr.Add(' end;'); + gradstr.Add('end;'); + s := ExtractFileName(fn); + for i := 1 to Length(s) do + if CharInSet(s[i], [#32, '-', '(', ')']) then s[i] := '_'; + gradstr.SaveToFile(ExtractFilePath(fn) + s); + MainForm.GetScripts; + finally + gradstr.Free; + end; + end; +end; + procedure TAdjustForm.cmbPaletteDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); var @@ -2190,7 +2261,7 @@ begin end; procedure TAdjustForm.mnuSepiaClick(Sender: TObject); -var i, sep: integer; +var i, sep: smallint; begin for i := 0 to 255 do begin @@ -2205,7 +2276,7 @@ end; procedure TAdjustForm.mnuSetColorClick(Sender: TObject); var - i: integer; + i: smallint; col: Longint; begin ColorDialog.Color := RGB(Palette[selA,0], Palette[selA,1], Palette[selA,2]); @@ -2278,8 +2349,8 @@ procedure TAdjustForm.GradImageMouseMove(Sender: TObject; begin j := j0 + round((i - i0) * k); -assert(j >= 0); -assert(j < 256); + assert(j >= 0); + assert(j < 256); cp.cmap[i] := Palette[j]; BackupPal[i] := tmpBackupPal[j]; //? @@ -2292,8 +2363,8 @@ assert(j < 256); j := j0 + trunc(f); f := frac(f); -assert(j >= 0); -assert(j < 256); + assert(j >= 0); + assert(j < 256); if j < 255 then jj := j + 1 else jj := 0; @@ -2344,8 +2415,8 @@ begin if (selB < 0) then selB := 0 else if (selB > 255) then selB := 255; if (selB - selA > 1) then begin - //btnSelected.Visible := True; - AdjustSelected.Checked := True; + //btnSelected.Visible := True; + AdjustSelected.Checked := True; end; GradStatusBar.Panels[2].Text := TextByKey('adjustment-tab-gradient-start') + space + IntToStr(selA); GradStatusBar.Panels[4].Text := TextByKey('adjustment-tab-gradient-last') + space + IntToStr(selB); @@ -2417,7 +2488,7 @@ begin end; end; -// AV: operations with selected color fragments +//*************** AV: operations with selected color fragments **********// procedure TAdjustForm.InvertColorsClick(Sender: TObject); var @@ -2460,19 +2531,20 @@ begin end; procedure TAdjustForm.Pastefragment1Click(Sender: TObject); -var i, j, l: integer; +var i, j, l: smallint; begin l := High(tmpColors); l := Min(selA + l, selB); for i := selA to l do - for j := 0 to 2 do Palette[i][j] := tmpColors[i - selA][j]; + for j := 0 to 2 do + Palette[i][j] := tmpColors[i - selA][j]; UpdateGradient(palette); Apply; end; procedure TAdjustForm.ReverseFragmentClick(Sender: TObject); var - i, j: integer; + i, j: byte; pal: array of array of byte; begin SetLength(pal, selB - selA + 1, 3); @@ -2490,11 +2562,11 @@ end; function TAdjustForm.PresetToStr(n: integer): string; begin - Result:=IntToStr(Preset[n].Width) + ' x ' + IntToStr(Preset[n].Height) + Result := IntToStr(Preset[n].Width) + ' x ' + IntToStr(Preset[n].Height) end; procedure TAdjustForm.RandomizeSelectedClick(Sender: TObject); -var i, j: integer; +var i, j: byte; tempPal: TColorMap; begin tempPal := GradientHelper.RandomGradient; @@ -2513,8 +2585,8 @@ begin txtHeight.Text := IntToStr(ImageHeight); if chkResizeMain.Checked then begin - MainForm.Left:=Preset[n].Left; - MainForm.Top:=Preset[n].Top; + MainForm.Left := Preset[n].Left; + MainForm.Top := Preset[n].Top; end; SetMainWindowSize; @@ -2542,7 +2614,6 @@ begin if EditForm.Visible then EditForm.UpdateDisplay; if MutateForm.Visible then MutateForm.UpdateDisplay; - if CurvesForm.Visible then CurvesForm.SetCp(cp); MainForm.RedrawTimer.enabled := true; { if ScrollCode = scEndScroll then @@ -2595,7 +2666,7 @@ begin if (s[1] = '-') then start := 2; - for i:=start to length(s) do + for i := start to length(s) do if not (CharInSet(s[i],['0'..'9'])) then begin Result := False; @@ -2639,10 +2710,12 @@ begin end; end; -//procedure TAdjustForm.chkMaintainClick(Sender: TObject); -//begin -// Ratio := ImageWidth / ImageHeight; -//end; +{ +procedure TAdjustForm.chkMaintainClick(Sender: TObject); +begin + Ratio := ImageWidth / ImageHeight; +end; +} procedure TAdjustForm.SetMainWindowSize; var diff --git a/Forms/Animate.dfm b/Forms/Animate.dfm new file mode 100644 index 0000000..de8da0d --- /dev/null +++ b/Forms/Animate.dfm @@ -0,0 +1,981 @@ +object AnimateForm: TAnimateForm + Left = 0 + Top = 0 + BorderStyle = bsSingle + Caption = 'Animate Flame' + ClientHeight = 476 + ClientWidth = 496 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Icon.Data = { + 0000010001001010000000000000680400001600000028000000100000002000 + 000001002000000000000004000000000000000000000000000000000000FFFF + FF00FFFFFF00FFFFFF00FFFFFF00113D55F7285F87FB4988BDFB428DBCC12D77 + B322FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002E2E + 2ED8292929FA242424CCFFFFFF002B6583FB94C7F9FF91C9F9FF4185C9FF1C64 + AAF310202DE0050505FF020202DCFFFFFF00FFFFFF00FFFFFF00FFFFFF003434 + 34FA2F2F2F61353535FF575757FF4389AAFFE0F2FFFF549AD8FF1A7ABEFF4998 + C5FF3177B0FF1B3C5A6D050505EFFFFFFF00FFFFFF00FFFFFF00FFFFFF003A3A + 3AFF353535C6303030F56EDF9DFE54B2A0FE7AB6D5FF90B7D1FF55C9E4FF5BDF + F5FF78D0EDFF3E8DCFF70F1B25FFFFFFFF00FFFFFF00FFFFFF00FFFFFF004040 + 40D03B3B3B6C363636D54FCB5CFF57D77AFF35B883FF73B8D3FFC2F6FDFF63DF + F7FF5DE2F8FF79D3F0FF4291D5FD388CD820FFFFFF00FFFFFF00FFFFFF004545 + 45DF404040C33B3B3BD04FC445FF4BBA2CFFD8BD60FFB1A87FFF77CBE7FFC7F7 + FDFF5EDCF5FF5AE1F7FF7BD4F1FF4295DCF2368CD934FFFFFF00FFFFFF004B4B + 4BDA464646A2414141CF7FBF36FFDDC569FFFFC270FFFFBF67FF86C3BAFF79D3 + EEFFC7F7FDFF5FDCF5FF5BE2F7FF7AD6F2FF4099DFE8448DCD30FFFFFF005151 + 51D44C4C4C81474747CCF8C66EFFFFC877FFFFC572FFFFC46CFF98D8CFFF78D7 + E9FF7BD3ECFFC4F6FDFF6CDDF6FF6DCAEDFF63A3D7FF5D9BD2EC5192CA265656 + 56E2515151D0686868FF575757FF575757FF575757FF575757FF575757FF5757 + 57FF275969F97CD2EAFEB2E3F9FF8BC0E7FFAED3F6FFC4E0FCFF669FD3F75B5B + 5BD457575781525252CD72E29EFF7CE3A4FF78E3A0FF63E095FF5AE195FF55E2 + 93FF303030D026748BAD77BEE7FFB4D2F0FFE5F3FFFFACD2EFFF488CC7E86060 + 60DA5C5C5CA2575757CF4FCB5CFF57D77AFF42D16AFF70C75EFFB6B850FFCBAE + 3FFF363636D0313131A22E5C6CE658A5D8FF85B1DBFF469DD0FF2B95D15E6464 + 64DF606060C35C5C5CD04FC445FF4BBA2CFFD8BD60FFFFBA62FFFFB965FFDBBB + 7DFF3B3B3BD2363636C3313131DFFFFFFF00FFFFFF00FFFFFF00FFFFFF006868 + 68D165656584616161D47FBF36FFDDC569FFFFC270FFFFBF67FFAECBACFF68E0 + F9FF414141D63C3C3C6C373737D0FFFFFF00FFFFFF00FFFFFF00FFFFFF006C6C + 6CFF696969ED656565FAE5BA6CF6ECBC74F6EBB86EF6EBB668F680CBCDF680D7 + EAF6474747FA424242CC3D3D3DFFFFFFFF00FFFFFF00FFFFFF00FFFFFF006F6F + 6FF86C6C6C9B696969FF575757FF575757FF575757FF575757FF575757FF5757 + 57FF4D4D4DFF4848488D434343D5FFFFFF00FFFFFF00FFFFFF00FFFFFF007171 + 71D46F6F6FF36D6D6DDDFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00525252D64D4D4DF9494949D7FFFFFF00FFFFFF00FFFFFF00FFFFFF00F0FF + 0000100F0000402F0000000F0000400F00000007000000030000000100000000 + 00000000000000010000000F0000002F0000000F0000000F00001F8F0000} + OldCreateOrder = False + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + DesignSize = ( + 496 + 476) + PixelsPerInch = 96 + TextHeight = 13 + object btSaveAnimation: TButton + Left = 304 + Top = 427 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Save' + ParentShowHint = False + ShowHint = True + TabOrder = 0 + OnClick = btSaveAnimationClick + end + object AnimPages: TPageControl + Left = 8 + Top = 8 + Width = 480 + Height = 412 + ActivePage = tsSettings + Anchors = [akLeft, akTop, akRight, akBottom] + TabOrder = 1 + object tsSettings: TTabSheet + Caption = 'General' + object gbOutput: TGroupBox + Left = 5 + Top = 5 + Width = 450 + Height = 125 + Caption = ' Output settings ' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 0 + object btSetFlame: TSpeedButton + Left = 420 + Top = 24 + Width = 24 + Height = 24 + Hint = 'Browse...' + Flat = True + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Font.Style = [fsBold] + Glyph.Data = { + 36030000424D3603000000000000360000002800000010000000100000000100 + 18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF75848F66808F + 607987576E7B4E626F4456613948522E3A43252E351B222914191E0E12160E13 + 18FF00FFFF00FFFF00FF77879289A1AB6AB2D4008FCD008FCD008FCD048CC708 + 88BE0F82B4157CA91B779F1F7296224B5C87A2ABFF00FFFF00FF7A8A957EBED3 + 8AA4AE7EDCFF5FCFFF55CBFF4CC4FA41BCF537B3F02EAAEB24A0E5138CD42367 + 805E696DFF00FFFF00FF7D8E9879D2EC8BA4AD89C2CE71D8FF65D3FF5CCEFF51 + C9FE49C1FA3FB9F534B0EE29A8E91085CD224B5B98B2BAFF00FF80919C81D7EF + 7DC5E08CA6B080DDFE68D3FF67D4FF62D1FF58CDFF4EC7FC46BEF73BB6F231AC + EC2569817A95A1FF00FF83959F89DCF18CE2FF8DA8B18CBAC774D8FF67D4FF67 + D4FF67D4FF5FD0FF54CDFF4BC5FC41BBF72EA2DB51677498B2BA869AA392E1F2 + 98E8FD80C4DE8EA7B081DEFD84E0FF84E0FF84E0FF84E0FF81DFFF7BDDFF74D8 + FF6BD6FF56A9D18F9BA4889CA59AE6F39FEBFB98E8FE8BACB98BACB98AAAB788 + A6B386A3AF839FAA819AA67F95A17C919D7A8E99798B957788938BA0A8A0EAF6 + A6EEF99FEBFB98E8FE7ADAFF67D4FF67D4FF67D4FF67D4FF67D4FF67D4FF7788 + 93FF00FFFF00FFFF00FF8EA2ABA7EEF6ABF0F7A6EEF99FEBFB98E8FD71D4FB89 + 9EA78699A382949F7E909A7A8C97778893FF00FFFF00FFFF00FF8FA4ACA0D2DA + ABF0F7ABF0F7A6EEF99FEBFB8DA1AAB5CBD0FF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFBDCED48FA4AC8FA4AC8FA4AC8FA4AC8FA4ACB5CBD0FF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} + ParentFont = False + ParentShowHint = False + ShowHint = True + OnClick = btSetFlameClick + end + object lbSeconds: TLabel + Left = 390 + Top = 56 + Width = 39 + Height = 13 + Caption = 'seconds' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + end + object pnlFPS: TPanel + Left = 8 + Top = 52 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Frames per second' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + end + object pnlDuration: TPanel + Left = 200 + Top = 52 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Duration' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + end + object seDuration: TSpinEdit + Left = 321 + Top = 52 + Width = 65 + Height = 22 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 100 + MinValue = 1 + ParentFont = False + TabOrder = 2 + Value = 1 + end + object seFPS: TSpinEdit + Left = 129 + Top = 52 + Width = 65 + Height = 22 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 200 + MinValue = 2 + ParentFont = False + TabOrder = 3 + Value = 25 + end + object pnlOutFlame: TPanel + Left = 8 + Top = 24 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Output flame file' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 4 + end + object edOutFlame: TEdit + Left = 127 + Top = 24 + Width = 290 + Height = 21 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 5 + end + object chkListFlames: TCheckBox + Left = 8 + Top = 80 + Width = 378 + Height = 17 + Caption = 'Show generated flames' + Checked = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + State = cbChecked + TabOrder = 6 + end + object chkRender: TCheckBox + Left = 8 + Top = 100 + Width = 378 + Height = 17 + Caption = 'Render all frames' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 7 + OnClick = chkRenderClick + end + end + object gbFrame: TGroupBox + Left = 5 + Top = 142 + Width = 450 + Height = 221 + Caption = 'Frame' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 1 + object pnlFrameWidth: TPanel + Left = 8 + Top = 24 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Width' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + end + object pnlFrameHeight: TPanel + Left = 200 + Top = 24 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Height' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + end + object seFrameHeight: TSpinEdit + Left = 321 + Top = 24 + Width = 65 + Height = 22 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 10000 + MinValue = 1 + ParentFont = False + TabOrder = 2 + Value = 600 + OnChange = seFrameHeightChange + end + object seFrameWidth: TSpinEdit + Left = 129 + Top = 24 + Width = 65 + Height = 22 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 10000 + MinValue = 1 + ParentFont = False + TabOrder = 3 + Value = 800 + OnChange = seFrameWidthChange + end + object cbAspectRatio: TComboBox + Left = 129 + Top = 52 + Width = 160 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 1 + ParentFont = False + TabOrder = 4 + Text = 'Maintain aspect ratio' + OnChange = cbAspectRatioChange + Items.Strings = ( + 'Custom' + 'Maintain aspect ratio' + '3 : 2 (Classic Film)' + '4 : 3 (Standart Monitor)' + '5 : 4 ' + '16 : 9 (HD Video)' + '16 : 10' + '21 : 9 (CinemaScope)') + end + object pnlRatio: TPanel + Left = 8 + Top = 52 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Aspect ratio' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 5 + end + object pnlPrefix: TPanel + Left = 8 + Top = 80 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Frame prefix' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 6 + end + object edPrefix: TEdit + Left = 129 + Top = 80 + Width = 65 + Height = 21 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 7 + Text = 'anim-' + end + object pnlFrameExt: TPanel + Left = 200 + Top = 80 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Graphic extension' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 8 + end + object cbFrameExt: TComboBox + Left = 321 + Top = 80 + Width = 65 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 1 + ParentFont = False + TabOrder = 9 + Text = '.png' + OnChange = cbAspectRatioChange + Items.Strings = ( + '.bmp' + '.png' + '.jpg') + end + object gbFrameQuality: TGroupBox + Left = 8 + Top = 112 + Width = 200 + Height = 97 + Caption = 'Quality settings' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 10 + object pnlDensity: TPanel + Left = 8 + Top = 20 + Width = 121 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Density' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + TabOrder = 2 + end + object pnlFilter: TPanel + Left = 8 + Top = 44 + Width = 121 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Filter radius' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + TabOrder = 3 + end + object pnlOversample: TPanel + Left = 8 + Top = 68 + Width = 121 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Oversample' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + TabOrder = 4 + end + object txtDensity: TComboBox + Left = 128 + Top = 20 + Width = 65 + Height = 21 + AutoComplete = False + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + TabOrder = 0 + Text = '200' + Items.Strings = ( + '200' + '500' + '1000' + '2000' + '4000') + end + object txtFilterRadius: TEdit + Left = 128 + Top = 44 + Width = 65 + Height = 21 + BiDiMode = bdLeftToRight + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentBiDiMode = False + ParentFont = False + TabOrder = 1 + Text = '0.1' + end + object sbFilterRadius: TSpinButton + Left = 175 + Top = 45 + Width = 15 + Height = 17 + DownGlyph.Data = { + 0E010000424D0E01000000000000360000002800000009000000060000000100 + 200000000000D800000000000000000000000000000000000000008080000080 + 8000008080000080800000808000008080000080800000808000008080000080 + 8000008080000080800000808000000000000080800000808000008080000080 + 8000008080000080800000808000000000000000000000000000008080000080 + 8000008080000080800000808000000000000000000000000000000000000000 + 0000008080000080800000808000000000000000000000000000000000000000 + 0000000000000000000000808000008080000080800000808000008080000080 + 800000808000008080000080800000808000} + FocusControl = txtFilterRadius + TabOrder = 5 + UpGlyph.Data = { + 0E010000424D0E01000000000000360000002800000009000000060000000100 + 200000000000D800000000000000000000000000000000000000008080000080 + 8000008080000080800000808000008080000080800000808000008080000080 + 8000000000000000000000000000000000000000000000000000000000000080 + 8000008080000080800000000000000000000000000000000000000000000080 + 8000008080000080800000808000008080000000000000000000000000000080 + 8000008080000080800000808000008080000080800000808000000000000080 + 8000008080000080800000808000008080000080800000808000008080000080 + 800000808000008080000080800000808000} + OnDownClick = sbFilterRadiusDownClick + OnUpClick = sbFilterRadiusUpClick + end + object seOversample: TSpinEdit + Left = 128 + Top = 68 + Width = 65 + Height = 22 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 4 + MinValue = 1 + ParentFont = False + ReadOnly = True + TabOrder = 6 + Value = 2 + end + end + end + end + object tsAnimation: TTabSheet + Caption = 'Animation' + ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 380 + object gbAnimType: TGroupBox + Left = 3 + Top = 4 + Width = 450 + Height = 155 + Caption = ' Animation parameters' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 0 + object cbAnimType: TComboBox + Left = 129 + Top = 24 + Width = 310 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 0 + ParentFont = False + TabOrder = 0 + Text = 'Rotate flame' + OnChange = cbAnimTypeChange + Items.Strings = ( + 'Rotate flame' + 'Rotate reference triangle' + 'Rotate 3D camera' + 'Rotate color gradient' + 'Change gradient hue' + 'Morphing (cosine, RGB)' + 'Morphing (cosine, HSV)' + 'Morphing (linear, RGB)' + 'Morphing (linear, HSV)') + end + object pnlAnimType: TPanel + Left = 8 + Top = 24 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Animation type' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + end + object pnlStartFlame: TPanel + Left = 8 + Top = 52 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Initial flame' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + end + object cbFlames: TComboBox + Left = 129 + Top = 52 + Width = 310 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 0 + ParentFont = False + TabOrder = 3 + Text = 'Current' + OnChange = cbFlamesChange + Items.Strings = ( + 'Current') + end + object pnlEndFlame: TPanel + Left = 8 + Top = 80 + Width = 121 + Height = 21 + BevelOuter = bvLowered + Caption = 'Final flame' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 4 + end + object cbFlamesTo: TComboBox + Left = 129 + Top = 80 + Width = 310 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 0 + ParentFont = False + TabOrder = 5 + Text = 'Current' + OnChange = cbFlamesChange + Items.Strings = ( + 'Current') + end + object chkResetLocation: TCheckBox + Left = 8 + Top = 110 + Width = 378 + Height = 17 + Caption = 'Reset location for each frame' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 6 + end + object chkInvertBG: TCheckBox + Left = 8 + Top = 130 + Width = 378 + Height = 17 + Caption = 'Invert background color' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 7 + end + end + object gbPreview: TGroupBox + Left = 5 + Top = 160 + Width = 450 + Height = 220 + Caption = 'Preview' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 1 + object tbPlay: TSpeedButton + Left = 50 + Top = 189 + Width = 75 + Height = 22 + Hint = 'Play' + Caption = 'Play' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Glyph.Data = { + 36060000424D3606000000000000360000002800000020000000100000000100 + 18000000000000060000120B0000120B00000000000000000000FF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFDEEAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFDEEAE0FF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF096314DEEAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9FF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF11681B04600FDEEAE0FF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9DE + EAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF1A6F2420732C04600FDEEAE0FF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9DEEAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF23752E2F833D20732C04600FDEEAE0FF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9D6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF2E7C3750A25A2F833D20732C04600FDEEAE0FF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9D6EDD9DEEAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF3883415DB06850A25A2F833D20732C0B6618DEEAE0FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9D6EDD9D6EDD9DEEAE0FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF438A4C6BBF766BBF7650A25A2F7639D6EDD9FF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9D6EDD9D6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF4B90536BBF76A3DAB02F7639D6EDD9FF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9D6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF52945AA3DAB02F7639D6EDD9FF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9D6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF5898602F7639D6EDD9FF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9D6 + EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FF589860D6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9D6EDD9FF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFD6EDD9FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFD6EDD9FF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} + NumGlyphs = 2 + ParentFont = False + ParentShowHint = False + ShowHint = True + OnClick = tbPlayClick + end + object tbStop: TSpeedButton + Left = 140 + Top = 189 + Width = 75 + Height = 22 + Hint = 'Stop' + Caption = 'Stop' + Enabled = False + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Glyph.Data = { + 36060000424D3606000000000000360000002800000020000000100000000100 + 18000000000000060000120B0000120B00000000000000000000FF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFE39A75B66239B05C33A7532A9D4820923E1689340D822D06812C05FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFE39770F3BCA0D7A183CE8D6DC17C59AF6B48A762409B5837812C05FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFE79B74F9C9AFF5B594EDA37EE6956CDA8559CE794EAC6543853009FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFEA9E78F9D0BBF8BDA1F4B090EF9F79E69268DC8459B46B488B360FFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFEFA37DFBD7C8F8C7ADF7B798F2AB88ED9F7AE6946DBE7755923E16FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFF3A881FBE1D3F9CEBAF8BFA5F3B394F2A885EB9F7AD08D6C9A461EFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFF6AD86FBE5DAFBDACAF9CAB3F8C2A8F6B698F3B391DCA387A24E25FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFAB08AFCE1D5FBE2D4FAD8C6F9CDB9F9CAB3F9C6ACF5BB9DAA552DFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFDB38DFAB08AF6AD86F3A881EFA37DEA9E78E79B74E39770E39A75FF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFF9C6ACF9C6ACF9C6ACF9C6ACF9 + C6ACF9C6ACF9C6ACF9C6ACF9C6ACFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} + NumGlyphs = 2 + ParentFont = False + ParentShowHint = False + ShowHint = True + OnClick = tbStopClick + end + object pnlPreview: TPanel + Left = 16 + Top = 24 + Width = 240 + Height = 160 + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + object AnimPreview: TImage + Left = 0 + Top = 0 + Width = 240 + Height = 160 + PopupMenu = QualityPopup + end + end + end + end + end + object AnimStatus: TStatusBar + Left = 0 + Top = 457 + Width = 496 + Height = 19 + Panels = <> + SimplePanel = True + end + object btClose: TButton + Left = 399 + Top = 427 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Close' + TabOrder = 3 + OnClick = btCloseClick + end + object QualityPopup: TPopupMenu + Images = MainForm.Buttons + Left = 24 + Top = 416 + object mnuLowQuality: TMenuItem + Caption = 'Low Quality' + RadioItem = True + OnClick = mnuPreviewQualityClick + end + object mnuMediumQuality: TMenuItem + Tag = 1 + Caption = 'Medium Quality' + Checked = True + RadioItem = True + OnClick = mnuPreviewQualityClick + end + object mnuHighQuality: TMenuItem + Tag = 2 + Caption = 'High Quality' + RadioItem = True + OnClick = mnuPreviewQualityClick + end + end +end diff --git a/Forms/Animate.pas b/Forms/Animate.pas new file mode 100644 index 0000000..70f3ef1 --- /dev/null +++ b/Forms/Animate.pas @@ -0,0 +1,831 @@ +{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } + +unit Animate; + +interface + +uses + Windows, Messages, SysUtils, Classes, Graphics, StdCtrls, ComCtrls, ExtCtrls, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Samples.Spin, Vcl.Buttons, + Menus, ControlPoint, RenderingInterface, Translation; + +type + TAnimateForm = class(TForm) + seFPS: TSpinEdit; + seDuration: TSpinEdit; + edOutFlame: TEdit; + btSetFlame: TSpeedButton; + gbOutput: TGroupBox; + pnlFPS: TPanel; + pnlDuration: TPanel; + pnlOutFlame: TPanel; + btSaveAnimation: TButton; + pnlFrameWidth: TPanel; + pnlFrameHeight: TPanel; + seFrameWidth: TSpinEdit; + seFrameHeight: TSpinEdit; + pnlPrefix: TPanel; + edPrefix: TEdit; + cbAspectRatio: TComboBox; + pnlRatio: TPanel; + AnimPages: TPageControl; + tsSettings: TTabSheet; + chkListFlames: TCheckBox; + AnimStatus: TStatusBar; + gbFrame: TGroupBox; + tsAnimation: TTabSheet; + gbAnimType: TGroupBox; + cbAnimType: TComboBox; + pnlAnimType: TPanel; + pnlStartFlame: TPanel; + cbFlames: TComboBox; + pnlEndFlame: TPanel; + cbFlamesTo: TComboBox; + gbPreview: TGroupBox; + AnimPreview: TImage; + btClose: TButton; + chkResetLocation: TCheckBox; + chkRender: TCheckBox; + QualityPopup: TPopupMenu; + mnuLowQuality: TMenuItem; + mnuMediumQuality: TMenuItem; + mnuHighQuality: TMenuItem; + pnlFrameExt: TPanel; + cbFrameExt: TComboBox; + gbFrameQuality: TGroupBox; + pnlDensity: TPanel; + pnlFilter: TPanel; + pnlOversample: TPanel; + txtDensity: TComboBox; + txtFilterRadius: TEdit; + sbFilterRadius: TSpinButton; + seOversample: TSpinEdit; + lbSeconds: TLabel; + pnlPreview: TPanel; + tbPlay: TSpeedButton; + tbStop: TSpeedButton; + chkInvertBG: TCheckBox; + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure btSaveAnimationClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btSetFlameClick(Sender: TObject); + procedure cbAspectRatioChange(Sender: TObject); + procedure seFrameWidthChange(Sender: TObject); + procedure seFrameHeightChange(Sender: TObject); + procedure cbFlamesChange(Sender: TObject); + procedure cbAnimTypeChange(Sender: TObject); + procedure tbPlayClick(Sender: TObject); + procedure btCloseClick(Sender: TObject); + procedure mnuPreviewQualityClick(Sender: TObject); + procedure chkRenderClick(Sender: TObject); + procedure sbFilterRadiusDownClick(Sender: TObject); + procedure sbFilterRadiusUpClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure tbStopClick(Sender: TObject); + private + { Private declarations } + + totFrames: integer; + FrameWidth, FrameHeight: integer; + FrameRatio: double; + AnimPrefix, SaveAnimPath: string; + AnimType: shortint; + AnimCp, PreviewCp: TControlPoint; + PreviewDensity: double; + AnimRender: TRenderer; + AnimProc, DrawPreviewProc: TProc; + StatusGenerating, StatusFinished: string; + CurrentFlame: string; + StopAnimate: boolean; + StartBG: array [0..2] of byte; + + procedure ARotateFlame; + procedure ARotateReference; + procedure ARotate3DCamera; + procedure ARotateGradient; + procedure ARotateHue; + procedure AMorphing; + procedure LerpBG(const i: integer); + + procedure DoAnimate; + procedure FillFlameList; + procedure ChangeControlState(const activate: boolean); + public + { Public declarations } + + procedure UpdateControls; + end; + +var + AnimateForm: TAnimateForm; + +implementation + +{$R *.dfm} + +uses + Main, Editor, Global, XForm, XFormMan, CMap, FormRender, Registry; + +procedure TAnimateForm.btCloseClick(Sender: TObject); +begin + AnimRender.Stop; + tbStopClick(Sender); + Close; +end; + +procedure TAnimateForm.btSaveAnimationClick(Sender: TObject); +var + i: word; + FrameFolder: string; +begin + // AV: first we must check the output directory + SaveAnimPath := edOutFlame.Text; + + if SaveAnimPath = '' then begin + Application.MessageBox(PChar(TextByKey('render-status-nofilename')), + ApophysisSVN, 48); + exit; + end; + + if not DirectoryExists(ExtractFilePath(SaveAnimPath)) then + raise Exception.Create(TextByKey('render-status-pathdoesnotexist')); // AV + + if FileExists(SaveAnimPath) then begin + if Application.MessageBox(PChar( + Format(TextByKey('render-status-fileexists-message1'),[SaveAnimPath]) + + #13#10 + TextByKey('render-status-fileexists-message2')), + ApophysisSVN, 52) = ID_NO then exit; + DeleteFile(SaveAnimPath); + end; + + AnimPrefix := edPrefix.Text; + cbFlamesChange(Sender); + AnimCp.AdjustScale(FrameWidth, FrameHeight); + + StopAnimate := False; + ChangeControlState(false); + + if chkInvertBG.Checked then + for i := 0 to 2 do + StartBG[i] := AnimCp.background[i]; + + AnimProc := procedure + begin + MainForm.SaveXMLFlame(AnimCp, AnimCp.name, SaveAnimPath); + end; + DoAnimate; + + if StopAnimate then begin + AnimStatus.SimpleText := TextByKey('animate-status-stopped'); + exit; + end + else + AnimStatus.SimpleText := StatusFinished; + + ChangeControlState(true); + + if FileExists(SaveAnimPath) then + begin + if chkListFlames.Checked then + begin + OpenFile := SaveAnimPath; + OpenFileType := ftXML; + ListXML(SaveAnimPath, 1); + end; + + if chkRender.Checked then + begin + if Assigned(RenderForm.Renderer) then + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), + ApophysisSVN, 36) = ID_NO then exit; + + if Assigned(RenderForm.Renderer) then RenderForm.Renderer.Terminate; + if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #1 + RenderForm.ResetControls; + + RenderForm.bRenderAll := true; + + if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2 + + RenderForm.RenderFlameFile := SaveAnimPath; + SetLength(RenderForm.FlameNames, totFrames); + for i := 0 to totFrames - 1 do + RenderForm.FlameNames[i] := AnimPrefix + Format('%.3d', [i]); + + if CreateAnimFolder then begin + FrameFolder := RemoveExt(SaveAnimPath) + '\'; + CreateDir(FrameFolder); // create a separate folder for flames + end else + FrameFolder := ExtractFilePath(SaveAnimPath); + RenderForm.Filename := FrameFolder + AnimCp.name + + cbFrameExt.Items[cbFrameExt.ItemIndex]; + renderFileFormat := cbFrameExt.ItemIndex + 1; + renderOversample := seOversample.Value; + renderFilterRadius := StrToFloat(txtFilterRadius.Text); + renderDensity := StrToFloat(txtDensity.Text); + renderWidth := seFrameWidth.Value; + renderHeight := seFrameHeight.Value; + SaveInFlame := False; // all flames are already saved + + RenderForm.Show; + self.Close; + + RenderForm.btnRenderClick(Sender); + end; + end; + +end; + +procedure TAnimateForm.btSetFlameClick(Sender: TObject); +begin + with MainForm.SaveDialog do begin + Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*.xml|' + + TextByKey('common-filter-allfiles') + '|*.*'; + InitialDir := ParamFolder; + FileName := ExtractFileName(edOutFlame.Text); + if Execute then + begin + if ExtractFileExt(FileName) = '' then + FileName := FileName + '.flame'; + edOutFlame.Text := FileName; + end; + end; +end; + +procedure TAnimateForm.cbAnimTypeChange(Sender: TObject); +begin + AnimType := cbAnimType.ItemIndex; + + if AnimType < 5 then + begin + cbFlamesTo.ItemIndex := cbFlames.ItemIndex; + cbFlamesTo.Enabled := False; + end + else begin + cbFlamesTo.Enabled := True; + end; +end; + +procedure TAnimateForm.cbAspectRatioChange(Sender: TObject); +var + r: double; +begin + case cbAspectRatio.ItemIndex of + 0, 1: FrameRatio := FrameWidth / FrameHeight; + 2: FrameRatio := 1.5; + 3: FrameRatio := 4 / 3; + 4: FrameRatio := 1.25; + 5: FrameRatio := 16 / 9; + 6: FrameRatio := 1.6; + 7: FrameRatio := 21 / 9; + end; + + if FrameRatio > (pnlPreview.Width / pnlPreview.Height) then + begin + AnimPreview.Width := pnlPreview.Width; + r := FrameWidth / AnimPreview.Width; + AnimPreview.Height := round(FrameHeight / r); + AnimPreview.Left := 0; + AnimPreview.Top := (pnlPreview.Height - AnimPreview.Height) shr 1; + end + else begin + AnimPreview.Height := pnlPreview.Height; + r := FrameHeight / AnimPreview.height; + AnimPreview.Width := round(FrameWidth / r); + AnimPreview.Top := 0; + AnimPreview.Left := (pnlPreview.Width - AnimPreview.Width) shr 1; + end; +end; + +procedure TAnimateForm.cbFlamesChange(Sender: TObject); +var + flameXML: string; + i: integer; +begin + i := cbFlames.ItemIndex; + if i < 0 then exit; + + if i < (cbFlames.Items.Count - 1) then + begin + flameXML := LoadXMLFlameText(Openfile, cbFlames.Items[i]); + MainForm.ParseXML(AnimCp, flameXML, true); + end + else + AnimCp.Copy(MainCp); + + seFrameWidth.Value := AnimCp.Width; + seFrameHeight.Value := AnimCp.Height; + cbAspectRatioChange(Sender); + + DrawPreviewProc; +end; + +procedure TAnimateForm.chkRenderClick(Sender: TObject); +begin + gbFrameQuality.Enabled := chkRender.Checked; + cbFrameExt.Enabled := chkRender.Checked; +end; + +procedure TAnimateForm.FillFlameList; +var FItem: TListItem; +begin + cbFlames.Clear; + for FItem in MainForm.ListView1.Items do + cbFlames.AddItem(FItem.Caption, nil); + cbFlames.AddItem(MainCp.name + CurrentFlame, nil); + cbFlames.ItemIndex := cbFlames.Items.Count - 1; + cbFlamesTo.Items.Assign(cbFlames.Items); + cbFlamesTo.ItemIndex := cbFlames.ItemIndex; +end; + +procedure TAnimateForm.LerpBG(const i: integer); +var + k, k1: double; + c: byte; +begin + //if (totFrames <= 1) then exit; + k := i / (totFrames - 1); + k1 := (1 - k); + for c := 0 to 2 do + AnimCp.background[c] := Round(k1 * StartBG[c] + k * (255 - StartBG[c])); +end; + +procedure TAnimateForm.ARotateFlame; +var + j: integer; + i, nx: smallint; + rstep: double; + Triangles: TTriangles; + fx: TXForm; +begin + rstep := 2 * pi / totFrames; + nx := AnimCp.NumXForms; + fx := TXForm.Create; + fx.Assign(AnimCp.xform[nx]); + AnimCp.TrianglesFromCp(Triangles); + + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + + for i := -1 to nx - 1 do + Triangles[i] := RotateTriangle(Triangles[i], rstep * j); + AnimCp.GetFromTriangles(Triangles, nx); + AnimCp.xform[nx].Assign(fx); + if chkResetLocation.Checked then AnimCp.CalcBoundbox; + if chkInvertBG.Checked then LerpBG(j); + + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + AnimProc; + + if StopAnimate then break; + end; + fx.Free; +end; + +procedure TAnimateForm.ARotateReference; +var + j, nx: integer; + rstep: double; + Triangles: TTriangles; + fx: TXForm; +begin + rstep := 2 * pi / totFrames; + nx := AnimCp.NumXForms; + fx := TXForm.Create; + fx.Assign(AnimCp.xform[nx]); + AnimCp.TrianglesFromCp(Triangles); + + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + + Triangles[-1] := RotateTriangle(Triangles[-1], rstep * j); + AnimCp.GetFromTriangles(Triangles, nx); + AnimCp.xform[nx].Assign(fx); + if chkResetLocation.Checked then AnimCp.CalcBoundbox; + if chkInvertBG.Checked then LerpBG(j); + + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + AnimProc; + + if StopAnimate then break; + end; + fx.Free; +end; + +procedure TAnimateForm.ARotate3DCamera; +var + j: integer; + rstep: double; +begin + rstep := 2 * pi / totFrames; + + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + + AnimCp.cameraPitch := AnimCp.cameraPitch + rstep; + AnimCp.cameraYaw := AnimCp.cameraYaw + rstep; + AnimCp.cameraRoll := AnimCp.cameraRoll + rstep; + if chkResetLocation.Checked then AnimCp.CalcBoundbox; + if chkInvertBG.Checked then LerpBG(j); + + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + AnimProc; + + if StopAnimate then break; + end; +end; + +procedure TAnimateForm.ARotateGradient; +var + i, j, n: integer; + rstep: double; + SourceMap: TColorMap; +begin + SourceMap := AnimCp.cmap; + rstep := 256 / totFrames; + + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + for i := 0 to 255 do + begin + n := (256 + i - Round(rstep * j)) mod 256; + AnimCp.cmap[i,0] := SourceMap[n,0]; + AnimCp.cmap[i,1] := SourceMap[n,1]; + AnimCp.cmap[i,2] := SourceMap[n,2]; + end; + if chkInvertBG.Checked then LerpBG(j); + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + AnimProc; + + if StopAnimate then break; + end; +end; + +procedure TAnimateForm.ARotateHue; +var + j: integer; + h: double; +begin + h := 1 / totFrames; + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + AnimCp.hue_rotation := h; + RotateCMapHue(AnimCp); + AnimCp.hue_rotation := 1; + if chkInvertBG.Checked then LerpBG(j); + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + AnimProc; + + if StopAnimate then break; + end; +end; + +procedure TAnimateForm.AMorphing; +var + j: integer; + t: smallint; + SourceCp, TargetCp: TControlPoint; + flameXML: string; +begin + j := cbFlamesTo.ItemIndex; + if j = cbFlames.ItemIndex then begin + Application.MessageBox(PChar(TextByKey('animate-status-changeflame')), + ApophysisSVN, 48); + exit; + end; + + SourceCp := AnimCp.Clone; + SourceCp.time := 0; + + if j < (cbFlamesTo.Items.Count - 1) then + begin + TargetCp := TControlPoint.Create; + flameXML := LoadXMLFlameText(Openfile, cbFlamesTo.Items[j]); + MainForm.ParseXML(TargetCp, flameXML, true); + end + else + TargetCp := MainCp.Clone; + TargetCp.time := totFrames - 1; + + PrepareToInterpolation(SourceCp, TargetCp); // adjust non-common parameters + + if chkInvertBG.Checked then + for j := 0 to 2 do // invert target background + TargetCp.background[j] := 255 - SourceCp.background[j]; + + t := AnimType - 5; // interpolation type + + try + for j := 0 to totFrames - 1 do + begin + AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]); + + AnimCp.InterpolateAll(SourceCp, TargetCp, j, t); + if chkResetLocation.Checked then AnimCp.CalcBoundbox; + AnimCp.name := AnimPrefix + Format('%.3d', [j]); + + AnimProc; + + if StopAnimate then break; + end; + finally + SourceCp.Free; + TargetCp.Free; + end; +end; + +procedure TAnimateForm.DoAnimate; +begin + totFrames := seFPS.Value * seDuration.Value; + + try + case AnimType of + 0: ARotateFlame; + 1: ARotateReference; + 2: ARotate3DCamera; + 3: ARotateGradient; + 4: ARotateHue; + 5..8: AMorphing; + end; + except + // TODO + end; +end; + +procedure TAnimateForm.FormClose(Sender: TObject; var Action: TCloseAction); +var + Registry: TRegistry; +begin + { Write position to registry } + Registry := TRegistry.Create; + try + Registry.RootKey := HKEY_CURRENT_USER; + if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Animate', True) then + begin + Registry.WriteInteger('Top', self.Top); + Registry.WriteInteger('Left', self.Left); + Registry.WriteBool('ResetLocation', chkResetLocation.Checked); + Registry.WriteBool('ListFlames', chkListFlames.Checked); + Registry.WriteBool('RenderFrames', chkRender.Checked); + Registry.WriteInteger('AnimationType', cbAnimType.ItemIndex); + end; + finally + Registry.Free; + end; +end; + +procedure TAnimateForm.FormCreate(Sender: TObject); +begin + self.Caption := TextByKey('animate-title'); + tsSettings.Caption := TextByKey('animate-general'); + tsAnimation.Caption := TextByKey('animate-animation'); + gbOutput.Caption := TextByKey('animate-output'); + pnlOutFlame.Caption := TextByKey('animate-outflame'); + pnlPrefix.Caption := TextByKey('animate-prefix'); + gbPreview.Caption := TextByKey('animate-preview'); + pnlFrameExt.Caption := TextByKey('animate-graphicext'); + pnlDuration.Caption := TextByKey('animate-duration'); + lbSeconds.Caption := TextByKey('common-seconds'); + pnlFPS.Caption := TextByKey('animate-fps'); + + gbFrame.Caption := TextByKey('animate-frame'); + pnlFrameWidth.Caption := TextByKey('common-width'); + pnlFrameHeight.Caption := TextByKey('common-height'); + pnlRatio.Caption := TextByKey('adjustment-tab-size-ratio'); + cbAspectRatio.Items[0] := TextByKey('adjustment-tab-size-custom'); + cbAspectRatio.Items[1] := TextByKey('common-keepaspect'); + cbAspectRatio.ItemIndex := 1; // keep current aspect ratio + + gbFrameQuality.Caption := TextByKey('common-quality'); + pnlFilter.Caption := TextByKey('common-filterradius'); + pnlDensity.Caption := TextByKey('common-density'); + pnlOversample.Caption := TextByKey('common-oversample'); + + gbAnimType.Caption := TextByKey('animate-parameters'); + pnlAnimType.Caption := TextByKey('animate-type'); + chkListFlames.Caption := TextByKey('animate-showframes'); + chkRender.Caption := TextByKey('animate-render'); + chkResetLocation.Caption := TextByKey('animate-resetlocation'); + chkInvertBG.Caption := TextByKey('animate-invertbg'); + tbPlay.Caption := TextByKey('common-start'); + btSaveAnimation.Caption := TextByKey('animate-save'); + btClose.Caption := TextByKey('common-close'); + btSetFlame.Hint := TextByKey('common-browse'); + StatusGenerating := TextByKey('animate-status-generating'); + StatusFinished := TextByKey('animate-status-finished'); + CurrentFlame := #32 + TextByKey('animate-currentflame'); + pnlStartFlame.Caption := TextByKey('animate-initflame'); + pnlEndFlame.Caption := TextByKey('animate-finalflame'); + tbPlay.Hint := TextByKey('animate-playhint'); + tbStop.Hint := TextByKey('animate-stophint'); + tbStop.Caption := TextByKey('animate-stop'); + btSaveAnimation.Hint := TextByKey('animate-savehint'); + + cbAnimType.Items[0] := TextByKey('animate-kind-rotateflame'); + cbAnimType.Items[1] := TextByKey('animate-kind-rotatereference'); + cbAnimType.Items[2] := TextByKey('animate-kind-rotatecamera'); + cbAnimType.Items[3] := TextByKey('animate-kind-rotatepalette'); + cbAnimType.Items[4] := TextByKey('animate-kind-rotatehue'); + cbAnimType.Items[5] := TextByKey('animate-kind-morph1'); + cbAnimType.Items[6] := TextByKey('animate-kind-morph2'); + cbAnimType.Items[7] := TextByKey('animate-kind-morph3'); + cbAnimType.Items[8] := TextByKey('animate-kind-morph4'); + cbAnimType.ItemIndex := 0; + + mnuLowQuality.Caption := TextByKey('common-lowquality'); + mnuMediumQuality.Caption := TextByKey('common-mediumquality'); + mnuHighQuality.Caption := TextByKey('common-highquality'); + + case AnimPrevQual of + 0: begin + PreviewDensity := prevLowQuality; + mnuLowQuality.Checked := True; + end; + 1: begin + PreviewDensity := prevMediumQuality; + mnuMediumQuality.Checked := True; + end; + 2: begin + PreviewDensity := prevHighQuality; + mnuHighQuality.Checked := True; + end; + end; + + AnimCp := TControlPoint.Create; + PreviewCp := TControlPoint.Create; + AnimRender := TRenderer.Create; + + DrawPreviewProc := procedure + begin + PreviewCp.Copy(AnimCp); + PreviewCp.sample_density := PreviewDensity; + PreviewCp.AdjustScale(AnimPreview.Width, AnimPreview.Height); + AnimRender.Stop; + AnimRender.SetCP(PreviewCp); + AnimRender.Render; + AnimPreview.Picture.Graphic := AnimRender.GetImage; + Application.ProcessMessages; + end; +end; + +procedure TAnimateForm.FormDestroy(Sender: TObject); +begin + AnimCp.Free; + PreviewCp.Free; + AnimRender.Free; +end; + +procedure TAnimateForm.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\Animate', False) then + begin + if Registry.ValueExists('Left') then + self.Left := Registry.ReadInteger('Left'); + if Registry.ValueExists('Top') then + self.Top := Registry.ReadInteger('Top'); + + if Registry.ValueExists('ResetLocation') then + chkResetLocation.Checked := Registry.ReadBool('ResetLocation'); + if Registry.ValueExists('ListFlames') then + chkListFlames.Checked := Registry.ReadBool('ListFlames'); + if Registry.ValueExists('RenderFrames') then + chkRender.Checked := Registry.ReadBool('RenderFrames'); + if Registry.ValueExists('AnimationType') then + cbAnimType.ItemIndex := Registry.ReadInteger('AnimationType'); + + Registry.CloseKey; + end; + finally + Registry.Free; + end; + + cbFrameExt.ItemIndex := defFrameExt; + txtDensity.Text := FloatToStr(renderDensity); + txtFilterRadius.Text := FloatToStr(Round6(renderFilterRadius)); + seOversample.Value := renderOversample; + edPrefix.Text := defAnimPrefix; + seFPS.Value := AnimFPS; + + edOutFlame.Text := ParamFolder + MainCp.name + ' (animated).flame'; + chkRenderClick(Sender); + cbAnimTypeChange(Sender); + UpdateControls; +end; + +procedure TAnimateForm.mnuPreviewQualityClick(Sender: TObject); +begin + if TMenuItem(Sender).Checked then exit; // prevent unneseccary updating + TMenuItem(Sender).Checked := True; + + case TMenuItem(Sender).Tag of + 0: PreviewDensity := prevMediumQuality; + 1: PreviewDensity := prevMediumQuality; + 2: PreviewDensity := prevHighQuality; + end; + AnimPrevQual := TMenuItem(Sender).Tag; + + DrawPreviewProc; +end; + +procedure TAnimateForm.sbFilterRadiusDownClick(Sender: TObject); +var n: double; +begin + try + n := StrToFloat(txtFilterRadius.Text); + n := Round6(n - 0.05); + if (n > 0) then + txtFilterRadius.Text := FloatToStr(n); + except + raise Exception.Create(TextByKey('render-status-invalidfilterradius')); + end; +end; + +procedure TAnimateForm.sbFilterRadiusUpClick(Sender: TObject); +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 TAnimateForm.seFrameHeightChange(Sender: TObject); +begin + try + FrameHeight := seFrameHeight.Value; + if (cbAspectRatio.ItemIndex > 0) and seFrameHeight.Focused then + begin + FrameWidth := Round(FrameHeight * FrameRatio); + seFrameWidth.Value := FrameWidth; + end; + except + end; +end; + +procedure TAnimateForm.seFrameWidthChange(Sender: TObject); +begin + try + FrameWidth := seFrameWidth.Value; + if (cbAspectRatio.ItemIndex > 0) and seFrameWidth.Focused then + begin + FrameHeight := Round(FrameWidth / FrameRatio); + seFrameHeight.Value := FrameHeight; + end; + except + end; +end; + +procedure TAnimateForm.tbPlayClick(Sender: TObject); +var i: byte; +begin + StopAnimate := False; + cbFlamesChange(Sender); + ChangeControlState(false); + + if chkInvertBG.Checked then + for i := 0 to 2 do + StartBG[i] := AnimCp.background[i]; + + AnimProc := DrawPreviewProc; + DoAnimate; + + AnimStatus.SimpleText := ''; + ChangeControlState(true); +end; + +procedure TAnimateForm.tbStopClick(Sender: TObject); +begin + StopAnimate := True; + ChangeControlState(true); +end; + +procedure TAnimateForm.ChangeControlState(const activate: boolean); +begin + gbFrame.Enabled := activate; + gbAnimType.Enabled := activate; + btSaveAnimation.Enabled := activate; + tbPlay.Enabled := activate; + tbStop.Enabled := not activate; +end; + +procedure TAnimateForm.UpdateControls; +begin + FillFlameList; + cbFlamesChange(self); +end; + +end. diff --git a/Forms/Browser.dfm b/Forms/Browser.dfm index d699304..ba6616f 100644 --- a/Forms/Browser.dfm +++ b/Forms/Browser.dfm @@ -204,7 +204,7 @@ object GradientBrowser: TGradientBrowser end end object SmallImages: TImageList - Left = 192 + Left = 224 Top = 24 Bitmap = { 494C010101000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 @@ -363,12 +363,12 @@ object GradientBrowser: TGradientBrowser object OpenDialog: TOpenDialog DefaultExt = 'ugr' Filter = 'Gradient files (*.ugr)|*.ugr|Fractint map files (*.map)|*.map' - Left = 136 + Left = 160 Top = 24 end object TooltipTimer: TTimer OnTimer = TooltipTimerTimer - Left = 88 + Left = 96 Top = 20 end end diff --git a/Forms/Browser.pas b/Forms/Browser.pas index cf339aa..de8dbcc 100644 --- a/Forms/Browser.pas +++ b/Forms/Browser.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -28,11 +28,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, ToolWin, ImgList, StdCtrls, System.ImageList, - Cmap, Menus, Global, Buttons, Translation; - -const - PixelCountMax = 32768; - PaletteTooltipTimeout = 1500; + Cmap, Menus, Global, Buttons; type TGradientBrowser = class(TForm) @@ -64,10 +60,10 @@ type procedure ListViewInfoTip(Sender: TObject; Item: TListItem; var InfoTip: String); procedure TooltipTimerTimer(Sender: TObject); - // AV: now you really can rename it :-) - function RenameGradient(OldIdent: string; var NewIdent: string): boolean; procedure btnRandomClick(Sender: TObject); // AV private + // AV: now you really can rename it :-) + function RenameGradient(OldIdent: string; var NewIdent: string): boolean; procedure DrawPalette; procedure Apply; public @@ -78,22 +74,24 @@ type function LoadFractintMap(filen: string): TColorMap; end; +{ // AV: we already have this declarations in other units (Cmap and Global)! type EFormatInvalid = class(Exception); pRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = array[0..PixelCountMax - 1] of TRGBTriple; +} var GradientBrowser: TGradientBrowser; -function CreatePalette(strng: string): TColorMap; - implementation -uses Main, Options, Editor, Registry, Adjust, Mutate; +uses + Main, Options, Editor, Registry, Adjust, Mutate, Translation; {$R *.DFM} +(* // AV: exactly the same functions we have in Cmap unit function GetVal(token: string): string; var p: integer; @@ -118,6 +116,7 @@ begin end; Result := str; end; + *) function TGradientBrowser.LoadFractintMap(filen: string): TColorMap; var @@ -140,10 +139,12 @@ begin CloseFile(MapFile); Result := Pal; except - on EInOutError do Application.MessageBox(PChar(Format(TextByKey('common-genericopenfailure'), [FileName])), PCHAR('Apophysis'), 16); + on EInOutError do + raise Exception.CreateFmt(TextByKey('common-genericopenfailure'), [FileName]); end; end; +(* // AV: moved into Cmap unit function CreatePalette(strng: string): TColorMap; { Loads a palette from a gradient string } var @@ -209,7 +210,7 @@ begin RGBBlend(a, b, Result); end; except on EFormatInvalid do - // Result := False; + // end; finally Tokens.Free; @@ -218,6 +219,7 @@ begin Colors.Free; end; end; +*) procedure TGradientBrowser.DrawPalette; var @@ -338,6 +340,11 @@ begin DeleteItem.Caption := TextByKey('common-delete'); RenameItem.Caption := TextByKey('common-rename'); btnRandom.Hint := TextByKey('adjustment-tab-gradient-presethint'); + // AV: moved this here since it never changes + OpenDialog.Filter := Format('%s|*.gradient;*.ugr|%s|*.map|%s|*.*', + [TextByKey('common-filter-gradientfiles'), + TextByKey('common-filter-fractintfiles'), + TextByKey('common-filter-allfiles')]); end; procedure TGradientBrowser.FormShow(Sender: TObject); @@ -373,8 +380,8 @@ begin if ListView.SelCount <> 0 then begin if ConfirmDelete then - c := Application.MessageBox( - PChar(Format(TextByKey('common-confirmdelete'), [ListView.Selected.Caption])), 'Apophysis', 36) = IDYES + c := Application.MessageBox(PChar(Format(TextByKey('common-confirmdelete'), + [ListView.Selected.Caption])), 'Apophysis', 36) = IDYES else c := True; if c then @@ -415,7 +422,8 @@ begin end else Result := False; - except on Exception do Result := False; + except on Exception do + Result := False; end; finally Strings.Free; @@ -424,7 +432,7 @@ end; procedure TGradientBrowser.RenameItemClick(Sender: TObject); begin - if ListView.SelCount <> 0 then + if ListView.Selected <> nil then ListView.Items[ListView.Selected.Index].EditCaption; end; @@ -437,21 +445,15 @@ begin end; procedure TGradientBrowser.btnDefGradientClick(Sender: TObject); -var - fn:string; begin OpenDialog.InitialDir := BrowserPath; - OpenDialog.Filter := Format('%s|*.gradient;*.ugr|%s|*.map|%s|*.*', - [TextByKey('common-filter-gradientfiles'), - TextByKey('common-filter-fractintfiles'), - TextByKey('common-filter-allfiles')]); OpenDialog.FileName := ''; - if OpenSaveFileDialog(GradientBrowser, OpenDialog.DefaultExt, OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then + //if OpenSaveFileDialog(GradientBrowser, OpenDialog.DefaultExt, OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then + if OpenDialog.Execute then begin - Filename := fn; //OpenDialog.FileName; + Filename := OpenDialog.FileName; GradientFile := Filename; - BrowserPath := ExtractFilePath(fn); //ExtractFilePath(OpenDialog.FileName); + BrowserPath := ExtractFilePath(Filename); ListFileContents; end; end; @@ -512,6 +514,8 @@ end; procedure TGradientBrowser.ListViewInfoTip(Sender: TObject; Item: TListItem; var InfoTip: String); +const + PaletteTooltipTimeout = 1500; var i, j: integer; Row: pRGBTripleArray; diff --git a/Forms/ColorRangeForm.dfm b/Forms/ColorRangeForm.dfm index c3633de..2b236de 100644 --- a/Forms/ColorRangeForm.dfm +++ b/Forms/ColorRangeForm.dfm @@ -61,29 +61,15 @@ object ColorSelection: TColorSelection object StartColor: TShape Left = 10 Top = 40 - Width = 30 + Width = 40 Height = 22 end object LastColor: TShape - Left = 140 + Left = 150 Top = 40 - Width = 30 + Width = 40 Height = 22 end - object lbStart: TLabel - Left = 8 - Top = 16 - Width = 94 - Height = 13 - Caption = 'Start palette index:' - end - object lbLast: TLabel - Left = 140 - Top = 16 - Width = 90 - Height = 13 - Caption = 'Last palette index:' - end object btOK: TButton Left = 101 Top = 82 @@ -107,9 +93,9 @@ object ColorSelection: TColorSelection TabOrder = 1 end object SpinStart: TSpinEdit - Left = 40 + Left = 50 Top = 40 - Width = 70 + Width = 80 Height = 22 MaxValue = 253 MinValue = 0 @@ -119,9 +105,9 @@ object ColorSelection: TColorSelection OnKeyPress = SpinValueKeyPress end object SpinLast: TSpinEdit - Left = 170 + Left = 190 Top = 40 - Width = 70 + Width = 80 Height = 22 MaxValue = 255 MinValue = 2 @@ -130,4 +116,22 @@ object ColorSelection: TColorSelection OnChange = SpinLastChange OnKeyPress = SpinValueKeyPress end + object lbStart: TPanel + Left = 10 + Top = 19 + Width = 120 + Height = 21 + BevelOuter = bvLowered + Caption = 'Start palette index:' + TabOrder = 4 + end + object lbLast: TPanel + Left = 150 + Top = 19 + Width = 120 + Height = 21 + BevelOuter = bvLowered + Caption = 'Last palette index:' + TabOrder = 5 + end end diff --git a/Forms/ColorRangeForm.pas b/Forms/ColorRangeForm.pas index 201859e..678edd4 100644 --- a/Forms/ColorRangeForm.pas +++ b/Forms/ColorRangeForm.pas @@ -5,9 +5,10 @@ unit ColorRangeForm; interface uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, ComCtrls, StdCtrls, ExtCtrls, Vcl.Forms, Vcl.Dialogs, Adjust, Translation, - Vcl.Samples.Spin; + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, + System.Classes, Vcl.Controls, ComCtrls, StdCtrls, ExtCtrls, Vcl.Dialogs, + Vcl.Forms, Vcl.Graphics,Vcl.Samples.Spin, Adjust, Translation; + type TColorSelection = class(TForm) btOK: TButton; @@ -16,8 +17,8 @@ type SpinLast: TSpinEdit; StartColor: TShape; LastColor: TShape; - lbStart: TLabel; - lbLast: TLabel; + lbStart: TPanel; + lbLast: TPanel; procedure FormCreate(Sender: TObject); procedure btOKClick(Sender: TObject); procedure FormShow(Sender: TObject); diff --git a/Forms/Curves.dfm b/Forms/Curves.dfm deleted file mode 100644 index 3b97403..0000000 --- a/Forms/Curves.dfm +++ /dev/null @@ -1,125 +0,0 @@ -object CurvesForm: TCurvesForm - Left = 197 - Top = 111 - BorderStyle = bsDialog - Caption = 'Curves' - ClientHeight = 492 - ClientWidth = 489 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'System' - Font.Style = [] - OldCreateOrder = False - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 16 - object Label1: TLabel - Left = 8 - Top = 16 - Width = 75 - Height = 13 - Caption = 'Selected curve:' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - end - object CurvesPanel: TPanel - Left = 8 - Top = 68 - Width = 473 - Height = 414 - BevelOuter = bvNone - Color = clBlack - ParentBackground = False - TabOrder = 0 - end - object cbChannel: TComboBox - Left = 8 - Top = 35 - Width = 185 - Height = 21 - Style = csDropDownList - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ItemIndex = 0 - ParentFont = False - TabOrder = 1 - Text = 'Overall' - OnChange = cbChannelChange - Items.Strings = ( - 'Overall' - 'Red' - 'Green' - 'Blue') - end - object tbWeightLeft: TScrollBar - Left = 326 - Top = 8 - Width = 155 - Height = 21 - Max = 160 - PageSize = 0 - Position = 80 - TabOrder = 2 - OnChange = tbWeightChange - OnScroll = tbWeightScroll - end - object tbWeightRight: TScrollBar - Left = 326 - Top = 35 - Width = 155 - Height = 21 - Max = 160 - PageSize = 0 - Position = 80 - TabOrder = 3 - OnChange = tbWeightChange - OnScroll = tbWeightScroll - end - object Panel2: TPanel - Left = 199 - Top = 8 - Width = 121 - Height = 21 - Cursor = crHandPoint - BevelOuter = bvLowered - Caption = ' First CP weight:' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 4 - end - object Panel1: TPanel - Left = 199 - Top = 35 - Width = 121 - Height = 21 - Cursor = crHandPoint - BevelOuter = bvLowered - Caption = ' Second CP weight:' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 5 - end -end diff --git a/Forms/Curves.pas b/Forms/Curves.pas deleted file mode 100644 index 959d238..0000000 --- a/Forms/Curves.pas +++ /dev/null @@ -1,123 +0,0 @@ -unit Curves; - -interface - -uses Windows, Classes, Graphics, Forms, Controls, CurvesControl, Vcl.ExtCtrls, - Vcl.StdCtrls, Vcl.ComCtrls, ControlPoint, Registry, Global; - -type - TCurvesForm = class(TForm) - CurvesPanel: TPanel; - cbChannel: TComboBox; - tbWeightLeft: TScrollBar; - tbWeightRight: TScrollBar; - Panel2: TPanel; - Panel1: TPanel; - Label1: TLabel; - procedure FormShow(Sender: TObject); - procedure cbChannelChange(Sender: TObject); - procedure tbWeightChange(Sender: TObject); - procedure tbWeightScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); - procedure FormCreate(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - private - { Private declarations } - published - CurvesControl: TCurvesControl; - public - procedure SetCp(cp: TControlPoint); - end; - -var - CurvesForm: TCurvesForm; - -implementation - -uses Main; - -{$R *.DFM} - -procedure TCurvesForm.tbWeightScroll(Sender: TObject; ScrollCode: TScrollCode; - var ScrollPos: Integer); -begin - if ScrollCode = scEndScroll then - CurvesControl.UpdateFlame; -end; - -procedure TCurvesForm.SetCp(cp: TControlPoint); -begin - if CurvesControl = nil then Exit; - CurvesControl.SetCp(cp); -end; - -procedure TCurvesForm.cbChannelChange(Sender: TObject); -begin - if CurvesControl = nil then Exit; - CurvesControl.ActiveChannel := TCurvesChannel(cbChannel.ItemIndex); - tbWeightLeft.Position := Round(CurvesControl.WeightLeft * 10); - tbWeightRight.Position := Round(CurvesControl.WeightRight * 10); -end; - -procedure TCurvesForm.FormClose(Sender: TObject; var Action: TCloseAction); -var - Registry: TRegistry; -begin - { Write position to registry } - Registry := TRegistry.Create; - try - Registry.RootKey := HKEY_CURRENT_USER; - if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Curves', True) then - begin - Registry.WriteInteger('Top', self.Top); - Registry.WriteInteger('Left', self.Left); - end; - finally - Registry.Free; - end; -// bStop := True; -end; - -procedure TCurvesForm.FormCreate(Sender: TObject); -begin - // -end; - -procedure TCurvesForm.FormShow(Sender: TObject); -var Registry: TRegistry; -begin - if not (assigned(curvesControl)) then - begin - CurvesControl := TCurvesControl.Create(self); - CurvesControl.Align := alClient; - CurvesControl.Parent := CurvesPanel; - end; - - Registry := TRegistry.Create; - try - Registry.RootKey := HKEY_CURRENT_USER; - if Registry.OpenKey('Software\' + APP_NAME + '\Forms\Curves', False) then - begin - if Registry.ValueExists('Left') then - self.Left := Registry.ReadInteger('Left'); - if Registry.ValueExists('Top') then - self.Top := Registry.ReadInteger('Top'); - Registry.CloseKey; - end; - finally - Registry.Free; - end; - - tbWeightLeft.Position := Round(CurvesControl.WeightLeft * 10); - tbWeightRight.Position := Round(CurvesControl.WeightRight * 10); - - SetCp(MainCp); -end; - -procedure TCurvesForm.tbWeightChange(Sender: TObject); -begin - CurvesControl.WeightLeft := tbWeightLeft.Position / 10.0; - CurvesControl.WeightRight := tbWeightRight.Position / 10.0; -end; - -end. diff --git a/Forms/Editor.dfm b/Forms/Editor.dfm index cc20def..4ad796d 100644 --- a/Forms/Editor.dfm +++ b/Forms/Editor.dfm @@ -419,6 +419,31 @@ object EditForm: TEditForm Style = tbsDropDown OnClick = InsertPi1Click end + object ToolButton7: TToolButton + Left = 655 + Top = 0 + Width = 8 + Caption = 'ToolButton7' + ImageIndex = 33 + Style = tbsSeparator + end + object tbComment: TToolButton + Left = 663 + Top = 0 + Caption = 'tbComment' + ImageIndex = 45 + ParentShowHint = False + ShowHint = True + OnClick = tbCommentClick + end + object SaveFlameState: TToolButton + Left = 687 + Top = 0 + ImageIndex = 46 + ParentShowHint = False + ShowHint = True + OnClick = SaveFlameStateClick + end end end object EditPnl: TPanel @@ -497,7 +522,7 @@ object EditForm: TEditForm Top = 79 Width = 298 Height = 413 - ActivePage = TabVariables + ActivePage = tabVariations Anchors = [akLeft, akTop, akRight, akBottom] MultiLine = True ParentShowHint = False @@ -541,9 +566,9 @@ object EditForm: TEditForm TabOrder = 0 OnResize = TrianglePanelResize object TriangleToolBar: TToolBar - Left = 28 + Left = 15 Top = 218 - Width = 163 + Width = 200 Height = 28 ParentCustomHint = False Align = alNone @@ -622,8 +647,19 @@ object EditForm: TEditForm ParentShowHint = False ShowHint = True end + object tbSyncTriangles: TToolButton + Left = 161 + Top = 0 + Caption = 'tbSyncTriangles' + DropdownMenu = mnuSyncTriangles + ImageIndex = 44 + ParentShowHint = False + ShowHint = True + Style = tbsDropDown + OnClick = tbSyncTrianglesClick + end end - object GroupBox5: TGroupBox + object gbTrgOperations: TGroupBox Left = 20 Top = 112 Width = 177 @@ -1078,7 +1114,7 @@ object EditForm: TEditForm '0.01') end end - object GroupBox6: TGroupBox + object gbCoordinates: TGroupBox Left = 6 Top = 0 Width = 209 @@ -1438,7 +1474,7 @@ object EditForm: TEditForm OnUpClick = SpinButtonUpClick end end - object GroupBox3: TGroupBox + object gbPivot: TGroupBox Left = 6 Top = 248 Width = 209 @@ -1623,7 +1659,7 @@ object EditForm: TEditForm OnUpClick = SpinButtonUpClick end end - object GroupBox10: TGroupBox + object gbFlip: TGroupBox Left = 6 Top = 319 Width = 209 @@ -3068,7 +3104,7 @@ object EditForm: TEditForm DesignSize = ( 290 367) - object Label4: TLabel + object lblSearch: TLabel Left = 2 Top = 8 Width = 37 @@ -3137,6 +3173,7 @@ object EditForm: TEditForm Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 0 + TextHint = 'type a name...' OnChange = chkCollapseVariationsClick end object btnVarOrder: TBitBtn @@ -3215,7 +3252,9 @@ object EditForm: TEditForm Items.Strings = ( 'Show all variations' 'Hide unused variations' - 'Favourite variations') + 'Favourite variations' + '3D-aware variations' + 'Direct coloring variations') end end object TabVariables: TTabSheet @@ -3627,136 +3666,264 @@ object EditForm: TEditForm Left = 313 Top = 40 Bitmap = { - 494C01012B003000040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 - 000000000000360000002800000040000000B0000000010020000000000000B0 + 494C01012F004000040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 000000000000360000002800000040000000C0000000010020000000000000C0 + 000000000000000000000000000000000000A449A300A449A300A449A300A449 + A300A449A300A449A30000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000DEE0DF009EA2 + A0008B908E008B908E008B908E008A8F8D008A8F8D00898F8D00898E8C00898E + 8C00888E8C009A9E9C00DDDEDD0000000000F8F8F807C6C6C639C5C5C53AC5C5 + C53AC5C5C53AC5C5C53AC5C5C53AC5C5C53ACACACA35FAFAFA05FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300BD6ABD00BD6ABD00BD6A + BD00A449A300000000000000000000000000000000006E9B7000FCFDFD000000 + 00000000000000000000000000000000000000000000000000009EA3A100EBED + EC00FEFFFE00FEFFFF00FEFFFF00000000000000000000000000000000000000 + 000000000000EEEFEF00999E9C0000000000C6C6C639F7F7F6FEF9F9F9FFFBFB + FBFFFBFBFBFFFCFCFCFFFDFDFDFFFFFFFFFFEAE9E9FE9C9C9AC7F5F5F50AFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300BD6ABD00BD6ABD00A449 + A30000000000000000000000000000000000000000004F885300619765000000 + 00000000000000000000000000000000000000000000000000008F959200FEFE + FE00EAEDEC00EAEDEC00EBEEED00ECEFEE00EDEFEE00EDF0EF00EEF0EF00EEF0 + EF00EEF0EF00FEFFFF008D929000FBFCFB00C5C5C53AF7F7F6FFF8F8F8FFFAFA + FAFFFBFBFBFFFCFCFCFFFDFDFDFFFEFEFEFFF4F4F4FFCCCCCCFF979793D5EDED + ED12FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300BD6ABD00A449A3000000 + 0000C6D7C7005789590023662700266B2B002A712F0053995A00569D5E006FA5 + 730000000000000000000000000000000000000000000000000091969400FDFE + FE00E7EAE900858A8800858A8800858A880000000000005CCE00BACFE500E9EC + EB00EAEDEC00FEFEFE008E939100FBFCFC00C5C5C53AF6F6F6FFF7F7F7FF9191 + BFFFECECF1FF9595C4FFFCFCFCFFFEFEFEFFFBFBFBFFC4C4C4FFFDFDFDFF9999 + 94D5F5F5F50AFFFFFF00FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300A449A30000000000C6D7 + C7004D82500060A7680081C88C0084C98E0087CA91008ACB94008DCD970060A7 + 6800529B5A00000000000000000000000000000000000000000092989600FDFE + FD00E4E8E700E3E7E500E3E8E600E4E8E600005CCE000000000036576B00005C + CE00B8CDE200FEFEFE0090969400FAFBFB00C5C5C53AF6F6F5FFF6F6F6FF3236 + C2FF2A2EB8FF3339C3FFFCFCFCFFFEFEFEFFFEFEFEFFE0E0E0FFC6C6C6FFCFCF + CEFFA2A09FC7FAFAFA05FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A30000000000000000007AA2 + 7C005BA1630082C88D0051975800317A360035803B005DA4650062A96A0075B1 + 7B00000000000000000000000000000000000000000000000000949A9700FDFD + FD00E1E6E300858A8800858A8800858A8800858A8800005CCE003EAFFC000079 + F500005CCE00A2C3EC0092979500FBFBFB00C5C5C53AF5F5F4FFF5F5F5FF3337 + C4FF0108DAFF373AC3FFFBFBFBFFFDFDFDFFFEFEFEFFFEFEFEFFFCFCFCFFFAFA + FAFFF0EFEFFECACACA35FFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000000000000000407C + 4400296F2E002D753300639B6800000000000000000062A3670071AE7700FEFE + FE00F9FCF9000000000000000000000000000000000000000000969B9900FDFD + FD00DDE3E000DCE1DF00DCE2DF00DDE2E000DDE2E000005CCE0000D4F5003EAF + FC000079F500005CCE004B7BB200FCFCFC00C5C5C53AF4F4F4FFF4F4F4FF3B3E + C2FF0409CFFF3E41C2FFFAFAFAFFFCFCFCFFFDFDFDFFFDFDFDFFFEFEFEFFFEFE + FEFFFEFEFEFFC5C5C53AFFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00CC483F00CC483F00CC48 + 3F00CC483F00CC483F00CC483F00CC483F000000000082B98800000000000000 + 0000000000000000000000000000000000000000000000000000979D9B00FDFD + FD00DAE0DD00858A8800858A8800858A8800858A8800858A8800005CCE0000D4 + F5003EAFFC000079F500005CCE0080ADE500C5C5C53AF4F4F3FFF3F3F2FF3A3E + BCFF060BC3FF3D40BCFFFAFAFAFFFBFBFBFFFCFCFCFFFCFCFCFFFDFDFDFFFDFD + FDFFFDFDFDFFC5C5C53AFFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00E8A20000E8A20000E8A2 + 0000E8A20000E8A20000CC483F0080B585000000000000000000241CED00241C + ED00241CED00241CED00241CED00241CED000000000000000000999F9D00FDFD + FD00D9DFDC00D6DCDA00D6DDD900D5DCD900D5DCD900D5DCD900D6DCD900005C + CE0000D4F5003EAFFC000079F500005CCE00C5C5C53AF2F2F2FFF1F1F1FF3336 + B3FF080CB8FF3738B4FFF9F9F9FFFAFAFAFFFBFBFBFFFBFBFBFFFCFCFCFFFCFC + FCFFFCFCFCFFC5C5C53AFFFFFF00FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00E8A20000E8A20000E8A2 + 0000E8A20000CC483F0070AE760068AC6F000000000000000000241CED00285E + FD00285EFD00285EFD00241CED000000000000000000000000009BA19E00FDFD + FD00DAE0DC00858A8800858A8800858A8800858A8800858A8800858A8800858A + 8800005CCE0000D4F5003EAFFC00005CCE00C5C5C53AF1F1F0FFF0F0EFFF2C2E + AAFF0B0DADFF3031ABFFF7F7F7FFF9F9F9FFFAFAFAFFFAFAFAFF9CDE9CFF26C0 + 26FF0AB10AFF1DB81DE2A1E1A15EFFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00E8A20000E8A20000E8A2 + 0000CC483F0077B17C006BB374006FB7780052A95C0057AF6100241CED00285E + FD00285EFD00241CED00000000000000000000000000000000009CA2A000FDFD + FD00DCE3E000DAE0DD00D8DFDC00D7DEDB00D6DCD900D4DBD800D1D9D500CBD2 + CE00C6CDC900005CCE00005CCE00A1C3EC00C5C5C53AEFEFEEFFEEEEEDFF2525 + A1FF0D0EA2FF292AA2FFF5F5F5FFF7F7F7FFF8F8F8FF9BDE9BFF01B401FF00A9 + 17FFFFFFFFFF00B234FF02B504FD9BE09B640000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00E8A20000E8A20000CC48 + 3F005FA566006CB474009FD5A700A2D6AA00A5D8AD00A8D9AF00241CED00285E + FD00241CED00D9F1DC00000000000000000000000000000000009EA4A200FDFD + FD00E1E6E400858A8800858A8800858A8800858A8800D7DEDB00BBC1BF00AAB0 + AC00B1B3B200D8DBD900BABFBD0000000000C5C5C53AEEEEEDFFECECECFF1D1E + 9DFF0D0EA1FF21219FFFF3F3F2FFF5F5F5FFF6F6F6FF22B522FF009F03FF00A0 + 34FFFFFFFFFF00B064FF00B033FF22B522DD0000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00E8A20000CC483F000000 + 00000000000080BE870075BE7E0079C282005DB7670060BC6B00241CED00241C + ED00D9F1DC000000000000000000000000000000000000000000A0A6A300FDFE + FD00E5E9E700E2E7E400E0E5E300DEE4E100DCE2DF00DAE0DD00C1C6C4000000 + 0000FCFDFC00ABAFAD00E7E8E70000000000C5C5C53AECECEBFFEBEBEAFF1C1D + A5FF0B0DACFF1F21A7FFF0F0F0FFF2F2F2FFF3F3F3FF099509FFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFF099709F60000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00CC483F00000000000000 + 0000000000000000000083C68A007AC583000000000000000000241CED000000 + 0000000000000000000000000000000000000000000000000000A1A7A500FEFE + FE00E9ECEB00E5E9E700E3E8E500E1E6E300DEE4E100DFE5E200D8DAD900FDFD + FD00BCC0BF00D2D5D4000000000000000000C5C5C53AEAE9E8FFE8E8E7FF2223 + B1FF090CB7FF2427B1FFEEEEEDFFF0F0EFFFF1F1F0FF25AC25FF1DAF1DFF29B4 + 3FFFFFFFFFFF29BC5AFF1DB531FF26AE26D90000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F0000000000000000000000 + 00000000000000000000FDFEFD0096D49E000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000AEB3B100EDEF + EE000000000000000000000000000000000000000000F9FAF900E8E9E900AFB5 + B200D3D5D400000000000000000000000000C5C5C53AEAEAEAFFE8E8E7FF282A + BCFF060BC3FF2A2CBCFFEEEEEDFFF0F0EFFFF1F1F0FF96D496FF36B736FF78D1 + 78FFFFFFFFFF78D67AFF36BB36FD9FDC9F600000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000E4E6E500AFB5 + B300A6ACAA00A6ACA900A5ABA900A5ABA800A5ABA800A6ACAA00BFC3C100E6E8 + E70000000000000000000000000000000000EFEFEF10C5C5C53AC5C5C53A6A6D + DFF08183E5F9686ADEEEC5C5C53AC5C5C53AC5C5C53AC5C5C53A79B779863EB2 + 3EE55EC45EF942B342E29BD99B64FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000050101002A0E0D00250D0B00250D 0B00260D0B0026090700000000007B7B7B00E6E6E60000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300A449A300A449A300A449 + A300A449A3000000800000008000000080000000800000008000000080000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002A0F0C00F1554A00DE4E4400DF4E 4400F653480057181400D7DEDF001A1A1A0000000000D8D8D800000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300BD6ABD00BD6ABD000000 + 8000000080000000800000008000000080000000800000008000000080000000 + 8000000080000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000250D0B00DE4E4400CD483F00D948 3E003A020000D6E1E20000000000000000000000000000000000E6E6E6000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000A449A300BD6ABD00000080000000 + 8000000080000000800000008000000080000000800000008000000080000000 + 8000000080000000800000008000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000250D0B00DF4E4500D8483E004C1C 1800CAD8D900000000000000000000000000F4F4F40010101000000000000000 000000000000000000000000000000000000000000000000000000000000FFFF FF00FFFFFF00D7D7D7000000000000000000D7D7D700FFFFFF00FFFFFF00FFFF - FF00000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + FF0000000000000000000000000000000000A449A30000008000000080000000 + 8000000080000000800023662700266B2B002A712F0053995A00569D5E000000 + 8000000080000000800000008000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000260D0B00F65348003A020000CAD8 D900000000000000000000000000000000000000000084848400000000000000 000000000000000000000000000000000000000000000000000000000000FFFF FF00FFFFFF00FFFFFF000000000000000000FFFFFF00FFFFFF00FFFFFF009191 - 9100C3C3C3000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 9100C3C3C3000000000000000000000000000000800000008000000080000000 + 800000008000000080000000800084C98E0087CA91008ACB94008DCD970060A7 + 6800000080000000800000008000000080000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002609060056171300D6E1E2000000 0000000000000000000000000000000000000000000000000000000000006D6D 6D00000000000000000000000000000000000000000000000000000000009191 9100FFFFFF00FFFFFF000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 0000FFFFFF000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000FFFFFF000000000000000000000000000000800000008000000080000000 + 80000000800000008000000080000000800035803B005DA4650062A96A0075B1 + 7B00000000000000800000008000000080000000000000000000000000000000 0000000000000000000000000000000000000000000052525200000000000000 00000000000000000000000000000000000000000000DAE1E100000000000000 000000000000000000000000000000000000F7F7F7000A0A0A005B5B5B000000 0000000000000000000000000000000000000000000000000000000000000000 0000FFFFFF00FFFFFF009191910000000000C3C3C300FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000080000000800000000000407C + 4400000080000000800000008000000080000000800062A3670071AE7700FEFE + FE00F9FCF9000000000000008000000080000000000000000000000000000000 0000000000000000000000000000000000005252520000000000000000000000 000000000000000000000000000000000000F1F1F10099999900F7F7F7000000 00000000000000000000000000000000000000000000E9E9E900000000000000 0000000000000000000000000000000000000000000000000000000000000000 000091919100FFFFFF009191910000000000C3C3C300FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000800000008000CC483F00CC48 + 3F00CC483F000000800000008000000080000000800000008000000000000000 + 0000000000000000000000008000000080000000000000000000000000000000 0000000000000000000000000000525252000000000000000000000000000000 000000000000000000000000000000000000929292000000000000000000E9E9 E900DFDFDF00C2C3B600C5C6B700C5C6B700C5C6B700CACABC00C4C4C100CECE CE00000000000000000000000000000000000000000000000000000000000000 000000000000C3C3C300C3C3C3000000000091919100FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000800000008000E8A20000E8A2 + 0000E8A20000E8A200000000800000008000000080000000800000008000241C + ED00241CED00241CED0000008000000080000000000000000000000000000000 0000000000000000000052525200000000000000000000000000000000000000 000000000000000000000000000000000000626262000000000078787800BBBB BB004C4D40000000620000006E0000006C0000006D000000850000000000B3B4 B100000000000000000000000000000000000000000000000000D7D7D7000000 00000000000091919100C3C3C3000000000091919100FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000800000008000E8A20000E8A2 + 0000E8A20000CC483F0070AE7600000080000000800000008000000080000000 + 8000285EFD00285EFD0000008000000080000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000DADADA0000000000F1F1F1000000 0000505139001B11EF00261DFD00261DFB00251CFF0000006F00C9C9C3000000 000000000000000000000000000000000000000000000000000091919100FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + FF00FFFFFF00000000000000000000000000000080000000800000008000E8A2 + 0000CC483F0077B17C006BB374006FB778000000800000008000000080000000 + 8000000080000000800000008000000080000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D0D0D00000000000F5F5F5000000 0000505139001910E300241CEF00261DFF0009066400CDCEB800000000000000 000000000000000000000000000000000000000000000000000000000000FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + FF00FFFFFF000000000000000000000000000000800000008000000080000000 + 80005FA566006CB474009FD5A700A2D6AA00A5D8AD0000008000000080000000 + 8000000080000000800000008000000080000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C8C8C800000000003F3F3F009F9F 9F005D5E46001910E400261DFF0000005E007A7A6A00393A3C00000000000000 000000000000E8E8E8009C9C9C00000000000000000000000000000000009191 9100D7D7D700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + FF00FFFFFF00000000000000000000000000CC483F0000008000000080000000 + 8000000080000000800075BE7E0079C282005DB7670060BC6B00000080000000 + 8000000080000000800000008000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000007F7F7F00000000007373 730060614B00160DF00004006700D1D2BF00DBDBDB0000000000000000004B4B 4B00F8F8F800C8C8C80000000000ADADAD000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F00CC483F00000080000000 + 8000000080000000800000008000000080000000800000008000000080000000 + 8000000080000000800000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00004F50460000005900C3C4AD000000000000000000BDBDBD00666666000000 0000000000000000000000000000424242000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000CC483F0000000000000000000000 + 8000000080000000800000008000000080000000800000008000000080000000 + 8000000080000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003D3D3D00C9C9BF000000000000000000000000000000000000000000C8C8 C800D4D4D400AFAFAF0043434300000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000800000008000000080000000800000008000000080000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 @@ -5038,12 +5205,16 @@ object EditForm: TEditForm 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 - 2800000040000000B00000000100010000000000800500000000000000000000 - 000000000000000000000000FFFFFF007FFF007FFFFF0000BBFF003FFFFF0000 - DFFF031FFFFF0000EBFF071FE30F0000F7FF0F9FE3070000A80A1F0FE3170000 - F99F3F1FF11F0000FA3F1FBFF11F0000FA71000FF91F0000F8B9000FD91F0000 - F9D5101FC0070000FBEF103FE0070000FFD70039E0070000FABB8000FFFF0000 - FE7DF180FFFF0000FA3EF3E1FFFF0000FFFFFFFF0001FFFFFFE7000100010000 + 2800000040000000C00000000100010000000000000600000000000000000000 + 000000000000000000000000FFFFFF0003FFC00100000000079FC1F900000000 + 0F9FC00000000000100FC000000000002007C00000000000600FC00000000000 + E187C0000000000000BFC0000000000000C0C0000000000000C1C00000000000 + 0003C000000000000003C001000000001807C011000000003CDFC00300000000 + 7CFFCF8700000000FFFFC00F000000007FFF007FFFFF001FBBFF003FFFFF0007 + DFFF031FFFFF0001EBFF071FE30F0001F7FF0F9FE3070000A80A1F0FE3170008 + F99F3F1FF11F2004FA3F1FBFF11F003CFA71000FF91F0000F8B9000FD91F0000 + F9D5101FC0070000FBEF103FE0070000FFD70039E0070001FABB8000FFFF0003 + FE7DF180FFFF6007FA3EF3E1FFFFF81FFFFFFFFF0001FFFFFFE7000100010000 FFC7000100010001000300010001000200010007000700070001000D000D000E 0003001F001F001FE027003D003D003EE02700570057002B0003003D00FD007E 0001031F03FF00FF0001068D06FD017E00030FC70FFF03FFFFC71EE11EFD077E @@ -5265,6 +5436,18 @@ object EditForm: TEditForm object N19: TMenuItem Caption = '-' end + object mnuCopyChaos: TMenuItem + Caption = 'Copy settings' + OnClick = mnuCopyChaosClick + end + object mnuPasteChaos: TMenuItem + Caption = 'Paste settings' + Enabled = False + OnClick = mnuPasteChaosClick + end + object N23: TMenuItem + Caption = '-' + end object ShowChaosMatrix: TMenuItem Caption = 'Show chaos matrix...' OnClick = btnFullChaosClick @@ -5389,31 +5572,56 @@ object EditForm: TEditForm Caption = 'Use degrees' Checked = True end + object N22: TMenuItem + Caption = '-' + end + object mnuCalcExpression: TMenuItem + Caption = 'Calculate expression...' + OnClick = mnuCalcExpressionClick + end end object CopyMenu: TPopupMenu Left = 305 Top = 241 - object Copytrianglecoordinates1: TMenuItem + object CopyTriangleCoordinates: TMenuItem Caption = 'Copy Triangle Coordinates' OnClick = btnCopyTriangleClick end - object Copytransform1: TMenuItem + object CopyTransform: TMenuItem Caption = 'Copy Whole Transform' - OnClick = Copytransform1Click + OnClick = CopyTransformClick + end + object CopyVariations: TMenuItem + Caption = 'Copy variations ' + OnClick = CopyVariationsClick + end + object CopyChaos: TMenuItem + Caption = 'Copy chaos' + OnClick = mnuCopyChaosClick end end object PasteMenu: TPopupMenu Left = 385 Top = 233 - object Pastetrianglecoordinates1: TMenuItem + object PasteTriangleCoordinates: TMenuItem Caption = 'Paste Triangle Coordinates' Enabled = False OnClick = btnPasteTriangleClick end - object Pastetransform1: TMenuItem + object PasteTransform: TMenuItem Caption = 'Paste Transform(s)' Enabled = False - OnClick = Pastetransform1Click + OnClick = PasteTransformClick + end + object PasteVariations: TMenuItem + Caption = 'Paste variations' + Enabled = False + OnClick = PasteVariationsClick + end + object PasteChaos: TMenuItem + Caption = 'Paste chaos' + Enabled = False + OnClick = mnuPasteChaosClick end end object TriangleOperations: TPopupMenu @@ -5506,6 +5714,15 @@ object EditForm: TEditForm Caption = '-' GroupIndex = 5 end + object SynchronizeAll: TMenuItem + Caption = 'Apply operations to all triangles' + GroupIndex = 5 + OnClick = SynchronizeAllClick + end + object N20: TMenuItem + Caption = '-' + GroupIndex = 5 + end object InvertMovevalue1: TMenuItem Caption = 'Invert current Move step' GroupIndex = 5 @@ -5934,4 +6151,10 @@ object EditForm: TEditForm FE7FFC7FFFF7FFCFFF7FFC7FFFFFFFFF00000000000000000000000000000000 000000000000} end + object mnuSyncTriangles: TPopupMenu + AutoHotkeys = maManual + OwnerDraw = True + Left = 377 + Top = 369 + end end diff --git a/Forms/Editor.pas b/Forms/Editor.pas index 9050180..037ff04 100644 --- a/Forms/Editor.pas +++ b/Forms/Editor.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -33,10 +33,10 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls, Math, Menus, ToolWin, Registry, - Grids, ValEdit, Buttons, ImgList, Types, StrUtils , Curves, + Grids, ValEdit, Buttons, ImgList, Types, StrUtils, ControlPoint, XForm, cmap, CustomDrawControl, ClipBrd, - RenderingInterface, Translation, RenderThread, System.ImageList, - Vcl.Samples.Spin; + RenderingInterface, RenderThread, System.ImageList, + Vcl.Samples.Spin, Vcl.GraphUtil; type TEditForm = class(TForm) @@ -156,7 +156,7 @@ type Panel2: TPanel; PrevPnl: TPanel; PreviewImage: TImage; - GroupBox5: TGroupBox; + gbTrgOperations: TGroupBox; btTrgRotateLeft90: TSpeedButton; btTrgRotateRight90: TSpeedButton; btTrgScaleDown: TSpeedButton; @@ -170,7 +170,7 @@ type txtTrgScaleValue: TComboBox; txtTrgRotateValue: TComboBox; txtTrgMoveValue: TComboBox; - GroupBox6: TGroupBox; + gbCoordinates: TGroupBox; LabelC: TLabel; LabelA: TLabel; LabelB: TLabel; @@ -246,14 +246,14 @@ type mnuEHighQuality: TMenuItem; mnuEMediumQuality: TMenuItem; mnuELowQuality: TMenuItem; - Label4: TLabel; + lblSearch: TLabel; txtSearchBox: TEdit; ToolButton5: TToolButton; btnMathPopup: TToolButton; tbPreLink: TToolButton; btnFullChaos: TToolButton; btnResetSearch: TSpeedButton; - GroupBox3: TGroupBox; + gbPivot: TGroupBox; btnResetPivot: TSpeedButton; btnPickPivot: TSpeedButton; btnPivotMode: TSpeedButton; @@ -273,10 +273,10 @@ type Insert1sqrt21: TMenuItem; CopyMenu: TPopupMenu; PasteMenu: TPopupMenu; - Copytrianglecoordinates1: TMenuItem; - Copytransform1: TMenuItem; - Pastetrianglecoordinates1: TMenuItem; - Pastetransform1: TMenuItem; + CopyTriangleCoordinates: TMenuItem; + CopyTransform: TMenuItem; + PasteTriangleCoordinates: TMenuItem; + PasteTransform: TMenuItem; Squareroots1: TMenuItem; Insertsqrt361: TMenuItem; Insertsqrt31: TMenuItem; @@ -296,7 +296,7 @@ type RotateY: TMenuItem; ScaleO: TMenuItem; RotateO: TMenuItem; - GroupBox10: TGroupBox; + gbFlip: TGroupBox; btnShowLine: TSpeedButton; btnResetFlip: TSpeedButton; btnFlip: TSpeedButton; @@ -359,6 +359,22 @@ type btnVarOrder: TBitBtn; cbCollapseVariations: TComboBox; btResetParams: TButton; + tbSyncTriangles: TToolButton; + mnuSyncTriangles: TPopupMenu; + SynchronizeAll: TMenuItem; + N20: TMenuItem; + CopyVariations: TMenuItem; + PasteVariations: TMenuItem; + ToolButton7: TToolButton; + tbComment: TToolButton; + mnuCalcExpression: TMenuItem; + N22: TMenuItem; + SaveFlameState: TToolButton; + N23: TMenuItem; + mnuCopyChaos: TMenuItem; + mnuPasteChaos: TMenuItem; + CopyChaos: TMenuItem; + PasteChaos: TMenuItem; procedure btnResetSearchClick(Sender: TObject); procedure txtSearchBoxKeyPress(Sender: TObject; var Key: Char); // procedure txtSearchBoxChange(Sender: TObject); @@ -422,8 +438,6 @@ type procedure scrlXFormColorScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); procedure scrlXFormColorChange(Sender: TObject); -// procedure chkUseXFormColorClick(Sender: TObject); -// procedure chkHelpersClick(Sender: TObject); procedure txtXFormColorExit(Sender: TObject); procedure txtXFormColorKeyPress(Sender: TObject; var Key: Char); procedure txtSymmetrySet(Sender: TObject); @@ -450,7 +464,6 @@ type procedure tbEditModeClick(Sender: TObject); procedure ValidateVariation; -// procedure ValidateValue(Sender: TObject); procedure VEVarsKeyPress(Sender: TObject; var Key: Char); procedure VEVarsChange(Sender: TObject); procedure VEVarsValidate(Sender: TObject; ACol, ARow: Integer; @@ -523,7 +536,6 @@ type Rect: TRect; State: TGridDrawState); procedure mnuChaosViewToClick(Sender: TObject); procedure mnuChaosViewFromClick(Sender: TObject); - // procedure chkPlotModeClick(Sender: TObject); procedure mnuChaosClearAllClick(Sender: TObject); procedure mnuChaosSetAllClick(Sender: TObject); procedure mnuLinkPostxformClick(Sender: TObject); @@ -541,12 +553,11 @@ type procedure bClearClick(Sender: TObject); procedure ColorBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - // procedure btnLoadVVARClick(Sender: TObject); procedure txtNameKeyPress(Sender: TObject; var Key: Char); procedure txtNameExit(Sender: TObject); procedure InsertPi1Click(Sender: TObject); - procedure Copytransform1Click(Sender: TObject); - procedure Pastetransform1Click(Sender: TObject); + procedure CopyTransformClick(Sender: TObject); + procedure PasteTransformClick(Sender: TObject); procedure btResetparamsClick(Sender: TObject); procedure SpinButtonDownClick(Sender: TObject); procedure SpinButtonUpClick(Sender: TObject); @@ -577,13 +588,22 @@ type procedure mnuResetTrgFlipClick(Sender: TObject); procedure btChaosClick(Sender: TObject); procedure mnuChangeGridClick(Sender: TObject); -// procedure btnInvisibleClick(Sender: TObject); -// procedure btnSoloClick(Sender: TObject); procedure ExtSysMenu(var Msg: TMessage); message WM_SysCommand; procedure TriangleOperationsClick(Sender: TObject); procedure btnFullChaosClick(Sender: TObject); procedure btnVarOrderClick(Sender: TObject); - procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean); // AV + procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean); + procedure tbSyncTrianglesClick(Sender: TObject); + procedure SynchronizeAllClick(Sender: TObject); + procedure SyncTrianglesDrawItem(Sender: TObject; ACanvas: TCanvas; + ARect: TRect; State: TOwnerDrawState); + procedure CopyVariationsClick(Sender: TObject); + procedure PasteVariationsClick(Sender: TObject); + procedure tbCommentClick(Sender: TObject); + procedure mnuCalcExpressionClick(Sender: TObject); // AV + procedure SaveFlameStateClick(Sender: TObject); + procedure mnuCopyChaosClick(Sender: TObject); + procedure mnuPasteChaosClick(Sender: TObject); // AV private TriangleView: TCustomDrawControl; cmap: TColorMap; @@ -614,6 +634,7 @@ type showVarPreview: boolean; ShowFlipLine: boolean; // AV hasLinkX: boolean; // AV + SyncTriangles: set of 0..NXFORMS; // AV: to change several triangles at time GraphZoom: double; TriangleCaught, CornerCaught, EdgeCaught: boolean; @@ -631,9 +652,9 @@ type oldx, oldy, olddist: double; Pivot, FlipPoint, fl: TSPoint; - VarsCache: array of double; // AV: now length is sets dynamically // hack: to prevent slow valuelist redraw - // -JF- 64 wasn't big enough... buffer overrun + VarsCache: array of double; // AV: now length is sets dynamically + MemChaos: array of double; // AV BackgroundBmp : TBitmap; Renderer : TRenderThread; @@ -657,13 +678,20 @@ type procedure ShowSelectedInfo; procedure Scale(var fx, fy: double; x, y: integer); + procedure RotateTriangleBy(const angle: double); // AV procedure TriangleViewPaint(Sender: TObject); procedure AutoZoom; procedure KeyInput(str: string); procedure CalcFlip; - function ValidNumField: boolean; inline; // AV: check active edit + function ValidNumField: boolean; inline; // AV: check active control + + // AV: methods to synchronize tranformations of triangles + procedure FillSyncTrianglesMenu; + procedure AdjustSyncTriangles; + procedure SyncTrianglesClick(Sender: TObject); + procedure UpdateSyncTriangles; public cp: TControlPoint; Render: TRenderer; @@ -674,18 +702,19 @@ type LocalPivot, WorldPivot: TSPoint; procedure UpdatePreview; - procedure UpdateDisplay(PreviewOnly: boolean = false); //(?) + procedure UpdateDisplay(PreviewOnly: boolean = false); function GetTriangleColor(n: integer): TColor; function LastTriangle: integer; function InsideTriangle(x, y: double): integer; procedure ScriptGetPivot(var px, py: double); - // procedure InvokeResetAll; + procedure UpdateColorBar; procedure PaintBackground; procedure CreateScreenShot; + procedure RedrawButtons; end; @@ -697,21 +726,27 @@ const $0000ff, $00cccc, $00cc00, $cccc00, $ff4040, $cc00cc, $0080cc, $4f0080, $228080, $608060, $808050, $804f4f, $805080, $226080 ); + saved_variations = 'Variations.list'; + saved_variables = 'Variables.list'; + var EditForm: TEditForm; function ColorValToColor(c: TColorMap; index: double): TColor; + function FlipTriangleVertical(t: TTriangle): TTriangle; function FlipTriangleHorizontal(t: TTriangle): TTriangle; function RotateTriangle(t: TTriangle; rad: double): TTriangle; -function OffsetTriangle(t: TTriangle; range: double): TTriangle; function ScaleTriangle(t: TTriangle; scale: double): TTriangle; -function RotateTriangleCenter(t: TTriangle; rad: double): TTriangle; function RotateTrianglePoint(t: TTriangle; xr, yr: double; rad: double): TTriangle; -function Centroid(t: TTriangle): TSPoint; -function OffsetTriangleRandom(t: TTriangle): TTriangle; -function ScaleTriangleCenter(t: TTriangle; scale: double): TTriangle; function ScaleTrianglePoint(t: TTriangle; x, y, scale: double): TTriangle; +{ +function Centroid(t: TTriangle): TSPoint; +function RotateTriangleCenter(t: TTriangle; rad: double): TTriangle; +function ScaleTriangleCenter(t: TTriangle; scale: double): TTriangle; +function OffsetTriangle(t: TTriangle; range: double): TTriangle; +function OffsetTriangleRandom(t: TTriangle): TTriangle; +} // AV: new operations function ScaleTriangleXY(t: TTriangle; axis: integer; scale: double): TTriangle; function ScaleTriangleO(t: TTriangle; x, y, scale: double): TTriangle; @@ -722,7 +757,8 @@ function FlipTriangleLine(t: TTriangle; x, y, fx, fy: double): TTriangle; implementation uses - Main, Global, Adjust, Mutate, XformMan, Chaos, VarOrderForm; + Main, Global, Adjust, Mutate, XformMan, Translation, + Chaos, VarOrderForm, FlameComment, MathExpressions; {$R *.DFM} @@ -941,13 +977,13 @@ end; procedure TEditForm.UpdateVariationList; // AV: adjust the var_order var - i: integer; + s: string; svars: TStringList; begin svars := TStringList.Create; with cp.xform[SelectedTriangle] do - for i := 0 to NrVar-1 do - svars.AddPair(ifs[i], Round6(GetVariation(GetVariationIndex(ifs[i]))).ToString); + for s in ifs do + svars.AddPair(s, Round6(GetVariation(GetVariationIndex(s))).ToString); VEVars.Strings.Assign(svars); svars.Free; end; @@ -976,6 +1012,15 @@ begin UpdateVariationList; // AV chkCollapseVariablesClick(nil); chkCollapseVariationsClick(nil); + + FillSyncTrianglesMenu; // AV + if (SelectedTriangle < Transforms) and (SelectedTriangle >= 0) then + begin + mnuSyncTriangles.Items[SelectedTriangle].Checked := True; + SyncTriangles := [SelectedTriangle]; + end + else + SyncTriangles := []; end; procedure TEditForm.UpdateDisplay(PreviewOnly: boolean = false); @@ -1153,6 +1198,8 @@ begin btChaos.Visible := True; // AV btClearChaos.Visible := True; // AV btResetChaos.Visible := True; // AV + CopyChaos.Enabled := True; // AV + PasteChaos.Enabled := length(MemChaos) <> 0; // AV if cp.soloXform >= 0 then begin chkXformSolo.Checked := true; @@ -1171,6 +1218,8 @@ begin btChaos.Visible := False; // AV btClearChaos.Visible := False; // AV btResetChaos.Visible := False; // AV + CopyChaos.Enabled := False; // AV + PasteChaos.Enabled := False; // AV optTo.Enabled := False; // AV optFrom.Enabled := False; // AV //chkXformInvisible.Enabled := false; @@ -1233,6 +1282,7 @@ begin end; //AV: moved checks here since Apo7X didn't refresh these pages well + // if cbCollapseVariations.ItemIndex = 1 then chkCollapseVariationsClick(nil); chkCollapseVariablesClick(nil); @@ -1255,7 +1305,102 @@ begin updating := false; end; -/////////////////////////////////////////////////// +{/////////////////////////////////////////////////// } + + procedure TEditForm.FillSyncTrianglesMenu; // AV + var + i: byte; + t: TMenuItem; + pic: TBitMap; + defStyle: boolean; + begin + mnuSyncTriangles.Items.Clear; + + pic := TBitmap.Create; + pic.Width := 16; + pic.Height := 16; + + if (CurrentStyle = 'Windows') then + begin + pic.Transparent := True; + pic.TransparentColor := clWhite; + defStyle := True; + end + else + defStyle := False; + + for i := 0 to Transforms - 1 do + begin + t := TMenuItem.Create(self); + t.Caption := IntToStr(i + 1); + t.Tag := i; + t.AutoCheck := True; + with pic.Canvas do + begin + brush.Color := clWhite; + FillRect(Rect(0, 0, 16, 16)); + pen.Color := TrgColors[i mod 14]; + brush.Color := pen.Color shr 1 and $7f7f7f; + Polygon([Point(15, 5), Point(15, 15), Point(5, 15)]); + end; + t.Bitmap.Assign(pic); + t.OnClick := SyncTrianglesClick; + if defStyle then + t.OnAdvancedDrawItem := SyncTrianglesDrawItem + else + // AV: it's better to rely on RTL rather than adjust colors for every theme manually + t.OnAdvancedDrawItem := nil; + mnuSyncTriangles.Items.Add(t); + end; + pic.Free; + + i := 0; + while i < mnuSyncTriangles.Items.Count do + begin + mnuSyncTriangles.Items[i].Break := mbBreak; + inc(i, mbHeight); + end; + end; + + procedure TEditForm.SynchronizeAllClick(Sender: TObject); + var i: smallint; + begin + for i := 0 to mnuSyncTriangles.Items.Count - 1 do + begin + mnuSyncTriangles.Items[i].Checked := True; + Include(SyncTriangles, i); + end; + end; + + procedure TEditForm.SyncTrianglesClick(Sender: TObject); // AV + begin + if (SelectedTriangle < Transforms) and + (Sender = mnuSyncTriangles.Items[SelectedTriangle]) then + TMenuItem(Sender).Checked := True; + if TMenuItem(Sender).Checked then + Include(SyncTriangles, TMenuItem(Sender).Tag) + else + Exclude(SyncTriangles, TMenuItem(Sender).Tag); + end; + +procedure TEditForm.SyncTrianglesDrawItem(Sender: TObject; ACanvas: TCanvas; + ARect: TRect; State: TOwnerDrawState); +begin + ACanvas.Draw(ARect.Left + 10, ARect.Top, TMenuItem(Sender).Bitmap); + if not (odSelected in State) then + begin + ACanvas.Brush.Color := clMenu; + ACanvas.Font.Color := clMenuText; + end; + if TMenuItem(Sender).Tag = SelectedTriangle then + ACanvas.Font.Style := [fsBold]; + ACanvas.TextOut(ARect.Left + 30, ARect.Top + 2, TMenuItem(Sender).Caption); + if (odChecked in State) then + DrawCheck(ACanvas, Point(ARect.Left + 5, ARect.Top + 10), 3); +end; + +{/////////////////////////////////////////////////// } + procedure TEditForm.CreateScreenShot; begin SaveScreenShot('Apophysis Transform Editor'); @@ -1365,7 +1510,7 @@ begin if not AllowResetCoefs then exit; with TEdit(Sender) do // restore defaults begin - if (Parent = GroupBox6) or btnCoefsRect.Down then + if (Parent = gbCoordinates) or btnCoefsRect.Down then num := IntToStr(Tag) else // if btnCoefsPolar.Down then begin @@ -1434,7 +1579,6 @@ begin cp.GetFromTriangles(MainTriangles, LastTriangle); -// if not chkPreserve.Checked then ComputeWeights(cp, MainTriangles, transforms); DrawPreview; ShowSelectedInfo; TriangleView.Refresh; @@ -1451,7 +1595,6 @@ begin end; if AdjustForm.Visible then AdjustForm.UpdateDisplay; if MutateForm.Visible then MutateForm.UpdateDisplay; - if CurvesForm.Visible then CurvesForm.SetCp(MainCp); MainForm.RedrawTimer.enabled := true; end; @@ -1618,7 +1761,7 @@ begin if (not ValidNumField) then begin Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end else if (ActiveControl = txtTrgRotateValue) then exit; @@ -1751,7 +1894,7 @@ begin txtTrgRotateValue.Text := Format('%.6g', [t]); end else Application.MessageBox(PChar(TextByKey('editor-status-warnscale')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); except Beep; end; @@ -1765,7 +1908,7 @@ begin if (not ValidNumField) then begin Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end; @@ -1806,6 +1949,53 @@ begin end; end; +procedure TEditForm.mnuCalcExpressionClick(Sender: TObject); // AV +var + sn: string; +begin + if (not ValidNumField) then + begin + Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')), + ApophysisSVN, MB_ICONWARNING); + exit; + end; + + try + if (ActiveControl is TEdit) then + sn := TEdit(ActiveControl).Text + else if (ActiveControl is TValueListEditor) then + sn := TValueListEditor(ActiveControl).Cells[1, + TValueListEditor(ActiveControl).Row] + else // if (ActiveControl is TComboBox) then + sn := TComboBox(ActiveControl).Text; + + if not InputQuery(TextByKey('editor-toolbar-calcexpression'), + TextByKey('editor-status-formula'), sn) then exit; + + MathExpressions.InDegrees := UseDegrees.Checked; + sn := MathExpressions.CalculateExpression(LowerCase(sn)); + if sn = '' then exit; // expression is not evaluated + + if (ActiveControl is TEdit) then + begin + TEdit(ActiveControl).Text := sn; + TEdit(ActiveControl).OnExit(ActiveControl); + end + else if (ActiveControl is TValueListEditor) then + begin + TValueListEditor(ActiveControl).Cells[1, + TValueListEditor(ActiveControl).Row] := sn; + TValueListEditor(ActiveControl).OnExit(ActiveControl); + end + else //if (ActiveControl is TComboBox) then + TComboBox(ActiveControl).Text := sn; + + except + Application.MessageBox(PChar(TextByKey('formula-cannotevaluate')), + ApophysisSVN, 16); + end; +end; + procedure TEditForm.TriangleViewPaint(Sender: TObject); const foc_ofs = 4; @@ -1974,12 +2164,9 @@ begin bm.Height := p1; bm.Assign(Render.GetImage); - //Windows.BitBlt(Handle, 0, 0, Windows.AlphaBlend(Handle, 0, 0, - TriangleView.Width, TriangleView.Height, - bm.Canvas.Handle, 0, 0, - //$CC0020); - bm.Width, bm.Height, bf); + TriangleView.Width, TriangleView.Height, + bm.Canvas.Handle, 0, 0, bm.Width, bm.Height, bf); RenderCp.Destroy; try @@ -2512,16 +2699,21 @@ begin mnuHighQuality.Caption := TextByKey('common-highquality'); tbCopy.Hint := TextByKey('common-copy'); tbCopyTriangle.Hint := TextByKey('editor-popup-transform-copycoords'); - Copytrianglecoordinates1.Caption := TextByKey('editor-popup-transform-copycoords'); - Copytransform1.Caption := TextByKey('editor-popup-transform-copywhole'); + CopyTriangleCoordinates.Caption := TextByKey('editor-popup-transform-copycoords'); + CopyTransform.Caption := TextByKey('editor-popup-transform-copywhole'); + CopyVariations.Caption := TextByKey('editor-popup-transform-copyvars'); tbPaste.Hint := TextByKey('common-paste'); tbPasteTriangle.Hint := TextByKey('editor-popup-transform-pastecoords'); - Pastetrianglecoordinates1.Caption := TextByKey('editor-popup-transform-pastecoords'); - Pastetransform1.Caption := TextByKey('editor-popup-transform-pastewhole'); - tbUndo.Caption := TextByKey('common-undo'); + PasteTriangleCoordinates.Caption := TextByKey('editor-popup-transform-pastecoords'); + PasteTransform.Caption := TextByKey('editor-popup-transform-pastewhole'); + PasteVariations.Caption := TextByKey('editor-popup-transform-pastevars'); + CopyChaos.Caption := TextByKey('editor-popup-chaos-copy'); + PasteChaos.Caption := TextByKey('editor-popup-chaos-paste'); + mnuCopyChaos.Caption := CopyChaos.Caption; + mnuPasteChaos.Caption := PasteChaos.Caption; + tbUndo.Hint := TextByKey('common-undo'); mnuUndo.Caption := TextByKey('common-undo'); - tbRedo.Caption := TextByKey('common-redo'); tbRedo.Hint := TextByKey('common-redo'); mnuRedo.Caption := TextByKey('common-redo'); bClear.Caption := TextByKey('common-clear'); @@ -2534,14 +2726,17 @@ begin Panel1.Caption := TextByKey('editor-common-transform'); Panel2.Caption := TextByKey('editor-common-name'); pnlWeight.Caption := TextByKey('editor-common-weight'); + tbComment.Hint := TextByKey('editor-common-editcomment'); + SaveFlameState.Hint := TextByKey('editor-toolbar-savestate'); tabVariations.Caption := TextByKey('editor-tab-variations-title'); VEVars.TitleCaptions[0] := TextByKey('editor-tab-variations-name'); VEVars.TitleCaptions[1] := TextByKey('editor-tab-variations-value'); - //chkCollapseVariations.Caption := TextByKey('editor-tab-variations-togglehideunused'); cbCollapseVariations.Items[0] := TextByKey('editor-tab-variations-toggleshowall'); cbCollapseVariations.Items[1] := TextByKey('editor-tab-variations-togglehideunused'); cbCollapseVariations.Items[2] := TextByKey('editor-tab-variations-togglefavourites'); + cbCollapseVariations.Items[3] := TextByKey('editor-tab-variations-toggle3d'); + cbCollapseVariations.Items[4] := TextByKey('editor-tab-variations-toggledc'); btnVarOrder.Caption := TextByKey('editor-tab-variations-order'); btnVarOrder.Hint := TextByKey('editor-tab-variations-orderhint'); TabVariables.Caption := TextByKey('editor-tab-variables-title'); @@ -2557,7 +2752,7 @@ begin optFrom.Caption := TextByKey('editor-tab-chaos-viewasfrom'); mnuChaosViewFrom.Caption := TextByKey('editor-tab-chaos-viewasfrom'); TriangleTab.Caption := TextByKey('editor-tab-triangle-title'); - GroupBox3.Caption := TextByKey('editor-tab-triangle-pivot'); + gbPivot.Caption := TextByKey('editor-tab-triangle-pivot'); GroupBox7.Caption := TextByKey('editor-tab-transform-coordsystem'); GroupBox9.Caption := TextByKey('editor-tab-transform-affine'); GroupBox8.Caption := TextByKey('editor-tab-transform-postaffine'); @@ -2614,9 +2809,9 @@ begin pnlDC.Caption := TextByKey('editor-tab-color-directcolor'); chkXFormSolo.Caption := TextByKey('editor-tab-color-togglesolo'); GroupBox2.Caption := TextByKey('editor-tab-color-varpreview'); - GroupBox10.Caption := TextByKey('editor-tab-triangle-reflection'); - GroupBox5.Caption := TextByKey('editor-tab-triangle-transforms'); - GroupBox6.Caption := TextByKey('editor-tab-triangle-coordinates'); + gbFlip.Caption := TextByKey('editor-tab-triangle-reflection'); + gbTrgOperations.Caption := TextByKey('editor-tab-triangle-transforms'); + gbCoordinates.Caption := TextByKey('editor-tab-triangle-coordinates'); btnResetFlip.Hint := TextByKey('editor-tab-triangle-resetflip'); Label1.Caption := TextByKey('editor-tab-color-previewrange'); Label2.Caption := TextByKey('editor-tab-color-previewdepth'); @@ -2624,7 +2819,8 @@ begin Label1.Hint := TextByKey('editor-tab-color-previewrangehint'); Label2.Hint := TextByKey('editor-tab-color-previewdepthhint'); Label3.Hint := TextByKey('editor-tab-color-previewdensityhint'); - Label4.Caption := TextByKey('editor-tab-variations-search'); // AV + lblSearch.Caption := TextByKey('editor-tab-variations-search'); // AV + txtSearchBox.TextHint := TextByKey('editor-tab-variations-searchhint'); // AV tbResetAll.Hint := TextByKey('editor-toolbar-newflame'); tbAdd.Hint := TextByKey('editor-toolbar-newtransform'); mnuAdd.Caption := TextByKey('editor-toolbar-newtransform'); @@ -2672,6 +2868,7 @@ begin mnuExtendedEdit.Caption := TextByKey('editor-popup-panel-toggleextendededit'); tbAxisLock.Hint := TextByKey('editor-popup-panel-locktransformaxes'); mnuAxisLock.Caption := TextByKey('editor-popup-panel-locktransformaxes'); + SynchronizeAll.Caption := TextByKey('editor-tab-triangle-syncall'); btnShowLine.Caption := TextByKey('editor-tab-triangle-showline'); btnShowLine.Hint := TextByKey('editor-tab-triangle-showlinehint'); btnFlip.Caption := TextByKey('editor-tab-triangle-fliptriangle'); @@ -2720,7 +2917,7 @@ begin GridComboBox.ItemIndex := 0; lblGridType.Caption := TextByKey('editor-grid-type'); lblGridType.Hint := TextByKey('editor-grid-typehint'); - GroupBox5.Hint := StringReplace(TextByKey('editor-tab-triangle-transformshint'), + gbTrgOperations.Hint := StringReplace(TextByKey('editor-tab-triangle-transformshint'), ',', ','#13, [rfReplaceAll]); // Math constants RedrawButtons; @@ -2748,6 +2945,7 @@ begin CalcSin.Caption := TextByKey('editor-toolbar-calcsin'); CalcTan.Caption := TextByKey('editor-toolbar-calctan'); UseDegrees.Caption := TextByKey('editor-toolbar-usedegrees'); + mnuCalcExpression.Caption := TextByKey('editor-toolbar-calcexpression'); ExtSM := GetSystemMenu(Handle, False); // AV InsertMenu(ExtSM, UINT(5), MF_ByPosition or MF_Separator, 0, nil); @@ -2813,9 +3011,8 @@ begin AxisLock := TransformAxisLock; tbAxisLock.Down := AxisLock; ExtendedEdit := ExtEditEnabled; -// tbExtendedEdit.Down := ExtendedEdit; + // tbExtendedEdit.Down := ExtendedEdit; widgetMode := modeRotate; -// tbExtendedEdit.ImageIndex := imgExtMove; ShowFlipLine := False; hasLinkX := False; @@ -2911,8 +3108,8 @@ begin end; end; - // MainForm.Buttons.GetBitmap(9, btnResetPivot.Glyph); - // btnResetFlip.Glyph.Assign(btnResetPivot.Glyph); + // MainForm.Buttons.GetBitmap(9, btnResetPivot.Glyph); + // MainForm.Buttons.GetBitmap(9, btnResetFlip.Glyph); PageControl.ActivePage := tabVariations; // AV cbCollapseVariations.ItemIndex := 0; // AV @@ -2922,6 +3119,8 @@ procedure TEditForm.FormDestroy(Sender: TObject); begin cp.free; Render.free; + if FileExists(APPDATA + saved_variations) then DeleteFile(APPDATA + saved_variations); + if FileExists(APPDATA + saved_variables) then DeleteFile(APPDATA + saved_variables); end; procedure TEditForm.TriangleViewMouseMove(Sender: TObject; Shift: TShiftState; @@ -3375,7 +3574,7 @@ begin SelectedCorner := j; // Pivot := GetPivot; - if (j = 1) then //and ((rgPivot.ItemIndex = 1) or (rgPivot.ItemIndex = 4)) then + if (j = 1) then begin if PivotMode = pivotLocal then begin Pivot.x := 0; @@ -3397,6 +3596,7 @@ begin HasChanged := false; ShowSelectedInfo; TriangleView.Invalidate; + UpdateSyncTriangles; // AV exit; end; end; @@ -3442,24 +3642,25 @@ begin else if AxisLock then editMode := modeRotate else -begin - // hacky... - CornerCaught := True; - editMode := modeRotate; - if j = 1 then SelectedCorner := 2 - else SelectedCorner := 0; - Pivot := GetPivot; - LocalAxisLocked := false; - OldTriangle := MainTriangles[SelectedTriangle]; - oldx := MainTriangles[SelectedTriangle].x[SelectedCorner] - Pivot.X; - oldy := MainTriangles[SelectedTriangle].y[SelectedCorner] - Pivot.Y; - olddist := sqrt(sqr(oldx) + sqr(oldy)); + begin + // hacky... + CornerCaught := True; + editMode := modeRotate; + if j = 1 then SelectedCorner := 2 + else SelectedCorner := 0; + Pivot := GetPivot; + LocalAxisLocked := false; + OldTriangle := MainTriangles[SelectedTriangle]; + oldx := MainTriangles[SelectedTriangle].x[SelectedCorner] - Pivot.X; + oldy := MainTriangles[SelectedTriangle].y[SelectedCorner] - Pivot.Y; + olddist := sqrt(sqr(oldx) + sqr(oldy)); - HasChanged := false; - ShowSelectedInfo; - TriangleView.Invalidate; - exit; -end; + HasChanged := false; + ShowSelectedInfo; + TriangleView.Invalidate; + UpdateSyncTriangles; // AV + exit; + end; end; goto FoundTriangle; end; @@ -3490,7 +3691,9 @@ FoundTriangle: olddist := sqrt(oldx*oldx + oldy*oldy); UpdateVariationList; // AV - ShowSelectedInfo; + UpdateSyncTriangles; // AV + + ShowSelectedInfo; TriangleView.Invalidate; exit; end @@ -3662,12 +3865,12 @@ begin finally Registry.Free; end; -// chkUseXFormColor.checked := UseTransformColors; -// chkHelpers.Checked := HelpersEnabled; if ExtendedEdit then tbExtendedEdit.Down := true else tbMove.Down := true; + AdjustSyncTriangles; // AV + UpdateDisplay; TrianglePanelResize(nil); ScrollBox1Resize(nil); @@ -3741,11 +3944,11 @@ begin begin with cp.xform[SelectedTriangle] do begin - deta := det(c[0,0], c[0,1], c[1,0], c[1,1]); + deta := detC; // pre-affine determinant if (abs(deta) < 1E-4) then begin Application.MessageBox(PChar(TextByKey('editor-status-warninvert')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end; MainForm.UpdateUndo; @@ -3761,11 +3964,11 @@ begin begin with cp.xform[SelectedTriangle] do begin - deta := det(p[0,0], p[0,1], p[1,0], p[1,1]); + deta := detP; // post-affine determinant if (abs(deta) < 1E-4) then begin Application.MessageBox(PChar(TextByKey('editor-status-warninvert')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end; MainForm.UpdateUndo; @@ -3800,8 +4003,8 @@ begin FlipPoint.x := 1; editFlipX.Text := '1'; FlipPoint.y := 1; editFlipY.Text := '1'; end; - if not ShowFlipLine then CalcFlip; // refresh current angle - TriangleView.Invalidate; + if not ShowFlipLine then CalcFlip // refresh current angle + else TriangleView.Invalidate; // refresh angle and image end; procedure TEditForm.btnCloseClick(Sender: TObject); @@ -4046,6 +4249,11 @@ begin finally Registry.Free; end; + + // AV: free memory + SetLength(MemChaos, 0); + mnuPasteChaos.Enabled := False; + PasteChaos.Enabled := False; end; procedure TEditForm.mnuUndoClick(Sender: TObject); @@ -4061,7 +4269,7 @@ begin if (not ValidNumField) then begin Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end; @@ -4078,8 +4286,8 @@ begin begin case TMenuItem(Sender).Tag of 0: if (txtTrgScaleValue.Focused) then - sn := Format('%.6g', [num * num * 0.01]) - else sn := Format('%.6g', [num * num]); + sn := Format('%.6g', [num * num * 0.01]) + else sn := Format('%.6g', [num * num]); 1: sn := Format('%.6g', [num * 2]); 2: sn := Format('%.6g', [num * 0.5]); else if (txtTrgScaleValue.Focused) then @@ -4105,7 +4313,7 @@ begin end; procedure TEditForm.NormChaosClick(Sender: TObject); -var i, j: integer; +var i, j: smallint; sum: double; begin MainForm.UpdateUndo; @@ -4114,10 +4322,9 @@ begin sum := 0; for j := 0 to Transforms-1 do sum := sum + cp.xform[i].modWeights[j]; - if sum = 1.0 then Exit; - if (sum > 0) then - for j := 0 to Transforms-1 do - cp.xform[i].modWeights[j] := cp.xform[i].modWeights[j] / sum; + if (sum = 1.0) or (sum = 0.0) then continue; + for j := 0 to Transforms-1 do + cp.xform[i].modWeights[j] := cp.xform[i].modWeights[j] / sum; end; UpdateFlame(True); if ChaosForm.Visible then // AV @@ -4180,7 +4387,7 @@ end; procedure TEditForm.mnuFlipAllVClick(Sender: TObject); var - i: integer; + i: smallint; begin MainForm.UpdateUndo; for i := -1 to Transforms do @@ -4195,7 +4402,7 @@ end; procedure TEditForm.mnuFlipAllHClick(Sender: TObject); var - i: integer; + i: smallint; begin MainForm.UpdateUndo; for i := -1 to Transforms do @@ -4210,7 +4417,7 @@ end; procedure TEditForm.mnuFlipAllLineClick(Sender: TObject); // AV var - i: integer; + i: smallint; begin if (FlipPoint.x = 0) and (FlipPoint.y = 0) then exit; if (FlipPoint.x = 0) then mnuFlipAllH.Click @@ -4230,15 +4437,25 @@ end; procedure TEditForm.mnuFlipVerticalClick(Sender: TObject); var p: double; + i: integer; begin MainForm.UpdateUndo; - with MainTriangles[SelectedTriangle] do - begin - p := GetPivot.y * 2; - y[0] := p - y[0]; - y[1] := p - y[1]; - y[2] := p - y[2]; - end; + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + with MainTriangles[SelectedTriangle] do + begin + p := GetPivot.y * 2; + y[0] := p - y[0]; + y[1] := p - y[1]; + y[2] := p - y[2]; + end + else for i in SyncTriangles do + with MainTriangles[i] do + begin + p := GetPivot(i).y * 2; + y[0] := p - y[0]; + y[1] := p - y[1]; + y[2] := p - y[2]; + end;; //AutoZoom; UpdateFlame(True); end; @@ -4246,22 +4463,32 @@ end; procedure TEditForm.mnuFlipHorizontalClick(Sender: TObject); var p: double; + i: integer; begin MainForm.UpdateUndo; - with MainTriangles[SelectedTriangle] do - begin - p := GetPivot.x * 2; - x[0] := p - x[0]; - x[1] := p - x[1]; - x[2] := p - x[2]; - end; + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + with MainTriangles[SelectedTriangle] do + begin + p := GetPivot.x * 2; + x[0] := p - x[0]; + x[1] := p - x[1]; + x[2] := p - x[2]; + end + else for i in SyncTriangles do + with MainTriangles[i] do + begin + p := GetPivot(i).x * 2; + x[0] := p - x[0]; + x[1] := p - x[1]; + x[2] := p - x[2]; + end; //AutoZoom; UpdateFlame(True); end; procedure TEditForm.cbTransformsChange(Sender: TObject); var - n: integer; + n: smallint; begin n := cbTransforms.ItemIndex; @@ -4272,6 +4499,20 @@ begin ShowSelectedInfo; TriangleView.Invalidate; end; + + UpdateSyncTriangles; // AV +end; + +procedure TEditForm.UpdateSyncTriangles; +var n: smallint; +begin + if SelectedTriangle in SyncTriangles then exit; + + for n := 0 to Transforms-1 do + if mnuSyncTriangles.Items[n].Checked then + mnuSyncTriangles.Items[n].Click; + if SelectedTriangle < Transforms then + mnuSyncTriangles.Items[SelectedTriangle].Click; end; procedure TEditForm.cbTransformsDrawItem(Control: TWinControl; @@ -4305,7 +4546,7 @@ begin end; procedure TEditForm.ChaosClearBelowClick(Sender: TObject); -var i, n: integer; +var i, n: smallint; begin n := vleChaos.Row; if n = Transforms then exit; @@ -4321,7 +4562,7 @@ begin end; procedure TEditForm.ClearAllAboveClick(Sender: TObject); -var i, n: integer; +var i, n: smallint; begin n := vleChaos.Row; if (n < 2) then exit; @@ -4454,7 +4695,8 @@ begin if Result then if (ActiveControl = txtSearchBox) or (ActiveControl = txtName) then Exit(False); - Result := Result or (ActiveControl is TValueListEditor) or (ActiveControl is TComboBox); + Result := Result or (ActiveControl is TValueListEditor) or + ((ActiveControl is TComboBox) and (ActiveControl.Parent = gbTrgOperations)); end; (* @@ -4728,8 +4970,7 @@ begin ShowSelectedInfo; UpdateFlame(True); end; - //chkCollapseVariationsClick(nil); - //chkCollapseVariablesClick(nil); + end; (* @@ -5059,7 +5300,7 @@ begin if not (isEdit or (ActiveControl is TValueListEditor)) then begin Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')), - PChar('Apophysis AV'), MB_ICONWARNING); + ApophysisSVN, MB_ICONWARNING); exit; end; @@ -5097,7 +5338,7 @@ begin end; procedure TEditForm.InvertXaosClick(Sender: TObject); -var i: integer; +var i: smallint; cmax: double; begin MainForm.UpdateUndo; @@ -5131,9 +5372,9 @@ end; procedure TEditForm.UpdateColorBar; var - BitMap:TBitmap; - Row:pRGBTripleArray; - i:integer; + BitMap: TBitmap; + Row: pRGBTripleArray; + i: smallint; begin BitMap := TBitMap.Create; try @@ -5156,6 +5397,49 @@ begin end; end; +procedure TEditForm.RotateTriangleBy(const angle: double); // AV +var + i: smallint; +begin + MainForm.UpdateUndo; + + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + begin + if RotateXYO.Checked then + MainTriangles[SelectedTriangle] := + RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, angle) + else if RotateX.Checked then begin + MainTriangles[SelectedTriangle] := + RotateTriangleXY(MainTriangles[SelectedTriangle], 0, angle); + if tbAutoWeights.Down then cp.CalculateWeights; // AV + end else if RotateY.Checked then begin + MainTriangles[SelectedTriangle] := + RotateTriangleXY(MainTriangles[SelectedTriangle], 2, angle); + if tbAutoWeights.Down then cp.CalculateWeights; // AV + end else //if RotateO.Checked then + MainTriangles[SelectedTriangle] := + RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, angle); + end + else begin + if RotateXYO.Checked then + for i in SyncTriangles do + MainTriangles[i] := + RotateTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, angle) + else if RotateX.Checked then + for i in SyncTriangles do + MainTriangles[i] := RotateTriangleXY(MainTriangles[i], 0, angle) + else if RotateY.Checked then + for i in SyncTriangles do + MainTriangles[i] := RotateTriangleXY(MainTriangles[i], 2, angle) + else //if RotateO.Checked then + for i in SyncTriangles do + MainTriangles[i] := RotateTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, angle); + end; + + HasChanged := True; + UpdateFlame(true); +end; + procedure TEditForm.btTrgRotateLeftClick(Sender: TObject); var angle: double; @@ -5168,32 +5452,18 @@ begin end; assert(angle <> 0); - if GetKeyState(VK_CONTROL) < 0 then angle := angle/6.0 - else if GetKeyState(VK_SHIFT) < 0 then angle := angle*6.0; + if GetKeyState(VK_CONTROL) < 0 then angle := angle / 6.0 + else if GetKeyState(VK_SHIFT) < 0 then angle := angle * 6.0; // AV: to show internally modified value if (ShowModVals.Checked) then txtTrgRotateValue.Text := Format('%.6g', [angle]); - MainForm.UpdateUndo; - if RotateXYO.Checked then - MainTriangles[SelectedTriangle] := - RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, (PI/180)*angle) - else if RotateX.Checked then - MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 0, (PI/180)*angle) - else if RotateY.Checked then - MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 2, (PI/180)*angle) - else //if RotateO.Checked then - MainTriangles[SelectedTriangle] := RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, (PI/180)*angle); - HasChanged := True; - UpdateFlame(true); + angle := PI/180 * angle; // AV + RotateTriangleBy(angle); // AV end; procedure TEditForm.btTrgRotateLeft90Click(Sender: TObject); begin - MainForm.UpdateUndo; - MainTriangles[SelectedTriangle] := - RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, PI/2); - HasChanged := True; - UpdateFlame(true); + RotateTriangleBy(PI/2); // AV end; procedure TEditForm.btTrgRotateRightClick(Sender: TObject); @@ -5213,30 +5483,13 @@ begin // AV: to show internally modified value if (ShowModVals.Checked) then txtTrgRotateValue.Text := Format('%.6g', [angle]); - MainForm.UpdateUndo; - if RotateXYO.Checked then - MainTriangles[SelectedTriangle] := - RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, -(PI/180)*angle) - else if RotateX.Checked then begin - MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 0, -(PI/180)*angle); - if tbAutoWeights.Down then cp.CalculateWeights; // AV - end else if RotateY.Checked then begin - MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 2, -(PI/180)*angle); - if tbAutoWeights.Down then cp.CalculateWeights; // AV - end else //if RotateO.Checked then - MainTriangles[SelectedTriangle] := RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, -(PI/180)*angle); - - HasChanged := True; - UpdateFlame(true); + angle := -PI/180 * angle; // AV + RotateTriangleBy(angle); // AV end; procedure TEditForm.btTrgRotateRight90Click(Sender: TObject); begin - MainForm.UpdateUndo; - MainTriangles[SelectedTriangle] := - RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, -PI/2); - HasChanged := True; - UpdateFlame(true); + RotateTriangleBy(-PI/2); // AV end; procedure TEditForm.PaintBackground; @@ -5247,7 +5500,7 @@ end; procedure TEditForm.TrgMove(dx, dy: double); var - i: integer; + i, j: smallint; offset: double; begin try @@ -5264,12 +5517,21 @@ begin if (ShowModVals.Checked) then txtTrgMoveValue.Text := Format('%.6g', [offset]); MainForm.UpdateUndo; - for i := 0 to 2 do begin - MainTriangles[SelectedTriangle].x[i] := + + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + for i := 0 to 2 do begin + MainTriangles[SelectedTriangle].x[i] := MainTriangles[SelectedTriangle].x[i] + dx*offset; - MainTriangles[SelectedTriangle].y[i] := + MainTriangles[SelectedTriangle].y[i] := MainTriangles[SelectedTriangle].y[i] + dy*offset; - end; + end + else + for j in SyncTriangles do + for i := 0 to 2 do begin + MainTriangles[j].x[i] := MainTriangles[j].x[i] + dx * offset; + MainTriangles[j].y[i] := MainTriangles[j].y[i] + dy * offset; + end; + // HasChanged := True; UpdateFlame(true); end; @@ -5321,6 +5583,7 @@ end; procedure TEditForm.btTrgScaleUpClick(Sender: TObject); var scale: double; + i: smallint; begin try scale := StrToFloat(txtTrgScaleValue.Text) / 100.0; @@ -5337,15 +5600,36 @@ begin if (ShowModVals.Checked) then txtTrgScaleValue.Text := Format('%.6g', [scale * 100.0]); MainForm.UpdateUndo; - if ScaleXYO.Checked then - MainTriangles[SelectedTriangle] := - ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale) + + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + begin + if ScaleXYO.Checked then + MainTriangles[SelectedTriangle] := + ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale) else if ScaleX.Checked then MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 0, scale) else if ScaleY.Checked then - MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 2, scale) - else //if ScaleO.Checked then - MainTriangles[SelectedTriangle] := ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale); + MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 2, scale) + else //if ScaleO.Checked then + MainTriangles[SelectedTriangle] := + ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale); + end + else begin + if ScaleXYO.Checked then + for i in SyncTriangles do + MainTriangles[i] := + ScaleTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, scale) + else if ScaleX.Checked then + for i in SyncTriangles do + MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 0, scale) + else if ScaleY.Checked then + for i in SyncTriangles do + MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 2, scale) + else //if ScaleO.Checked then begin + for i in SyncTriangles do + MainTriangles[i] := + ScaleTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, scale); + end; if tbAutoWeights.Down then cp.CalculateWeights; // AV HasChanged := True; @@ -5355,6 +5639,7 @@ end; procedure TEditForm.btTrgScaleDownClick(Sender: TObject); var scale: double; + i: smallint; begin try scale := 100.0 / StrToFloat(txtTrgScaleValue.Text); @@ -5371,15 +5656,37 @@ begin if (ShowModVals.Checked) then txtTrgScaleValue.Text := Format('%.6g', [scale * 100.0]); MainForm.UpdateUndo; - if ScaleXYO.Checked then - MainTriangles[SelectedTriangle] := - ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale) - else if ScaleX.Checked then - MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 0, scale) - else if ScaleY.Checked then + + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + begin + if ScaleXYO.Checked then + MainTriangles[SelectedTriangle] := + ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale) + else if ScaleX.Checked then + MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 0, scale) + else if ScaleY.Checked then MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 2, scale) - else //if ScaleO.Checked then - MainTriangles[SelectedTriangle] := ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale); + else //if ScaleO.Checked then + MainTriangles[SelectedTriangle] := + ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale); + end + else begin + if ScaleXYO.Checked then + for i in SyncTriangles do + MainTriangles[i] := + ScaleTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, scale) + else if ScaleX.Checked then + for i in SyncTriangles do + MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 0, scale) + else if ScaleY.Checked then + for i in SyncTriangles do + MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 2, scale) + else //if ScaleO.Checked then begin + for i in SyncTriangles do + MainTriangles[i] := + ScaleTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, scale); + end; + if tbAutoWeights.Down then cp.CalculateWeights; // AV HasChanged := True; UpdateFlame(true); @@ -5535,8 +5842,8 @@ end; procedure TEditForm.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - var num: double; - begin +var num: double; +begin case key of VK_ADD: if SelectedTriangle < LastTriangle then begin @@ -5579,11 +5886,16 @@ procedure TEditForm.EditKeyDown(Sender: TObject; var Key: Word; RotateO.Checked := True; end; Ord('A'): - if (not txtName.Focused) and (not txtSearchBox.Focused) then - begin - ScaleXYO.Checked := True; - RotateXYO.Checked := True; - end; + if (not txtName.Focused) and (not txtSearchBox.Focused) then + begin + ScaleXYO.Checked := True; + RotateXYO.Checked := True; + end; + Ord('M'): + if (not txtName.Focused) and (not txtSearchBox.Focused) then + begin + mnuCalcExpression.Click; + end; else key_handled := false; exit; @@ -5595,13 +5907,18 @@ end; procedure TEditForm.EditKeyPress(Sender: TObject; var Key: Char); begin if txtName.Focused then begin - if (key = '+') or (key='-') then begin + { + if (key = '+') or (key='-') then begin // nvm...code moved to EditKeyDown key := #0; end; if (key='"') then key := #0; // we dont want that in "name" box -> XML mess! + } + // AV: we also don't want XML-tag's brackets here + if CharInSet(Key,['+', '-', '"', '<', '>']) then key := #0; exit; - end else if txtSearchBox.Focused then + end + else if txtSearchBox.Focused then begin if (key = #13) then key := #0; // AV: to prevent a beep exit; @@ -5613,7 +5930,7 @@ begin { AV: a lot of users type comma as the decimal separator, but Apo discard it. It's not normally... } if (Key = ',') then Key := '.'; // FormatSettings.DecimalSeparator; - if key_handled or not CharinSet(Key,['0'..'9', '-', #8, #13, '.']) + if key_handled or not CharInSet(Key,['0'..'9', '-', #8, #13, '.']) then Key:= #0; end; @@ -5641,6 +5958,30 @@ begin SetCursorPos(MousePos.x, MousePos.y); end; +procedure TEditForm.tbSyncTrianglesClick(Sender: TObject); +begin + UseTriangleSync := not UseTriangleSync; + AdjustSyncTriangles; +end; + +procedure TEditForm.AdjustSyncTriangles; +begin + if UseTriangleSync then begin + tbSyncTriangles.Style := tbsDropDown; + tbSyncTriangles.DropdownMenu := mnuSyncTriangles; + TriangleToolBar.Perform(CM_CONTROLCHANGE, WPARAM(tbSyncTriangles), 36); + tbSyncTriangles.ImageIndex := 44; + tbSyncTriangles.Hint := TextByKey('editor-tab-triangle-enablesync'); + end + else begin + tbSyncTriangles.Style := tbsButton; + tbSyncTriangles.DropdownMenu := nil; + TriangleToolBar.Perform(CM_CONTROLCHANGE, WPARAM(tbSyncTriangles), 23); + tbSyncTriangles.ImageIndex := 43; + tbSyncTriangles.Hint := TextByKey('editor-tab-triangle-disablesync'); + end; +end; + procedure TEditForm.TriangleViewMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); var @@ -5753,6 +6094,16 @@ begin tbAxisLock.Down := AxisLock; end; +procedure TEditForm.tbCommentClick(Sender: TObject); +begin + CommentForm.memComment.Lines.Text := cp.comment; + if CommentForm.ShowModal = mrOK then + begin + cp.comment := Trim(CommentForm.memComment.Lines.Text); + MainCp.comment := cp.comment; + end; +end; + procedure TEditForm.tbFullViewClick(Sender: TObject); begin MainForm.mnuFullScreenClick(Sender); @@ -5807,8 +6158,6 @@ begin end; {$endif} - //chkCollapseVariationsClick(nil); - //chkCollapseVariablesClick(nil); end; procedure TEditForm.vleVariablesExit(Sender: TObject); @@ -5867,6 +6216,7 @@ end; procedure TEditForm.mnuResetAllClick(Sender: TObject); var i: integer; + saved: boolean; begin MainForm.UpdateUndo; for i := 0 to Transforms do cp.xform[i].Clear; @@ -5889,7 +6239,7 @@ begin cp.cameraDOF := 0; Transforms := 1; - SelectedTriangle := 1; + SelectedTriangle := 0; // AV: fixed - was 1; MainTriangles[0] := MainTriangles[-1]; MainTriangles[1] := MainTriangles[-1]; // kinda reset finalxform @@ -5904,14 +6254,44 @@ begin if AutoSaveXML then // AV: create a flame from scratch if needed begin MainCp.name := 'New flame' + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); - if MainForm.SaveXMLFlame(MainCp, MainCp.name, OpenFile) then - if MainForm.SortFlames.Checked then - ListXML(OpenFile, 2, MainCp.name) // show the new item - else - ListXML(OpenFile, 0); // show the last item + if (OpenFileType = ftXML) then + saved := MainForm.SaveXMLFlame(MainCp, MainCp.name, OpenFile) + else + saved := MainForm.SaveFlame(MainCp, MainCp.name, OpenFile); + if saved then MainForm.AddFlameToList; // AV: show the new item end; end; +procedure TEditForm.SaveFlameStateClick(Sender: TObject); // AV +{ Saves current flame into opened file and adds it to list view } +var + n: word; + FItem: TListItem; + Ftitle: string; + saved: boolean; +begin + n := 0; // + for FItem in MainForm.ListView1.Items do + if pos(MainCp.name, FItem.Caption) = 1 then inc(n); + + if (n = 0) then + Ftitle := MainCp.name // current flame is not in the list + else begin + Ftitle := MainCp.name + ' (' + IntToStr(n) + ')'; + + Fitem := MainForm.ListView1.FindCaption(0, FTitle, false, true, false); + if FItem <> nil then // we already have a flame with the same name + Ftitle := MainCp.name + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); + end; + + if (OpenFileType = ftXML) then + saved := MainForm.SaveXMLFlame(MainCp, Ftitle, OpenFile) + else + saved := MainForm.SaveFlame(MainCp, Ftitle, OpenFile); + if saved then + MainForm.AddFlameToList(Ftitle); // show the new item +end; + // ----------------------------------------------------------------------------- procedure TEditForm.btnXcoefsClick(Sender: TObject); @@ -6285,31 +6665,36 @@ begin VEVars.canvas.brush.Color := col; VEVars.canvas.fillRect(Rect); VEVars.canvas.TextOut(Rect.Left+2, Rect.Top+2, VEVars.Cells[ACol,ARow]); - end else col := VEVars.canvas.brush.color; - if (Acol = 0) and (Arow > 0) then begin + end + else col := VEVars.canvas.brush.color; + + if (Acol = 0) and (Arow > 0) then + begin VEVars.Canvas.Font.Name := 'Arial'; VEVars.Canvas.Font.Size := 5; - VarSupports(i, supports3D, supportsDC); // Arow - 1 + supports3D := VarSupports3D(i); // i <-- (Arow - 1) + supportsDC := VarSupportsDC(i); // AV: separate methods - frect.Left := Rect.Right - 12; - frect.Right := Rect.Right; - frect.Top := Rect.Top; - frect.Bottom := Rect.Bottom; + if (supports3D or supportsDC) then // AV: optimized calculations + begin + frect.Left := Rect.Right - 12; + frect.Right := Rect.Right; + frect.Top := Rect.Top; + frect.Bottom := Rect.Bottom; - if (supports3D or supportsDC) then begin VEVars.canvas.brush.Color := col; VEVars.canvas.fillRect(frect); - end; - - if (supports3D) then begin - VEVars.Canvas.Font.Color := $a00000; - VEVars.Canvas.TextOut(frect.Left, frect.Top + 2, '3D'); - end; - if (supportsDC) then begin - VEVars.Canvas.Font.Color := $0000a0; - VEVars.Canvas.TextOut(frect.Left, frect.Top + 9, 'DC'); + if (supports3D) then begin + VEVars.Canvas.Font.Color := $a00000; + VEVars.Canvas.TextOut(frect.Left, frect.Top + 2, '3D'); + end; + + if (supportsDC) then begin + VEVars.Canvas.Font.Color := $0000a0; + VEVars.Canvas.TextOut(frect.Left, frect.Top + 9, 'DC'); + end; end; end; end; @@ -6335,6 +6720,7 @@ begin cp.finalXformEnabled := EnableFinalXform; UpdateFlame(True); TriangleView.Invalidate; + UpdateSyncTriangles; // AV end; procedure TEditForm.DragPanelMouseDown(Sender: TObject; @@ -6758,7 +7144,7 @@ procedure TEditForm.btnCopyTriangleClick(Sender: TObject); begin MemTriangle := MainTriangles[SelectedTriangle]; tbPasteTriangle.Enabled := True; - PasteTriangleCoordinates1.Enabled := True; + PasteTriangleCoordinates.Enabled := True; end; procedure TEditForm.btnFlipClick(Sender: TObject); @@ -6777,10 +7163,7 @@ begin end; if (px = fx) and (py = fy) then exit; MainForm.UpdateUndo; - //if (px = fx) then MainTriangles[SelectedTriangle] := - // FlipTriangleHorizontal(MainTriangles[SelectedTriangle]) - //else if (py = fy) then MainTriangles[SelectedTriangle] := - // FlipTriangleVertical(MainTriangles[SelectedTriangle]) else + MainTriangles[SelectedTriangle] := FlipTriangleLine(MainTriangles[SelectedTriangle], px, py, fx, fy); UpdateFlame(true); @@ -6923,6 +7306,37 @@ begin //ShowSelectedInfo; end; +procedure TEditForm.mnuCopyChaosClick(Sender: TObject); +var i: smallint; +begin + SetLength(MemChaos, NXFORMS); + if mnuChaosViewTo.Checked then + for i := 0 to high(MemChaos) do + MemChaos[i] := cp.xform[SelectedTriangle].modWeights[i] + else + for i := 0 to high(MemChaos) do + MemChaos[i] := cp.xform[i].modWeights[SelectedTriangle]; + + mnuPasteChaos.Enabled := True; + PasteChaos.Enabled := True; +end; + +procedure TEditForm.mnuPasteChaosClick(Sender: TObject); +var i, t: smallint; +begin + MainForm.UpdateUndo; + if mnuChaosViewTo.Checked then + for t in SyncTriangles do + for i := 0 to high(MemChaos) do + cp.xform[t].modWeights[i] := MemChaos[i] + else + for t in SyncTriangles do + for i := 0 to high(MemChaos) do + cp.xform[i].modWeights[t] := MemChaos[i]; + UpdateFlame(true); + if ChaosForm.Visible then ChaosForm.ChaosMatrix.Invalidate; +end; + (* procedure TEditForm.chkPlotModeClick(Sender: TObject); var newMode: boolean; @@ -7143,11 +7557,13 @@ procedure TEditForm.chkCollapseVariationsClick(Sender: TObject); var i: integer; s: string; + IsSupport: boolean; begin s := Trim(txtSearchBox.Text); for i := 1 to VEVars.RowCount - 1 do begin - if (Length(s) = 0) then + if (Length(s) = 0) or ((Length(s) <= Length(VEVars.Cells[0, i])) and + (Pos(s, VEVars.Cells[0, i]) > 0)) then // AV: search text is not empty begin case cbCollapseVariations.ItemIndex of 0: VEVars.RowHeights[i] := VEVars.DefaultRowHeight; // all @@ -7159,31 +7575,23 @@ begin 2: VEVars.RowHeights[i] := // favourites IfThen(FavouriteVariations[GetVariationIndex(VEVars.Cells[0,i])], // i-1 VEVars.DefaultRowHeight, -1); + 3: // 3D + begin + IsSupport := VarSupports3D(GetVariationIndex(VEVars.Cells[0,i])); + VEVars.RowHeights[i] := IfThen(IsSupport, VEVars.DefaultRowHeight, -1); + end; + 4: // DC + begin + IsSupport := VarSupportsDC(GetVariationIndex(VEVars.Cells[0,i])); + VEVars.RowHeights[i] := IfThen(IsSupport, VEVars.DefaultRowHeight, -1); + end; end; end - else begin // AV: search text is not empty - if (Length(s) > Length(VEVars.Cells[0, i])) then - VEVars.RowHeights[i] := -1 - else if Pos(s, VEVars.Cells[0, i]) > 0 then - begin - case cbCollapseVariations.ItemIndex of - 0: VEVars.RowHeights[i] := VEVars.DefaultRowHeight; // all - 1: if Assigned(cp) then - VEVars.RowHeights[i] := // active - IfThen((VEVars.Cells[1,i] = '0'), -1, VEVars.DefaultRowHeight) - else - VEVars.RowHeights[i] := -1; - 2: VEVars.RowHeights[i] := // favourites - IfThen(FavouriteVariations[GetVariationIndex(VEVars.Cells[0,i])], - VEVars.DefaultRowHeight, -1); - end; - end - else + else VEVars.RowHeights[i] := -1; - end; end; -{ + { s := Trim(txtSearchBox.Text); for i:= 1 to VEVars.RowCount - 1 do begin @@ -7214,7 +7622,7 @@ begin VEVars.RowHeights[i] := -1; end; end; -} + } end; procedure TEditForm.chkCollapseVariablesClick(Sender: TObject); @@ -7354,9 +7762,9 @@ end; procedure TEditForm.ColorBarMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var - dx: double; //Extended; + dx: double; begin - // dx := Round(100 * X / ColorBar.Width) / 100; // AV: it's not correct + // dx := Round(100 * X / ColorBar.Width) / 100; // <-- AV: it's not correct dx := X / (ColorBarPicture.Width - 1); // AV: this gives the best results txtXFormColor.Text := FloatToStrF(dx, ffFixed, 4, 3); // AV: default presision txtXFormColorExit(nil); @@ -7399,7 +7807,6 @@ begin Key := #0; txtNameExit(sender); end; - end; procedure TEditForm.txtNameExit(Sender: TObject); @@ -7435,10 +7842,10 @@ end; procedure TEditForm.TrianglePanelResize(Sender: TObject); begin - GroupBox5.Left := (TrianglePanel.CLientWidth - GroupBox5.Width) div 2; - GroupBox6.Left := (TrianglePanel.CLientWidth - GroupBox6.Width) div 2; - GroupBox3.Left := (TrianglePanel.CLientWidth - GroupBox3.Width) div 2; - GroupBox10.Left := (TrianglePanel.CLientWidth - GroupBox10.Width) div 2; + gbTrgOperations.Left := (TrianglePanel.CLientWidth - gbTrgOperations.Width) div 2; + gbCoordinates.Left := (TrianglePanel.CLientWidth - gbCoordinates.Width) div 2; + gbPivot.Left := (TrianglePanel.CLientWidth - gbPivot.Width) div 2; + gbFlip.Left := (TrianglePanel.CLientWidth - gbFlip.Width) div 2; TriangleToolBar.Left := (TrianglePanel.CLientWidth - TriangleToolBar.Width) div 2; end; @@ -7450,28 +7857,52 @@ begin PageControl.Height := ControlPanel.Height - PageControl.Top; end; -procedure TEditForm.Copytransform1Click(Sender: TObject); -var txt: string; +procedure TEditForm.CopyTransformClick(Sender: TObject); +var + txt: string; + i, n: byte; begin MemCp.Clear; MemCp.Name := 'Memorized XForm Parameters'; - MemCp.xform[0].Assign(cp.xform[SelectedTriangle]); - txt := Trim(MainForm.RetrieveXML(MemCp)); + if (not UseTriangleSync) or (SelectedTriangle = Transforms) then + MemCp.xform[0].Assign(cp.xform[SelectedTriangle]) + else begin // AV: copy all selected transforms + n := 0; + for i in SyncTriangles do + begin + MemCp.xform[n].Assign(cp.xform[i]); + inc(n); + end; + end; + txt := Trim(FlameToXML(MemCp)); Clipboard.SetTextBuf(PChar(txt)); - Pastetransform1.Enabled := True; + PasteTransform.Enabled := True; MainForm.mnuPaste.Enabled := False; end; -procedure TEditForm.Pastetransform1Click(Sender: TObject); +procedure TEditForm.CopyVariationsClick(Sender: TObject); +begin + try + VEVars.Strings.SaveToFile(APPDATA + saved_variations); + VLEVariables.Strings.SaveToFile(APPDATA + saved_variables); + PasteVariations.Enabled := True; + except + // TODO + PasteVariations.Enabled := False; + end; +end; + +procedure TEditForm.PasteTransformClick(Sender: TObject); var TempTriangles: TTriangles; - i: integer; + i, t: smallint; begin - if (MemCp.NumXForms > 0) and (Transforms < NXFORMS) then + t := MemCp.NumXForms - 1; + if (t >= 0) and (Transforms + t < NXFORMS) then begin MainForm.UpdateUndo; MemCp.TrianglesFromCP(TempTriangles); - for i := 0 to MemCp.NumXForms - 1 do + for i := 0 to t do begin MainTriangles[Transforms+1] := MainTriangles[Transforms]; cp.xform[Transforms+1].Assign(cp.xform[Transforms]); @@ -7485,6 +7916,59 @@ begin end; end; +procedure TEditForm.PasteVariationsClick(Sender: TObject); +var + i: integer; + v: double; + s: string; +begin + MainForm.UpdateUndo; + try + VEVars.Strings.LoadFromFile(APPDATA + saved_variations); + for i := 0 to NrVar-1 do + begin + s := VEVars.Strings.Names[i]; + cp.xform[SelectedTriangle].SetVariation(GetVariationIndex(s), + StrToFloat(VEVars.Strings.Values[s])); + cp.xform[SelectedTriangle].ifs[i] := s; + end; + + VLEVariables.Strings.LoadFromFile(APPDATA + saved_variables); + for i := 0 to GetNrVariableNames - 1 do + begin + v := StrToFloat(VLEVariables.Strings.ValueFromIndex[i]); + cp.xform[SelectedTriangle].SetVariable(VLEVariables.Strings.Names[i], v); + end; + + UpdateFlame(true); + except + // restore defaults? + cp.xform[SelectedTriangle].SetVariation(0, 1); + cp.xform[SelectedTriangle].ifs[0] := 'linear'; + VEVars.Strings.BeginUpdate; + VEVars.Strings[0] := 'linear=1'; + for i := 1 to NrVar-1 do + begin + s := VarNames(i); + cp.xform[SelectedTriangle].SetVariation(i, 0); + cp.xform[SelectedTriangle].ifs[i] := s; + VEVars.Strings[i] := s + '=0'; + end; + VEVars.Strings.EndUpdate; + + VLEVariables.Strings.BeginUpdate; + for i := 0 to GetNrVariableNames - 1 do + begin + s := GetVariableNameAt(i); + cp.xform[SelectedTriangle].ResetVariable(s); + VLEVariables.Strings[i] := s + '=' + cp.xform[SelectedTriangle].GetVariableStr(s); + end; + VLEVariables.Strings.EndUpdate; + + UpdateFlame(true); + end; +end; + procedure TEditForm.ScrollBox2Resize(Sender: TObject); begin // AV: done GroupBox1.Left := (ScrollBox2.ClientWidth - GroupBox1.Width) div 2; @@ -7549,6 +8033,7 @@ begin tbExtendedEdit.Down := ExtEditEnabled; tbAxisLock.Down := TransformAxisLock; mnuChaosRebuild.Checked := RebuildXaosLinks; + AdjustSyncTriangles; // AV chkCollapseVariationsClick(nil); end; diff --git a/Forms/FlameComment.dfm b/Forms/FlameComment.dfm new file mode 100644 index 0000000..add08fd --- /dev/null +++ b/Forms/FlameComment.dfm @@ -0,0 +1,303 @@ +object CommentForm: TCommentForm + Left = 0 + Top = 0 + BorderStyle = bsSingle + Caption = 'Edit Flame Comment' + ClientHeight = 172 + ClientWidth = 459 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + Icon.Data = { + 0000010001001616000000000000100800001600000028000000160000002C00 + 000001002000000000009007000000000000000000000000000000000000FFFF + FF00000000070000002100000026000000260000002600000026000000260000 + 0026000000260000002600000026000000260000002600000026000000260000 + 002600000026000000260000002100000007FFFFFF00000000020000001C3133 + 325E818583C58B918FFD8B908EFF8B908EFF8B908EFF8A908DFF8A8F8DFF8A8F + 8DFF8A8F8DFF898E8CFF898E8CFF898E8CFF888E8CFF888D8BFF898E8CFD7E82 + 80C52F32305E0000001C00000002FFFFFF00000000078A908DB9D9DBDAFFFEFE + FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFEFFD9DBDAFF878C8AB90000 + 0007FFFFFF00FFFFFF00FFFFFF008F9593FCFEFEFEFFEBEEEDFFEAEDECFFEBEE + ECFFECEEEDFFECEFEEFFEDF0EFFFEEF0F0FFEFF1F0FFEFF1F0FFEFF1F1FFEFF1 + F1FFEFF1F1FFEFF1F0FFF0F1F1FFFEFEFEFF8B908EFCFFFFFF00FFFFFF00FFFF + FF00FFFFFF00909593FFFFFFFFFFEAEDECFFEBEEEDFF9AAAB4FF22313CFF6E8B + 9FFFB9C9D2FFD8DADAFFE4E6E5FFF1F2F2FFF2F4F3FFF2F4F3FFF2F3F3FFF1F3 + F2FFF0F2F2FFFFFFFFFF8B908EFFFFFFFF00FFFFFF00FFFFFF00FFFFFF009196 + 94FFFFFFFFFFEAEDECFFD0D3D2FFC7C9CAFF223542FF6A9FC4FF6DB5E8FF67B3 + E6FF668EB8FFA7A8A8FFC0C1C1FFE7E8E8FFF0F1F1FFF2F3F3FFF1F3F2FFFFFF + FFFF8C9290FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00929895FFFFFFFFFFE9EC + EBFFEAEDECFFEBEEEDFF97C6E9FF8BC4ECFFFFFFFFFF8CBFEEFF1569D0FF7D9E + C5FFCBCCCCFFD5D7D6FFDFE0E0FFEAECECFFEFF1F1FFFFFFFFFF8E9391FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00939997FFFFFFFFFFE8EBEAFFCFD1D0FFC7CA + C9FFBAC6CDFF6BB5E8FFA2D7FCFF4EAAF3FF549DE7FF1669D0FF7A9AC0FFB7B8 + B8FFBCBDBCFFCDCFCEFFEDF0EFFFFFFFFFFF8F9492FFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00959A98FFFFFFFFFFE6EAE9FFE7EBE9FFE8EBEAFFE9ECEBFF72A9 + E0FF2B7DDAFF6BBFFBFF4CAAF3FF549DE7FF176AD1FF9DBDE2FFE8EBEAFFE8EB + EAFFEBEDECFFFFFFFFFF909693FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00969B + 99FFFFFFFFFFE4E8E7FFCBCFCDFFC4C6C5FFC4C7C5FFC5C7C6FF5C90CBFF2A7C + D9FF6CBFFBFF4DAAF3FF539DE7FF1669D0FF85A5C8FFCED0CFFFE8EBEAFFFFFF + FFFF919795FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00979D9AFFFFFFFFFFE2E7 + E5FFE3E7E5FFE3E7E6FFE4E8E6FFE4E8E7FFE5E9E7FF689EDAFF2B7DDAFF6CBF + FBFF4DAAF3FF539CE7FF146AD1FF9EBDDFFFE5E9E7FFFFFFFFFF939896FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00989E9CFFFFFFFFFFE0E5E2FFC7CBC9FFBFC3 + C1FFBFC4C2FFC0C4C2FFC0C4C2FFC0C5C3FF558CC9FF2A7CD9FF6CC0FBFF4DAA + F3FF529CE7FF1368D0FF9DBDDDFFFFFFFFFF949997FFFFFFFF00FFFFFF00FFFF + FF00FFFFFF009A9F9DFFFFFFFFFFDFE4E2FFE0E5E2FFE0E4E2FFDFE5E2FFE0E5 + E2FFDFE4E2FFDFE4E2FFDFE4E2FF6198D7FF2B7FDBFF6CC0FBFF4DAAF3FF529C + E6FF1469D1FFA5BAD1FF959B98FFFFFFFF00FFFFFF00FFFFFF00FFFFFF009BA1 + 9EFFFFFFFFFFE0E4E3FFC7CBC8FFBEC3C0FFBFC2C0FFBEC3C0FFBDC2BFFFBDC1 + BFFFBDC1BFFFBCC0BFFF4F87C8FF2A7CD9FF6DC0FBFF4DAAF3FF5998D9FF858A + 88FF77899BFDFFFFFF00FFFFFF00FFFFFF00FFFFFF009CA29FFFFFFFFFFFE0E5 + E3FFE0E5E2FFE0E5E2FFDFE4E2FFDFE4E1FFDEE3E1FFDEE3E1FFDDE2E0FFDCE2 + DFFFDBE1DEFF5791D2FF2B7ED9FF6DC0FBFF6C99BAFF828787FF858A90FF6064 + B087FFFFFF00FFFFFF00FFFFFF009DA3A1FFFFFFFFFFE1E6E4FFC7CBC9FFBFC3 + C1FFBEC3C1FFBEC2C0FFBEC1BFFFBCC0BFFFBBC0BEFFBABFBDFFBFC4C2FFAEB1 + AFFF6280A1FF838A8DFF92999BFFAEAFAFFF808388FF5355C2FA2828EE4DFFFF + FF00FFFFFF009EA5A2FFFFFFFFFFE2E7E4FFE2E6E4FFE1E6E4FFE0E5E3FFE0E5 + E2FFDEE4E1FFDDE3E0FFDCE1DFFFDAE0DEFFD9DFDDFFB9BEBCFFFEFEFEFF7A8C + A7FF999DA2FFAFB2B5FF818594FE6D6DDDFF3131EED0FFFFFF00FFFFFF00A0A6 + A3FFFFFFFFFFE4E8E6FFC9CECBFFC0C5C2FFBFC4C1FFBFC3C0FFBDC1BFFFBCC1 + BFFFBDC2C0FFC4C9C6FFC6CCC9FFB5BAB7FFFFFFFFFFFDFDFDFF797CB1FE5E61 + B7FE7778CEFF6868EDFF3030F0C8FFFFFF00FFFFFF00A1A7A4FFFFFFFFFFE6EA + E8FFE5E9E7FFE4E8E6FFE2E7E5FFE1E6E3FFDFE4E1FFDDE3E0FFDBE1DEFFDAE0 + DDFFCAD0CDFFCCCECDFFFFFFFFFFDBDDDDFD9FA5A3D02E2EEAA02C2CEDF52E2E + EDDD2B2BEF30FFFFFF00FFFFFF00A2A9A6FCFEFEFEFFEBEFEDFFE7EBE9FFE6EA + E8FFE4E8E6FFE2E7E4FFE0E5E3FFE1E6E4FFE6EAE8FFEBEFEDFFE9EAEAFFF5F6 + F5FFCCD0CEF7A0A7A4D89EA4A213FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00A6ADAAAEDBDEDDFFFEFEFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFCFCFCFFF0F2F1FFE4E7E6FFCFD3D1F8A2A8A6E9A0A6A45EA0A6 + A302FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A5AB + A821A7AEABAEA4AAA8FCA4AAA7FFA4AAA7FFA3AAA7FFA3A9A7FFA3A9A6FFA4AA + A7F5A5ABA9D2A4AAA8A0A2A8A561A1A8A506FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E0001F00C0000F00C0000F00C000 + 0F00C0000F00C0000F00C0000F00C0000F00C0000F00C0000F00C0000F00C000 + 0F00C0000F00C0000700C0000700C0000300C0000300C0000700C0007F00C001 + FF00E007FF00} + OldCreateOrder = False + OnCreate = FormCreate + DesignSize = ( + 459 + 172) + PixelsPerInch = 96 + TextHeight = 13 + object btnCopy: TSpeedButton + Left = 8 + Top = 58 + Width = 23 + Height = 22 + Hint = 'Copy gradient to clipboard' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00E39A6F00FFFFFF00E3996C00E2996D00E3996D00FFFFFF000000 + 0000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00FFFFFF00FFFFFF00000000000000000000000000000000000000 + 000000000000000000000000000000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00E2956600E393630000000000FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00FFFFFF00FFFFFF0000000000FFFFFF00E39A6F00FFFFFF00E399 + 6C00E2996D00E3996D00FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00E3915F00E28C580000000000FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00FFFFFF00FFFFFF0000000000FFFFFF00E2956600E3936300FFFF + FF00E3926200E2936300FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00E2916000FFFFFF0000000000FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 0000FFFFFF00FFFFFF00FFFFFF0000000000FFFFFF00E3915F00E28C5800FFFF + FF00FFFFFF00E2936400FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 000000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF + FF0000000000000000000000000000000000FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF0000000000FFFFFF00E2916000FFFFFF00FFFF + FF0000000000FFFFFF0000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF0000000000FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00000000000000000000000000000000000000 + 000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00} + ParentShowHint = False + ShowHint = True + Transparent = False + OnClick = btnCopyClick + end + object btnPaste: TSpeedButton + Left = 8 + Top = 82 + Width = 23 + Height = 22 + Hint = 'Copy gradient to clipboard' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF000000000000000000000000000000 + 00000000000000000000000000000000000000000000FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF0000000000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF0000000000FFFFFF00E39A6F00FFFF + FF00E3996C00E2996D00E3996D00FFFFFF0000000000FF00FF00FF00FF00FF00 + FF000000000000000000000000000000000000000000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00E2956600E393 + 6300FFFFFF00E3926200E2936300FFFFFF0000000000FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00E3915F00E28C + 5800FFFFFF00FFFFFF00E2936400FFFFFF0000000000FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00FFFFFF00FFFF + FF00FFFFFF0000000000000000000000000000000000FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00E2916000FFFF + FF00FFFFFF0000000000FFFFFF0000000000FF00FF00FF00FF00FF00FF000000 + 000056B9F50056B9F50056B9F50056B9F50000000000FFFFFF00FFFFFF00FFFF + FF00FFFFFF000000000000000000FF00FF00FF00FF00FF00FF00FF00FF000000 + 000056B9F5000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000FF00FF00FF00FF00FF00FF00FF00FF000000 + 000056B9F50000000000BBE5F900BBE5F900BBE5F900BBE5F900BBE5F900BBE5 + F9000000000056B9F50000000000FF00FF00FF00FF00FF00FF00FF00FF000000 + 000056B9F50056B9F50000000000BBE5F9000000000000000000BBE5F9000000 + 000056B9F50056B9F50000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF0000000000000000000000000000000000BBE5F900BBE5F900000000000000 + 00000000000000000000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF0000000000000000000000000000000000FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00} + ParentShowHint = False + ShowHint = True + Transparent = False + OnClick = btnPasteClick + end + object btnCut: TSpeedButton + Left = 8 + Top = 34 + Width = 23 + Height = 22 + Hint = 'Copy gradient to clipboard' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00BBA19400975F450063423200A28D8200FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00CD866300AB623F008A50330062453700BDBDBE00B99F92006643 + 34005E3F3000A8918600FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00DD835500C3B2AA00B89C8E00854E3300C0C0C000C5826100AA62 + 3E00633C29002F252300FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00E1855700C5B3AA00BDAEA8008C523500BCB8B600D47C5200C2B2 + AA00AE9486006B422D00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00DA987600E5865600B06641008F5538009C725D00C9754D00C1B9 + B500BA9E90008F553600FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00C8B5AC00EB8E5D00DB8256009F5F400094604700BE744F00D57B + 4F00B96B4500AD877400FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00C8B6AE00DE997600DF845600C68D7000CC784D00D27C + 5100C6917700BDA79C00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00887366007160560086675500AB9E + 9900FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00B8B4B1008E8074007E6E6300695D55007672 + 6E00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00BAB0AA00A2948B00A8A099008E817700635B + 5500FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00BEB1AA00A1948B00C8C6C400CDC5C0006B5F + 5600ADADAE00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00A99B9200B2A8A300C3C3C300E8E4E2007C6F + 6600A8A9AA00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00BBB8B600A3968C00BCBAB900FF00FF00DDDCDC00BCB2 + AB00A6A19E00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00BFB8B300B3A89E00FF00FF00FF00FF00CBCBCB00E2DD + DA00A1979000FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00} + ParentShowHint = False + ShowHint = True + Transparent = False + OnClick = btnCutClick + end + object btnUndo: TSpeedButton + Left = 8 + Top = 10 + Width = 23 + Height = 22 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000000000000000000000000000000000000FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FBD7 + C500F8D5C300FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00F8DC + CF00F38A5700E1957100FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00EECBBA00F0855000DA865E00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00CA805C00F0885500EAC8B700FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00E1CDC300DB784700EF936700FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF008A462500954C2800A4542E00B65F3400C7693A00D6724000FF00 + FF00FF00FF00FF00FF00AE5C3600EC865200F2CFBD00FF00FF00FF00FF00FF00 + FF00FF00FF00954C2800DF733600EA824900F39A6A00F5B59400FF00FF00FF00 + FF00FF00FF00FF00FF00A3664800E9845200F7C2A700FF00FF00FF00FF00FF00 + FF00FF00FF00A3552E00EC824B00F38D5B00EC9C7600B6866F00E9D5CB00FF00 + FF00FF00FF00FF00FF00A9745900E1825400F7BE9E00FF00FF00FF00FF00FF00 + FF00FF00FF00B55F3400F39A6A00F49C7100F29465009D533000AA613B00DAB8 + A700FF00FF00F6C5AE009D644600DE805100F7BDA100FF00FF00FF00FF00FF00 + FF00FF00FF00C7693B00F7CAAE00FBDDCB00F4A37600F3946400B4623900B064 + 3E00BF816200BB846000A15E3900EE8B5A00F6C8B000FF00FF00FF00FF00FF00 + FF00FF00FF00D6724000FF00FF00FF00FF00FBDECF00F5A57E00F49D7200C973 + 4700B7663C00B6653D00E2815300F6BCA100F6CBB700FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FBDACA00F5A67E00F6B6 + 9600F5B28F00F6B09100F6C1A800F6C5AE00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FBE0 + D200F6C3A900F7CFBB00F9DBCD00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00 + FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00} + ParentShowHint = False + ShowHint = True + Transparent = False + OnClick = btnUndoClick + end + object memComment: TMemo + Left = 40 + Top = 8 + Width = 397 + Height = 113 + Lines.Strings = ( + '') + ScrollBars = ssBoth + TabOrder = 0 + OnKeyPress = memCommentKeyPress + end + object btnOK: TButton + Left = 246 + Top = 130 + Width = 93 + Height = 30 + Anchors = [akRight, akBottom] + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 1 + end + object btnCancel: TButton + Left = 345 + Top = 130 + Width = 92 + Height = 30 + Anchors = [akRight, akBottom] + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 2 + end +end diff --git a/Forms/FlameComment.pas b/Forms/FlameComment.pas new file mode 100644 index 0000000..0f9d0bf --- /dev/null +++ b/Forms/FlameComment.pas @@ -0,0 +1,76 @@ +{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } + +unit FlameComment; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, + System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, + Vcl.StdCtrls, Vcl.Buttons, Translation; + +type + TCommentForm = class(TForm) + memComment: TMemo; + btnOK: TButton; + btnCancel: TButton; + btnCopy: TSpeedButton; + btnPaste: TSpeedButton; + btnCut: TSpeedButton; + btnUndo: TSpeedButton; + procedure FormCreate(Sender: TObject); + procedure memCommentKeyPress(Sender: TObject; var Key: Char); + procedure btnUndoClick(Sender: TObject); + procedure btnCopyClick(Sender: TObject); + procedure btnPasteClick(Sender: TObject); + procedure btnCutClick(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + CommentForm: TCommentForm; + +implementation + +{$R *.dfm} + +procedure TCommentForm.btnCopyClick(Sender: TObject); +begin + memComment.CopyToClipboard; +end; + +procedure TCommentForm.btnCutClick(Sender: TObject); +begin + memComment.CutToClipboard; +end; + +procedure TCommentForm.btnPasteClick(Sender: TObject); +begin + memComment.PasteFromClipboard; +end; + +procedure TCommentForm.btnUndoClick(Sender: TObject); +begin + if memComment.CanUndo then memComment.Undo; +end; + +procedure TCommentForm.FormCreate(Sender: TObject); +begin + btnOK.Caption := TextByKey('common-ok'); + btnCancel.Caption := TextByKey('common-cancel'); + self.Caption := TextByKey('editor-common-editcomment'); + btnCopy.Hint := TextByKey('common-copy'); + btnPaste.Hint := TextByKey('common-paste'); + btnUndo.Hint := TextByKey('common-undo'); + btnCut.Hint := TextByKey('common-cut'); +end; + +procedure TCommentForm.memCommentKeyPress(Sender: TObject; var Key: Char); +begin + if (Key = '<') or (Key = '>') then Key := #0; // prevent XML-scanner errors +end; + +end. diff --git a/Forms/FormExport.dfm b/Forms/FormExport.dfm index ced4273..98701a9 100644 --- a/Forms/FormExport.dfm +++ b/Forms/FormExport.dfm @@ -128,6 +128,12 @@ object ExportDialog: TExportDialog Width = 337 Height = 21 Anchors = [akLeft, akTop, akRight] + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False TabOrder = 0 end end @@ -707,7 +713,7 @@ object ExportDialog: TExportDialog Filter = 'JPEG Image (*.jpg)|*.jpg|PPM Image (*.ppm)|*.ppm|PNG Images (*.p' + 'ng)|*.png' - Left = 464 - Top = 264 + Left = 424 + Top = 280 end end diff --git a/Forms/FormExport.pas b/Forms/FormExport.pas index 4b3d023..26bfc4f 100644 --- a/Forms/FormExport.pas +++ b/Forms/FormExport.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,7 +27,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, Buttons, ComCtrls, ExtCtrls, Translation; + StdCtrls, Buttons, ComCtrls, ExtCtrls; type TExportDialog = class(TForm) @@ -91,11 +91,11 @@ type FloatFormatSettings: TFormatSettings; public Filename: string; - ImageWidth, ImageHeight, Oversample, Batches, Strips: Integer; + ImageWidth, ImageHeight, Oversample: Integer; Sample_Density, Filter_Radius: double; Estimator, EstimatorMin, EstimatorCurve: double; GammaTreshold: double; - Jitters: integer; + // Batches, Jitters: Integer; end; var @@ -103,7 +103,8 @@ var Ratio: double; implementation -uses Global, Main, ShellAPI; + +uses Global, Main, ShellAPI, Translation; {$R *.DFM} @@ -111,14 +112,12 @@ procedure TExportDialog.btnBrowseClick(Sender: TObject); begin SaveDialog.InitialDir := ExtractFileDir(txtFilename.text); SaveDialog.Filename := txtFilename.Text; - case ExportFileFormat of - 0: SaveDialog.DefaultExt := 'jpg'; - 1: SaveDialog.DefaultExt := 'ppm'; + case ExportFileFormat of // AV: fixed + 1: SaveDialog.DefaultExt := 'jpg'; + 2: SaveDialog.DefaultExt := 'ppm'; + 3: SaveDialog.DefaultExt := 'png'; end; - SaveDialog.filterIndex := ExportFileFormat; - SaveDialog.Filter := Format('Portable Pixmap (*.ppm)|*.ppm|%s|*.jpg;*.jpeg|%s|*.png|%s|*.*', - [TextByKey('common-filter-jpeg'), TextByKey('common-filter-png'), - TextByKey('common-filter-allfiles')]); + SaveDialog.FilterIndex := ExportFileFormat; if SaveDialog.Execute then begin case SaveDialog.FilterIndex of @@ -144,11 +143,11 @@ begin txtOversample.text := IntToSTr(Oversample); udOversample.Position := Oversample; Ratio := ImageWidth / ImageHeight; - Batches := 1; + //Batches := 1; + //Jitters := 1; Estimator := 9.0; EstimatorMin := 0.0; EstimatorCurve := 0.4; - Jitters := 1; GammaTreshold := MainCP.gamma_threshold; //0.01; GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FloatFormatSettings); txtEstimator.Text := FloatToStr(Estimator, FloatFormatSettings); @@ -197,18 +196,12 @@ end; procedure TExportDialog.txtDensityChange(Sender: TObject); begin - try - Sample_Density := StrToFloat(txtDensity.Text); - except - end; + Sample_Density := StrToFloatDef(txtDensity.Text, 200); end; procedure TExportDialog.txtFilterRadiusChange(Sender: TObject); begin - try - Filter_Radius := StrToFloat(txtFilterRadius.Text); - except - end; + Filter_Radius := StrToFloatDef(txtFilterRadius.Text, 0.04); end; procedure TExportDialog.txtOversampleChange(Sender: TObject); @@ -217,46 +210,31 @@ begin txtOversample.Text := IntToStr(udOversample.Max); if StrToInt(txtOversample.Text) < udOversample.Min then txtOversample.Text := IntToStr(udOversample.Min); - try - Oversample := StrToInt(txtOversample.Text); - except - end; + + Oversample := StrToIntDef(txtOversample.Text, 2); end; procedure TExportDialog.txtEstimatorChange(Sender: TObject); begin Estimator := 0; - try - Estimator := StrToFloat(txtEstimator.Text, FloatFormatSettings); - except - end; + Estimator := StrToFloatDef(txtEstimator.Text, 0, FloatFormatSettings); end; procedure TExportDialog.txtEstimatorMinChange(Sender: TObject); begin EstimatorMin := 0; - try - EstimatorMin := StrToFloat(txtEstimatorMin.Text, FloatFormatSettings); - except - end; + EstimatorMin := StrToFloatDef(txtEstimatorMin.Text, 0, FloatFormatSettings); end; procedure TExportDialog.txtEstimatorCurveChange(Sender: TObject); begin EstimatorCurve := 0; - try - EstimatorCurve := StrToFloat(txtEstimatorCurve.Text, FloatFormatSettings); - except - end; + EstimatorCurve := StrToFloatDef(txtEstimatorCurve.Text, 0, FloatFormatSettings); end; procedure TExportDialog.txtGammaTresholdChange(Sender: TObject); begin - //GammaTreshold := 0.01; - try - GammaTreshold := StrToFloat(txtGammaTreshold.Text, FloatFormatSettings); - except - end; + GammaTreshold := StrToFloatDef(txtGammaTreshold.Text, 0.01, FloatFormatSettings); end; procedure TExportDialog.lblFlam3LinkClick(Sender: TObject); @@ -291,6 +269,9 @@ begin chkRender.Caption := TextByKey('export-paramoptions-dorender'); Label6.Caption := TextByKey('export-paramoptions-warningtitle'); Label15.Caption := TextByKey('export-paramoptions-warningtext'); + // AV: fixed the order and moved here here since the filter never changes + SaveDialog.Filter := Format('%s|*.jpg;*.jpeg|Portable Pixmap (*.ppm)|*.ppm|%s|*.png', + [TextByKey('common-filter-jpeg'), TextByKey('common-filter-png')]); end; procedure TExportDialog.Panel1Resize(Sender: TObject); diff --git a/Forms/FormExportC.dfm b/Forms/FormExportC.dfm deleted file mode 100644 index 929f1a4..0000000 --- a/Forms/FormExportC.dfm +++ /dev/null @@ -1,553 +0,0 @@ -object ExportCDialog: TExportCDialog - Left = 313 - Top = 276 - BorderStyle = bsDialog - Caption = 'Export Flame' - ClientHeight = 134 - ClientWidth = 496 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = False - Position = poScreenCenter - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 496 - 134) - PixelsPerInch = 96 - TextHeight = 13 - object btnOK: TButton - Left = 254 - Top = 98 - Width = 115 - Height = 25 - Anchors = [akTop, akRight] - Caption = '&OK' - Default = True - ModalResult = 1 - TabOrder = 0 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 376 - Top = 98 - Width = 111 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 1 - end - object GroupBox1: TGroupBox - Left = 8 - Top = 237 - Width = 481 - Height = 57 - Anchors = [akLeft, akTop, akRight] - Caption = ' Destination ' - TabOrder = 2 - Visible = False - DesignSize = ( - 481 - 57) - object btnBrowse: TSpeedButton - Left = 448 - Top = 19 - Width = 24 - Height = 24 - Hint = 'Browse...' - Anchors = [akTop, akRight] - Flat = True - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Arial' - Font.Style = [fsBold] - Glyph.Data = { - 36030000424D3603000000000000360000002800000010000000100000000100 - 18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF - FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF75848F66808F - 607987576E7B4E626F4456613948522E3A43252E351B222914191E0E12160E13 - 18FF00FFFF00FFFF00FF77879289A1AB6AB2D4008FCD008FCD008FCD048CC708 - 88BE0F82B4157CA91B779F1F7296224B5C87A2ABFF00FFFF00FF7A8A957EBED3 - 8AA4AE7EDCFF5FCFFF55CBFF4CC4FA41BCF537B3F02EAAEB24A0E5138CD42367 - 805E696DFF00FFFF00FF7D8E9879D2EC8BA4AD89C2CE71D8FF65D3FF5CCEFF51 - C9FE49C1FA3FB9F534B0EE29A8E91085CD224B5B98B2BAFF00FF80919C81D7EF - 7DC5E08CA6B080DDFE68D3FF67D4FF62D1FF58CDFF4EC7FC46BEF73BB6F231AC - EC2569817A95A1FF00FF83959F89DCF18CE2FF8DA8B18CBAC774D8FF67D4FF67 - D4FF67D4FF5FD0FF54CDFF4BC5FC41BBF72EA2DB51677498B2BA869AA392E1F2 - 98E8FD80C4DE8EA7B081DEFD84E0FF84E0FF84E0FF84E0FF81DFFF7BDDFF74D8 - FF6BD6FF56A9D18F9BA4889CA59AE6F39FEBFB98E8FE8BACB98BACB98AAAB788 - A6B386A3AF839FAA819AA67F95A17C919D7A8E99798B957788938BA0A8A0EAF6 - A6EEF99FEBFB98E8FE7ADAFF67D4FF67D4FF67D4FF67D4FF67D4FF67D4FF7788 - 93FF00FFFF00FFFF00FF8EA2ABA7EEF6ABF0F7A6EEF99FEBFB98E8FD71D4FB89 - 9EA78699A382949F7E909A7A8C97778893FF00FFFF00FFFF00FF8FA4ACA0D2DA - ABF0F7ABF0F7A6EEF99FEBFB8DA1AAB5CBD0FF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFBDCED48FA4AC8FA4AC8FA4AC8FA4AC8FA4ACB5CBD0FF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF - FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} - ParentFont = False - ParentShowHint = False - ShowHint = True - OnClick = btnBrowseClick - end - object Label10: TPanel - Left = 8 - Top = 20 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'File name' - ParentShowHint = False - ShowHint = True - TabOrder = 1 - end - object txtFilename: TEdit - Left = 112 - Top = 20 - Width = 337 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - end - end - object GroupBox3: TGroupBox - Left = 256 - Top = 10 - Width = 233 - Height = 79 - Anchors = [akTop, akRight] - Caption = ' Quality ' - TabOrder = 3 - DesignSize = ( - 233 - 79) - object udOversample: TUpDown - Left = 212 - Top = 44 - Width = 12 - Height = 21 - Anchors = [akTop, akRight] - Associate = txtOversample - Min = 1 - Max = 4 - Position = 2 - TabOrder = 2 - end - object Label5: TPanel - Left = 8 - Top = 20 - Width = 113 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Filter radius' - ParentShowHint = False - ShowHint = True - TabOrder = 3 - end - object txtFilterRadius: TEdit - Left = 120 - Top = 20 - Width = 105 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = txtFilterRadiusChange - end - object Label3: TPanel - Left = 8 - Top = 44 - Width = 113 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Oversample' - ParentShowHint = False - ShowHint = True - TabOrder = 4 - end - object txtOversample: TEdit - Left = 120 - Top = 44 - Width = 92 - Height = 21 - Anchors = [akLeft, akTop, akRight] - ReadOnly = True - TabOrder = 1 - Text = '2' - OnChange = txtOversampleChange - end - end - object GroupBox2: TGroupBox - Left = 8 - Top = 10 - Width = 241 - Height = 111 - Anchors = [akLeft, akTop, akRight] - Caption = ' Size ' - TabOrder = 4 - DesignSize = ( - 241 - 111) - object Label13: TLabel - Left = 184 - Top = 36 - Width = 26 - Height = 13 - Anchors = [akLeft, akTop, akRight] - Caption = 'pixels' - Visible = False - end - object Label16: TLabel - Left = 168 - Top = 22 - Width = 15 - Height = 36 - Anchors = [akLeft, akTop, akRight] - Caption = '}' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -32 - Font.Name = 'Times New Roman' - Font.Style = [] - ParentFont = False - Visible = False - end - object chkMaintain: TCheckBox - Left = 8 - Top = 76 - Width = 225 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Maintain aspect ratio' - Checked = True - State = cbChecked - TabOrder = 0 - OnClick = chkMaintainClick - end - object Label1: TPanel - Left = 8 - Top = 20 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Width' - ParentShowHint = False - ShowHint = True - TabOrder = 3 - end - object Label2: TPanel - Left = 8 - Top = 44 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Height' - ParentShowHint = False - ShowHint = True - TabOrder = 4 - end - object cbHeight: TComboBox - Left = 112 - Top = 44 - Width = 121 - Height = 21 - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 2 - OnChange = txtHeightChange - Items.Strings = ( - '200' - '240' - '480' - '600' - '768' - '1024' - '1200' - '2048' - '2400') - end - object cbWidth: TComboBox - Left = 112 - Top = 20 - Width = 121 - Height = 21 - Anchors = [akLeft, akTop, akRight] - ItemHeight = 13 - TabOrder = 1 - OnChange = txtWidthChange - Items.Strings = ( - '320' - '640' - '800' - '1024' - '1280' - '1600' - '1920' - '2048' - '2560' - '3200') - end - end - object GroupBox4: TGroupBox - Left = 8 - Top = 392 - Width = 377 - Height = 113 - Anchors = [akLeft, akTop, akRight] - Caption = ' Parameters ' - TabOrder = 5 - Visible = False - DesignSize = ( - 377 - 113) - object udStrips: TUpDown - Left = 172 - Top = 52 - Width = 12 - Height = 21 - Associate = txtStrips - Min = 1 - Max = 512 - Position = 1 - TabOrder = 2 - end - object Label7: TPanel - Left = 8 - Top = 20 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Buffer depth' - ParentShowHint = False - ShowHint = True - TabOrder = 7 - end - object Label8: TPanel - Left = 8 - Top = 52 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Strips' - ParentShowHint = False - ShowHint = True - TabOrder = 8 - end - object Label9: TPanel - Left = 8 - Top = 84 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'DE Radius' - ParentShowHint = False - ShowHint = True - TabOrder = 9 - end - object txtEstimator: TEdit - Left = 112 - Top = 84 - Width = 73 - Height = 21 - TabOrder = 3 - Text = '5' - end - object txtStrips: TEdit - Left = 112 - Top = 52 - Width = 60 - Height = 21 - TabOrder = 1 - Text = '1' - end - object cmbDepth: TComboBox - Left = 112 - Top = 20 - Width = 73 - Height = 21 - Style = csDropDownList - ItemHeight = 13 - TabOrder = 0 - Items.Strings = ( - '16-bit' - '32-bit' - '32-bit float' - '64-bit') - end - object Label14: TPanel - Left = 192 - Top = 20 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Gamma threshold' - ParentShowHint = False - ShowHint = True - TabOrder = 10 - end - object Label12: TPanel - Left = 192 - Top = 52 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'DE Curve' - ParentShowHint = False - ShowHint = True - TabOrder = 11 - end - object Label11: TPanel - Left = 192 - Top = 84 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'DE Minimum' - ParentShowHint = False - ShowHint = True - TabOrder = 12 - end - object txtGammaTreshold: TEdit - Left = 296 - Top = 20 - Width = 73 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 6 - Text = '0.01' - OnChange = txtGammaTresholdChange - end - object txtEstimatorCurve: TEdit - Left = 296 - Top = 52 - Width = 73 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - Text = '0.6' - end - object txtEstimatorMin: TEdit - Left = 296 - Top = 84 - Width = 73 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - Text = '0' - end - end - object chkRender: TCheckBox - Left = 392 - Top = 398 - Width = 89 - Height = 43 - Anchors = [akTop, akRight] - Caption = 'Render' - Checked = True - State = cbChecked - TabOrder = 6 - Visible = False - end - object Panel1: TPanel - Left = 8 - Top = 296 - Width = 481 - Height = 89 - Anchors = [akLeft, akTop, akRight] - BevelKind = bkSoft - BevelOuter = bvNone - Color = clInfoBk - TabOrder = 7 - Visible = False - DesignSize = ( - 477 - 85) - object Label6: TLabel - Left = 8 - Top = 4 - Width = 453 - Height = 24 - Alignment = taCenter - Anchors = [akLeft, akTop, akRight] - AutoSize = False - Caption = 'WARNING!' - Font.Charset = DEFAULT_CHARSET - Font.Color = clInfoText - Font.Height = -19 - Font.Name = 'MS Sans Serif' - Font.Style = [fsBold] - ParentFont = False - end - object Label15: TLabel - Left = 8 - Top = 25 - Width = 447 - Height = 26 - Alignment = taCenter - Anchors = [akLeft, akRight] - Caption = - 'Fractals created with this version of Apophysis are not supporte' + - 'd by the external renderer! To render 2D-only fractals, download' + - ' the latest version of FLAM3 from http://www.flam3.com' - Color = clInfoBk - Font.Charset = DEFAULT_CHARSET - Font.Color = clInfoText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentColor = False - ParentFont = False - WordWrap = True - end - end - object txtDensity: TEdit - Left = 120 - Top = 212 - Width = 105 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 8 - Visible = False - OnChange = txtDensityChange - end - object Label4: TPanel - Left = 8 - Top = 212 - Width = 113 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Density' - ParentShowHint = False - ShowHint = True - TabOrder = 9 - Visible = False - end - object SaveDialog: TSaveDialog - DefaultExt = 'jpg' - Filter = - 'JPEG Image (*.jpg)|*.jpg|PPM Image (*.ppm)|*.ppm|PNG Images (*.p' + - 'ng)|*.png' - Left = 464 - Top = 264 - end -end diff --git a/Forms/FormExportC.pas b/Forms/FormExportC.pas deleted file mode 100644 index 7902f18..0000000 --- a/Forms/FormExportC.pas +++ /dev/null @@ -1,257 +0,0 @@ -{ - 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 - - 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 FormExportC; - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, Buttons, ComCtrls, ExtCtrls, Translation; - -type - TExportCDialog = class(TForm) - btnOK: TButton; - btnCancel: TButton; - GroupBox1: TGroupBox; - btnBrowse: TSpeedButton; - txtFilename: TEdit; - SaveDialog: TSaveDialog; - GroupBox3: TGroupBox; - txtOversample: TEdit; - txtFilterRadius: TEdit; - udOversample: TUpDown; - GroupBox2: TGroupBox; - chkMaintain: TCheckBox; - cbWidth: TComboBox; - cbHeight: TComboBox; - GroupBox4: TGroupBox; - cmbDepth: TComboBox; - chkRender: TCheckBox; - txtStrips: TEdit; - udStrips: TUpDown; - txtEstimator: TEdit; - txtEstimatorMin: TEdit; - txtEstimatorCurve: TEdit; - txtGammaTreshold: TEdit; - Panel1: TPanel; - Label6: TLabel; - Label15: TLabel; - Label13: TLabel; - Label16: TLabel; - Label5: TPanel; - Label3: TPanel; - Label1: TPanel; - Label2: TPanel; - Label7: TPanel; - Label8: TPanel; - Label9: TPanel; - Label14: TPanel; - Label12: TPanel; - Label11: TPanel; - Label10: TPanel; - txtDensity: TEdit; - Label4: TPanel; - procedure FormCreate(Sender: TObject); - procedure btnBrowseClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure txtWidthChange(Sender: TObject); - procedure chkMaintainClick(Sender: TObject); - procedure txtHeightChange(Sender: TObject); - procedure txtDensityChange(Sender: TObject); - procedure txtFilterRadiusChange(Sender: TObject); - procedure txtOversampleChange(Sender: TObject); - procedure txtGammaTresholdChange(Sender: TObject); - private - FloatFormatSettings: TFormatSettings; - Estimator, EstimatorMin, EstimatorCurve: double; - Jitters, Batches, Strips: integer; - public - Filename: string; - ImageWidth, ImageHeight, Oversample: Integer; - Sample_Density, Filter_Radius: double; - GammaTreshold: double; - end; - -var - ExportCDialog: TExportCDialog; - Ratio: double; - -implementation -uses Global, Main, ShellAPI; - -{$R *.DFM} - -procedure TExportCDialog.btnBrowseClick(Sender: TObject); -begin - SaveDialog.InitialDir := ExtractFileDir(txtFilename.text); - SaveDialog.Filename := txtFilename.Text; - SaveDialog.DefaultExt := 'png'; - SaveDialog.filterIndex := ExportFileFormat; - SaveDialog.Filter := Format('%s|*.png|%s|*.*', - [TextByKey('common-filter-png'), - TextByKey('common-filter-allfiles')]); - if SaveDialog.Execute then - begin - ExportFileFormat := SaveDialog.FilterIndex; - renderPath := ExtractFilePath(SaveDialog.Filename); - end; - -end; - -procedure TExportCDialog.FormShow(Sender: TObject); -begin - txtFilename.Text := Filename; - cbWidth.Text := IntToStr(MainCp.Width); - cbHeight.Text := IntToStr(MainCp.Height); - ImageWidth := MainCp.Width; - ImageHeight := MainCp.Height; - txtDensity.text := FloatToStr(Sample_density); -// if cmbDepth.ItemIndex <> 2 then -// txtBatches.text := IntToStr(Round(Sample_density / 4)); - txtFilterRadius.text := FloatToStr(Filter_Radius); - txtOversample.text := IntToSTr(Oversample); - udOversample.Position := Oversample; - Ratio := ImageWidth / ImageHeight; - Batches := 1; - Estimator := 9.0; - EstimatorMin := 0.0; - EstimatorCurve := 0.4; - Jitters := 1; - GammaTreshold := MainCP.gamma_threshold; //0.01; - GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FloatFormatSettings); - txtEstimator.Text := FloatToStr(Estimator, FloatFormatSettings); - txtEstimatorMin.Text := FloatToStr(EstimatorMin, FloatFormatSettings); - txtEstimatorCurve.Text := FloatToStr(EstimatorCurve, FloatFormatSettings); -// txtJitters.Text := IntToStr(Jitters); - txtGammaTreshold.Text := FloatToStr(GammaTreshold, FloatFormatSettings); -end; - -procedure TExportCDialog.btnOKClick(Sender: TObject); -begin - Filename := txtFilename.text; - ImageWidth := StrToInt(cbWidth.Text); - ImageHeight := StrToInt(cbHeight.Text); -end; - -procedure TExportCDialog.txtWidthChange(Sender: TObject); -begin - try - ImageWidth := StrToInt(cbWidth.Text); - if chkMaintain.checked and cbWidth.Focused then - begin - ImageHeight := Round(ImageWidth / ratio); - cbHeight.Text := IntToStr(ImageHeight) - end; - except - end; -end; - -procedure TExportCDialog.chkMaintainClick(Sender: TObject); -begin - Ratio := ImageWidth / ImageHeight; -end; - -procedure TExportCDialog.txtHeightChange(Sender: TObject); -begin - try - ImageHeight := StrToInt(cbHeight.Text); - if chkMaintain.checked and cbHeight.Focused then - begin - ImageWidth := Round(ImageHeight * ratio); - cbWidth.Text := IntToStr(ImageWidth) - end; - except - end; -end; - -procedure TExportCDialog.txtDensityChange(Sender: TObject); -begin - try - Sample_Density := StrToFloat(txtDensity.Text); -// if cmbDepth.ItemIndex <> 2 then -// txtBatches.text := IntToStr(Round(Sample_density / 4)); - except - end; -end; - -procedure TExportCDialog.txtFilterRadiusChange(Sender: TObject); -begin - try - Filter_Radius := StrToFloat(txtFilterRadius.Text); - except - end; -end; - -procedure TExportCDialog.txtOversampleChange(Sender: TObject); -begin - if StrToInt(txtOversample.Text) > udOversample.Max then - txtOversample.Text := IntToStr(udOversample.Max); - if StrToInt(txtOversample.Text) < udOversample.Min then - txtOversample.Text := IntToStr(udOversample.Min); - try - Oversample := StrToInt(txtOversample.Text); - except - end; -end; - -procedure TExportCDialog.txtGammaTresholdChange(Sender: TObject); -begin - //GammaTreshold := 0.01; - try - GammaTreshold := StrToFloat(txtGammaTreshold.Text, FloatFormatSettings); - except - end; -end; - -procedure TExportCDialog.FormCreate(Sender: TObject); -begin - btnOK.Caption := TextByKey('common-ok'); - btnCancel.Caption := TextByKey('common-cancel'); - Label1.Caption := TextByKey('common-width'); - Label2.Caption := TextByKey('common-height'); - GroupBox2.Caption := TextByKey('common-size'); - Label13.Caption := TextByKey('common-pixels'); - chkMaintain.Caption := TextByKey('common-keepaspect'); - GroupBox1.Caption := TextByKey('common-destination'); - Label10.Caption := TextByKey('common-filename'); - btnBrowse.Hint := TextByKey('common-browse'); - GroupBox3.Caption := TextByKey('common-quality'); - Label5.Caption := TextByKey('common-filterradius'); - Label4.Caption := TextByKey('common-density'); - Label3.Caption := TextByKey('common-oversample'); - Label14.Caption := TextByKey('common-gammathreshold'); - self.Caption := TextByKey('main-menu-file-exportchaotica'); - GroupBox4.Caption := TextByKey('export-paramoptions-title'); - Label7.Caption := TextByKey('export-paramoptions-bufferdepth'); - Label8.Caption := TextByKey('export-paramoptions-strips'); - Label9.Caption := TextByKey('export-paramoptions-estimatorradius'); - Label12.Caption := TextByKey('export-paramoptions-estimatorcurve'); - Label11.Caption := TextByKey('export-paramoptions-estimatormin'); - chkRender.Caption := TextByKey('export-paramoptions-dorender'); - Label6.Caption := TextByKey('export-paramoptions-warningtitle'); - Label15.Caption := TextByKey('export-paramoptions-warningtext'); -end; - -end. - diff --git a/Forms/FormFavorites.pas b/Forms/FormFavorites.pas index f29a2a5..87939df 100644 --- a/Forms/FormFavorites.pas +++ b/Forms/FormFavorites.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,7 +27,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ExtCtrls, ComCtrls, Translation, Vcl.Buttons; + StdCtrls, ExtCtrls, ComCtrls, Vcl.Buttons; type TFavoritesForm = class(TForm) @@ -66,7 +66,8 @@ var implementation -uses Global, ScriptForm; +uses Global, ScriptForm, Translation; + {$R *.DFM} procedure TFavoritesForm.FormShow(Sender: TObject); @@ -85,15 +86,9 @@ begin Listitem.Caption := s; end; if Favorites.Count <> 0 then - ScriptList.Selected := ScriptList.Items[0] - else - btnRemove.Enabled := False; + ScriptList.Selected := ScriptList.Items[0]; - if ScriptList.Items.Count <= 1 then - begin - btnMoveUp.Enabled := False; - btnMoveDown.Enabled := False; - end; + ScriptListChange(Sender, ScriptList.Selected, ctText); // AV end; procedure TFavoritesForm.btnOKClick(Sender: TObject); @@ -130,8 +125,9 @@ var begin s := AppPath + 'Scripts'; if DirectoryExists(s) then - ScriptEditor.MainOpenDialog.InitialDir := s - else ScriptEditor.MainOpenDialog.InitialDir := ParamFolder; + ScriptEditor.MainOpenDialog.InitialDir := s + else + ScriptEditor.MainOpenDialog.InitialDir := ParamFolder; ScriptEditor.MainOpenDialog.Filter := Format('%s|*.aposcript;*.asc|%s|*.*', [TextByKey('common-filter-scriptfiles'), TextByKey('common-filter-allfiles')]); @@ -148,14 +144,9 @@ begin s := Copy(s, 0, length(s) - Length(ExtractFileExt(s))); Listitem.Caption := s; ScriptList.Selected := ScriptList.Items[ScriptList.Items.Count - 1]; - btnRemove.Enabled := True; end; - if ScriptList.Items.Count <= 1 then - begin - btnMoveUp.Enabled := False; - btnMoveDown.Enabled := False; - end; + ScriptListChange(Sender, ScriptList.Selected, ctText); // AV end; procedure TFavoritesForm.btnRemoveClick(Sender: TObject); @@ -170,15 +161,9 @@ begin if i < ScriptList.Items.Count then ScriptList.Selected := ScriptList.Items[i] else - ScriptList.Selected := ScriptList.Items[ScriptList.Items.Count - 1] - else - btnRemove.Enabled := False; + ScriptList.Selected := ScriptList.Items[ScriptList.Items.Count - 1]; - if ScriptList.Items.Count <= 1 then - begin - btnMoveUp.Enabled := False; - btnMoveDown.Enabled := False; - end; + ScriptListChange(Sender, ScriptList.Selected, ctText); // AV end; procedure TFavoritesForm.btnSortClick(Sender: TObject); @@ -200,27 +185,35 @@ begin end; ScriptList.Items.EndUpdate; scripts.Free; + ScriptListChange(Sender, ScriptList.Selected, ctText); // AV end; procedure TFavoritesForm.ScriptListChange(Sender: TObject; Item: TListItem; Change: TItemChange); +var + n: smallint; + IsSel: boolean; begin - // TODO: optimize old code - btnRemove.Enabled := (ScriptList.Items.Count > 0); + n := ScriptList.Items.Count; + IsSel := assigned(ScriptList.Selected); - if (Item.Index = ScriptList.Items.Count - 1) then - btnMoveDown.Enabled := False - else - btnMoveDown.Enabled := True; - if (Item.Index = 0) then - btnMoveUp.Enabled := False - else - btnMoveUp.Enabled := True; + btnRemove.Enabled := (n > 0) and IsSel; + btnSort.Enabled := (n > 1); - if (ScriptList.Items.Count <= 1) then + if (n <= 1) or (not IsSel) then begin btnMoveDown.Enabled := False; btnMoveUp.Enabled := False; + end + else begin + if (Item.Index = n - 1) then + btnMoveDown.Enabled := False + else + btnMoveDown.Enabled := True; + if (Item.Index = 0) then + btnMoveUp.Enabled := False + else + btnMoveUp.Enabled := True; end; end; @@ -250,7 +243,7 @@ procedure TFavoritesForm.btnClearClick(Sender: TObject); begin ScriptList.Items.Clear; Faves.Clear; - btnRemove.Enabled := False; + ScriptListChange(Sender, ScriptList.Selected, ctText); // AV end; procedure TFavoritesForm.btnMoveDownClick(Sender: TObject); diff --git a/Forms/FormRender.dfm b/Forms/FormRender.dfm index 9de91d0..4231bb1 100644 --- a/Forms/FormRender.dfm +++ b/Forms/FormRender.dfm @@ -241,19 +241,6 @@ object RenderForm: TRenderForm DesignSize = ( 233 97) - object lblRatio: TLabel - Left = 12 - Top = 72 - Width = 56 - Height = 13 - Caption = 'Aspect ratio' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentFont = False - end object pnlWidth: TPanel Left = 8 Top = 20 @@ -349,9 +336,9 @@ object RenderForm: TRenderForm '3200') end object cbAspectRatio: TComboBox - Left = 101 - Top = 70 - Width = 123 + Left = 100 + Top = 68 + Width = 125 Height = 21 Style = csDropDownList Font.Charset = DEFAULT_CHARSET @@ -372,6 +359,21 @@ object RenderForm: TRenderForm '16 : 10' '21 : 9 (CinemaScope)') end + object lblRatio: TPanel + Left = 8 + Top = 68 + Width = 92 + Height = 21 + BevelOuter = bvLowered + Caption = 'Aspect ratio' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'MS Sans Serif' + Font.Style = [] + ParentFont = False + TabOrder = 5 + end end object GroupBox3: TGroupBox Left = 248 @@ -874,10 +876,6 @@ object RenderForm: TRenderForm object TabOutput: TTabSheet Caption = 'Output' ImageIndex = 38 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object Output: TMemo Left = 0 Top = 0 @@ -958,13 +956,142 @@ object RenderForm: TRenderForm OnClick = btnSnapshotClick end object SaveDialog: TSaveDialog - Left = 456 + Left = 448 Top = 72 end object ProgressTaskbar: TTaskbar - TaskBarButtons = <> + TaskBarButtons = < + item + Hint = 'Show image state...' + Icon.Data = { + 0000010001001616000000000000900600001600000028000000160000002C00 + 0000010008000000000010020000000000000000000000010000000000005858 + 5800B0B0B000F9F9F90092929200EAEAEA0083838300DBDBDB00AEAEAE004747 + 47009F9F9F00E8E8E80081818100D9D9D90063636300BBBBBB00545454009D9D + 9D008E8E8E007F7F7F00D7D7D7007070700052525200AAAAAA008C8C8C00E4E4 + E4007D7D7D00D5D5D5006E6E6E00C6C6C6005F5F5F0050505000A8A8A8007B7B + 7B00B5B5B5004E4E4E003F3F3F0097979700D1D1D100C2C2C2005B5B5B00B3B3 + B300A4A4A4003D3D3D009595950086868600DEDEDE007777770068686800C0C0 + C00059595900B1B1B1004A4A4A00A2A2A20084848400DCDCDC0075757500CDCD + CD006666660057575700AFAFAF004848480091919100DADADA00CBCBCB005555 + 55009E9E9E00C9C9C90062626200BABABA009C9C9C008D8D8D007E7E7E00D6D6 + D600C7C7C700F2F2F200E3E3E3007C7C7C00D4D4D4005E5E5E0040404000FFFF + FF009898980089898900E1E1E100B4B4B400FDFDFD003E3E3E00EEEEEE008787 + 8700C1C1C100FBFBFB008585850076767600CECECE0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000005050 + 5050505050505050505050505050505050505050000050505050505050505050 + 5050505050505050505050500000505050505050505050505050505050505050 + 5050505000002A2A2A5050505050502A2A2A5050505050502A2A2A5000002A2A + 2A502A502A502A2A2A2A2A502A502A502A2A2A5000002A2A5050505050505050 + 5050505050505050502A2A500000505050165151033D3D58523D3D5151415152 + 505050500000502A502429584C332339374C583D51490952502A505000005050 + 50472E35121041462A432A394C523D1B5050505000005008505C412A2A451F26 + 162B4F2E402A433C502A505000005050502A3E3D2C172A0725500E102750050E + 5050505000000F1E502A3D5D32545139073F505D53575713502A2A5000000040 + 50442A014B4B501C2A50444B04183E1C502A2A5000004E315021595050503B38 + 4D0E0A5A505A0459502A2A5000005050501F0E59502149064806025050500242 + 505050500000500D5034443F3F3F0C364D2D55505050553F502A505000005050 + 50412830305959301C1A4A5050504A59505050500000501B50241F0101010101 + 0101493E533E4901502A50500000505050112B24244541414141411F071F4141 + 505050500000202E50505050505050505050505050505050502A2A5000000B4C + 2E5014502F504E273A152250085056502A2A2A5000005B0B195050505050501D + 27005050505050502A2A2A500000FFFFFF00FFFFFF00FFFFFF001F8FC7000000 + 04000000040080000C0080000E0080000E0080000E0080000E00000006000000 + 04000000040080000C0080000E0080000E0080000E0080000E00000006000000 + 04001F8FC400} + end + item + Hint = 'Cancel current rendering' + Icon.Data = { + 0000010001001616000000000000100800001600000028000000160000002C00 + 000001002000000000009007000000000000000000000000000000000000FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF005555550E545454495454 + 547E545454B2545454E5545454E5545454B25454547E545454495555550EFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF0054545450545454E7515151FF4E4E4EFF4B4B4BFF4848 + 48FF484848FF4B4B4BFF4E4E4EFF515151FF545454E754545450FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00565656115555 + 55A4535353FF4C4C4CFF555555FF757575FF989898FFBFBFBFFFC0C0C0FF9C9C + 9CFF797979FF575757FF4C4C4CFF535353FF555555A456565611FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0057575711565656E1525252FF494949FF8181 + 81FFD9D9D9FFE5E5E5FFEBEBEBFFEEEEEEFFEFEFEFFFEEEEEEFFEBEBEBFFE2E2 + E2FF8C8C8CFF494949FF525252FF565656E157575711FFFFFF00FFFFFF00FFFF + FF00FFFFFF00565656A4525252FF555555FFB1B1B1FFE1E1E1FFECECECFFF3F3 + F3FFF8F8F8FFFBFBFBFFFBFBFBFFFBFBFBFFF8F8F8FFF3F3F3FFECECECFFC2C2 + C2FF585858FF525252FF565656A4FFFFFF00FFFFFF00FFFFFF00575757505555 + 55FF4A4A4AFFACACACFFE1E1E1FFEEEEEEFFF7F7F7FFFCFCFCFFFDFDFDFFFFFF + FFFFFFFFFFFFFFFFFFFFFDFDFDFFFCFCFCFFF7F7F7FFEEEEEEFFC2C2C2FF4A4A + 4AFF555555FF57575750FFFFFF005959590E585858E74F4F4FFF7C7C7CFFDCDC + DCFFECECECFFF6F6F6FFE9E9E9FFEBEBEBFFEAEAEAFFE9E9E9FFE9E9E9FFE9E9 + E9FFEAEAEAFFEBEBEBFFFAFAFAFFF7F7F7FFECECECFF8D8D8DFF4F4F4FFF5858 + 58E75959590E5B5B5B49585858FF595959FFC8C8C8FFE5E5E5FFF3F3F3FFF2F2 + F2FF5F5F5FFF515151FF464646FF3E3E3EFF3B3B3BFF3E3E3EFF464646FF5151 + 51FFEBEBEBFFFCFCFCFFF3F3F3FFE2E2E2FF5B5B5BFF585858FF5B5B5B495D5D + 5D7E565656FF717171FFD5D5D5FFEBEBEBFFF8F8F8FFF2F2F2FF545454FF4444 + 44FF363636FF2B2B2BFF272727FF2B2B2BFF363636FF444444FFEAEAEAFFFDFD + FDFFF8F8F8FFEBEBEBFF7C7C7CFF565656FF5D5D5D7E5F5F5FB2545454FF8989 + 89FFDCDCDCFFEEEEEEFFFBFBFBFFF2F2F2FF4D4D4DFF3B3B3BFF2A2A2AFF1B1B + 1BFF131313FF1B1B1BFF2A2A2AFF3B3B3BFFE9E9E9FFFFFFFFFFFBFBFBFFEEEE + EEFF9E9E9EFF545454FF5F5F5FB2616161E5535353FFA4A4A4FFDDDDDDFFEFEF + EFFFFBFBFBFFF0F0F0FF4B4B4BFF383838FF252525FF121212FF000000FF1212 + 12FF252525FF383838FFE8E8E8FFFFFFFFFFFBFBFBFFEFEFEFFFC1C1C1FF5353 + 53FF616161E5636363E5555555FFA4A4A4FFDCDCDCFFEEEEEEFFFBFBFBFFF1F1 + F1FF6A6A6AFF5E5E5EFF535353FF474747FF373737FF313131FF363636FF4040 + 40FFE9E9E9FFFFFFFFFFFBFBFBFFEEEEEEFFC0C0C0FF555555FF636363E56565 + 65B25A5A5AFF8A8A8AFFD5D5D5FFEEEEEEFFFAFAFAFFF4F4F4FF8C8C8CFF7A7A + 7AFF686868FF565656FF4B4B4BFF464646FF474747FF4D4D4DFFEAEAEAFFFDFD + FDFFF8F8F8FFEBEBEBFF9B9B9BFF5A5A5AFF656565B26767677E606060FF7575 + 75FFDCDCDCFFF1F1F1FFF8F8F8FFF2F2F2FF939393FF838383FF747474FF6565 + 65FF5B5B5BFF565656FF565656FF595959FFEBEBEBFFFCFCFCFFF3F3F3FFE5E5 + E5FF7C7C7CFF606060FF6767677E6B6B6B49676767FF636363FFC5C5C5FFECEC + ECFFF4F4F4FFEFEFEFFF979797FF8E8E8EFF818181FF747474FF6B6B6BFF6767 + 67FF656565FF686868FFE9E9E9FFF7F7F7FFECECECFFDADADAFF636363FF6767 + 67FF6B6B6B497070700E6F6F6FE7636363FF828282FFDCDCDCFFEDEDEDFFF3F3 + F3FFEEEEEEFFF1F1F1FFF1F1F1FFF3F3F3FFF3F3F3FFF4F4F4FFF3F3F3FFF3F3 + F3FFF6F6F6FFEEEEEEFFE1E1E1FF888888FF636363FF6F6F6FE77070700EFFFF + FF00727272506F6F6FFF5E5E5EFFA9A9A9FFDEDEDEFFECECECFFF2F2F2FFF6F6 + F6FFFAFAFAFFFCFCFCFFFCFCFCFFFCFCFCFFF9F9F9FFF4F4F4FFECECECFFE1E1 + E1FFB3B3B3FF5E5E5EFF6F6F6FFF72727250FFFFFF00FFFFFF00FFFFFF007575 + 75A46F6F6FFF686868FFAAAAAAFFD7D7D7FFE7E7E7FFECECECFFF0F0F0FFF1F1 + F1FFF2F2F2FFF0F0F0FFEDEDEDFFE6E6E6FFDCDCDCFFAFAFAFFF686868FF6F6F + 6FFF757575A4FFFFFF00FFFFFF00FFFFFF00FFFFFF0079797911787878E17171 + 71FF636363FF858585FFC2C2C2FFD6D6D6FFDFDFDFFFE3E3E3FFE3E3E3FFE0E0 + E0FFD8D8D8FFCACACAFF858585FF636363FF717171FF787878E179797911FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF007D7D7D117B7B7BA4797979FF6E6E + 6EFF6E6E6EFF7C7C7CFF8F8F8FFFA9A9A9FFA8A8A8FF8F8F8FFF7C7C7CFF6E6E + 6EFF6E6E6EFF797979FF7B7B7BA47D7D7D11FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF007F7F7F507F7F7FE77B7B7BFF7676 + 76FF727272FF6E6E6EFF6E6E6EFF727272FF767676FF7B7B7BFF7F7F7FE77F7F + 7F50FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF008585850E838383498383837E848484B28484 + 84E5848484E5848484B28383837E838383498585850EFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FF87FF00FC00FF00F0003F00E0001F00C000 + 0F00C0000F008000070080000600800006000000020000000000000000000000 + 0000800004008000060080000600C0000E00C0000F00E0001F00F0003F00FC00 + FF00FF87FF00} + end> ProgressMaxValue = 100 TabProperties = [] + OnThumbButtonClick = ProgressTaskbarThumbButtonClick Left = 432 Top = 424 end diff --git a/Forms/FormRender.pas b/Forms/FormRender.pas index eef8f1e..2c0ebf3 100644 --- a/Forms/FormRender.pas +++ b/Forms/FormRender.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,10 +27,10 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ComCtrls, Math, Buttons, Registry, ExtCtrls, MMSystem, // Windows7, + StdCtrls, ComCtrls, Math, Buttons, Registry, ExtCtrls, MMSystem, System.Win.TaskbarCore, Vcl.Taskbar, Vcl.Samples.Spin, // AV - ControlPoint, RenderThread, cmap, RenderingCommon, RenderingInterface, - ShellAPI, Translation, ActiveX, ComObj; + ControlPoint, cmap, RenderThread, RenderingInterface, + ShellAPI, ActiveX, ComObj; const {$ifdef T500} @@ -38,6 +38,10 @@ const {$else} rendersAV = 'rendersAV.flame'; {$endif} + +type + TWin32Version = (wvUnknown, wvWin95, wvWin98, wvWinNT, wvWin2000, wvWinXP, + wvWinVista, wvWin7, wvWinFutureFromOuterSpace); type TRenderForm = class(TForm) @@ -93,12 +97,12 @@ type chkSaveIncompleteRenders: TCheckBox; lblCPUCores: TLabel; cbAspectRatio: TComboBox; - lblRatio: TLabel; chkEmbedFlame: TCheckBox; chkPlaySound: TCheckBox; btnSnapshot: TButton; ProgressTaskbar: TTaskbar; sbFilterRadius: TSpinButton; + lblRatio: TPanel; procedure btnSaveLogClick(Sender: TObject); procedure btnDonateClick(Sender: TObject); procedure cbMaxMemoryChange(Sender: TObject); @@ -133,10 +137,12 @@ type 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; @@ -148,27 +154,28 @@ type procedure ListPresets; function WindowsExit(RebootParam: Longword = EWX_POWEROFF or EWX_FORCE): Boolean; procedure Save(const str: string); - function IsLimitingMemory():boolean; - + function IsLimitingMemory(): boolean; + procedure OnProgress(prog: double); + procedure ShowMemoryStatus; public Renderer: TRenderThread; - PhysicalMemory, ApproxMemory, TotalPhysicalMemory: int64; - ColorMap: TColorMap; + + //ColorMap: TColorMap; cp: TControlPoint; Filename: string; ImageWidth, ImageHeight, Oversample: Integer; - // BitsPerSample: integer; Brightness, Gamma, Vibrancy: double; - zoom, Sample_Density, Filter_Radius: double; - center: array[0..1] of double; + Sample_Density, Filter_Radius: double; MaxMemory: integer; bRenderAll: boolean; - procedure OnProgress(prog: double); - procedure ShowMemoryStatus; + 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; @@ -177,7 +184,7 @@ var implementation uses - Main, Global, SavePreset, formPostProcess, PngImage, ImageMaker,Tracer; + Main, Global, SavePreset, formPostProcess, ImageMaker, Tracer, Translation; {$R *.DFM} @@ -197,7 +204,6 @@ begin txtOversample.Enabled := true; //chkLimitMem.Enabled := true; cbMaxMemory.enabled := true; - //cbBitsPerSample.Enabled := true; chkPostProcess.Enabled := not IsLimitingMemory; chkSaveIncompleteRenders.Enabled := not IsLimitingMemory; btnRender.Enabled := true; @@ -225,7 +231,6 @@ begin pnlOversample.Enabled := true; pnlLimit.Enabled := true; pnlTarget.Enabled := true; - //pnlBufferDepth.Enabled := true; pnlWidth.Font.Color := clWindowText; pnlHeight.Font.Color := clWindowText; @@ -234,27 +239,9 @@ begin pnlOversample.Font.Color := clWindowText; pnlLimit.Font.Color := clWindowText; pnlTarget.Font.Color := clWindowText; - //pnlBufferDepth.Font.Color := clWindowText; ShowMemoryStatus; end; -procedure WinShellExecute(const Operation, AssociatedFile: string); -var - a1: string; -begin - a1 := Operation; - if a1 = '' then - a1 := 'open'; - ShellExecute( - application.handle - , pchar(a1) - , pchar(AssociatedFile) - , '' - , '' - , SW_SHOWNORMAL - ); -end; - function GetCpuCount: integer; var si: TSystemInfo; @@ -273,10 +260,11 @@ begin TotalPhysicalMemory := GlobalMemoryInfo.dwTotalPhys div 1048576; //TotalPhysicalMemory := TotalPhysicalMemory * 9 div 10; // assume that OS will take 10% of RAM ;) - if SingleBuffer then - ApproxMemory := int64(ImageHeight) * int64(ImageWidth) * sqr(Oversample) * 16 div 1048576 - else - ApproxMemory := int64(ImageHeight) * int64(ImageWidth) * sqr(Oversample) * 32 div 1048576; + {$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)); @@ -372,7 +360,7 @@ begin 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')), 'Apophysis', MB_RETRYCANCEL or MB_ICONERROR) = IDRETRY); + #13#10 + TextByKey('render-status-saveerror-message2')), ApophysisSVN, MB_RETRYCANCEL or MB_ICONERROR) = IDRETRY); // AV: displaying status in red ProgressTaskBar.ProgressState := TTaskBarProgressState.Error; end; @@ -419,7 +407,6 @@ begin Trace2(MsgAnotherRunning); exit; end; - { // AV: temporary commented out since undestroyed TBaseRenderer objects // from Renderer.GetRenderer method cause regular large memory leaks! @@ -428,7 +415,7 @@ begin 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 @@ -466,9 +453,10 @@ begin prog := (Renderer.Slice + Prog) / Renderer.NrSlices; if ShowProgress then begin - ProgressBar2.Position := round(100 * prog); - // AV: to display the progress on the taskbar - ProgressTaskBar.ProgressValue := ProgressBar2.Position; // AV + 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', @@ -491,13 +479,32 @@ begin Trunc(Remaining * 24 * 60 * 60 * 100) mod 100]); end; StatusBar.Panels[2].text := Format(TextByKey('render-status-slicestatus'), [(Renderer.Slice + 1), (Renderer.nrSlices)]); - //'Slice ' + IntToStr(Renderer.Slice + 1) + ' of ' + IntToStr(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 Apo7X64} +{$ifdef CPUX64} cbMaxMemory.Items.Add('2048'); cbMaxMemory.Items.Add('3072'); cbMaxMemory.Items.Add('4096'); @@ -519,12 +526,12 @@ begin 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'); - //pnlBufferDepth.Caption := TextByKey('render-resourceusage-bufferdepth'); chkSave.Caption := TextByKey('render-output-saveparams1'); chkEmbedFlame.Caption := TextByKey('render-output-saveparams2'); GroupBox6.Caption := TextByKey('render-completion-title'); @@ -541,11 +548,18 @@ begin 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 - // BitsPerSample := 0; + MainForm.Buttons.GetBitmap(2, btnSavePreset.Glyph); // MainForm.Buttons.GetBitmap(9, btnDeletePreset.Glyph); bRenderAll := false; @@ -576,11 +590,10 @@ end; procedure TRenderForm.btnRenderClick(Sender: TObject); var - t: string; iCurrFlame: integer; - path, ext: string; - lim:integer; - ilm:boolean; + t, ext: string; + lim: integer; + ilm: boolean; { sl: TStringList; tryAgain: boolean; cancel: boolean; @@ -599,10 +612,9 @@ begin 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')), 'Apophysis', MB_RETRYCANCEL or MB_ICONERROR)); + #13#10 + TextByKey('render-status-saveerror-message2')), ApophysisSVN, MB_RETRYCANCEL or MB_ICONERROR)); tryAgain := (result = IDRETRY); cancel := (result = IDCANCEL); - ProgressBar2.ProgressBarState := pbstError; end; end; until (tryAgain = false) or (cancel = true); @@ -624,34 +636,25 @@ begin if not ilm then begin if (ApproxMemory > {Total}PhysicalMemory) then begin - if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-notenoughmemory1')), 'Apophysis', MB_ICONWARNING or MB_YESNO) then - exit; + if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-notenoughmemory1')), + ApophysisSVN, MB_ICONWARNING or MB_YESNO) then exit; end; -{ - if (ApproxMemory > PhysicalMemory) then - begin - if Application.MessageBox('There is not enough memory for this render. ' + #13 + - 'You can use memory limiting, or - if you are sure that your system *should* ' + #13 + - 'have the required amount of free RAM, you can try to allocate memory anyway. ' + #13#13 + - 'Dou you want to try? (SLOW AND UNSTABLE - USE AT YOUR OWN RISK!!!)', 'Apophysis', - MB_ICONWARNING or MB_YESNO) <> IDYES then exit; - end; -} end else if (PhysicalMemory < lim) and (Approxmemory > PhysicalMemory) then begin - if IDYES <> Application.MessageBox(PChar(TextByKey('render-status-notenoughmemory2')), 'Apophysis', MB_ICONWARNING or MB_YESNO) then - exit; + 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')), 'Apophysis', 48); - Exit; + 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')), - 'Apophysis', 52) = ID_NO then exit; + 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 @@ -665,7 +668,7 @@ begin { // AV: how is it possible, if (udOversample.Min = 1) and (txtOversample.ReadOnly = true)? if Oversample < 1 then - raise Exception.Create(TextByKey('render-status-invalidoversample')); // AV + raise Exception.Create(TextByKey('render-status-invalidoversample')); } if ImageWidth < 1 then raise Exception.Create(TextByKey('render-status-invalidwidth')); // AV @@ -676,13 +679,13 @@ begin 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')), 'Apophysis', MB_ICONERROR or MB_YESNO) then - exit; + 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 := ProgressBar2.Position; // AV + ProgressTaskBar.ProgressValue := 0; // AV txtFilename.Enabled := false; btnBrowse.Enabled := false; @@ -693,7 +696,6 @@ begin txtOversample.Enabled := false; //chkLimitMem.Enabled := true; cbMaxMemory.Enabled := false; - //cbBitsPerSample.Enabled := false; cmbPreset.enabled := false; chkSave.enabled := false; chkPostProcess.enabled := false; @@ -715,7 +717,6 @@ begin pnlOversample.Enabled := false; pnlLimit.Enabled := false; pnlTarget.Enabled := false; - //pnlBufferDepth.Enabled := false; pnlWidth.Font.Color := clGrayText; pnlHeight.Font.Color := clGrayText; @@ -724,7 +725,6 @@ begin pnlOversample.Font.Color := clGrayText; pnlLimit.Font.Color := clGrayText; pnlTarget.Font.Color := clGrayText; - //pnlBufferDepth.Font.Color := clGrayText; PageCtrl.TabIndex := 1; @@ -732,8 +732,8 @@ begin if bRenderAll then begin - path := ExtractFilePath(FileName); - ext := ExtractFileExt(FileName); + renderPath := ExtractFilePath(FileName); // AV + ext := ExtractFileExt(FileName); // AV if Assigned(Renderer) then begin Output.Lines.Add(TimeToStr(Now) + TextByKey('render-status-shuttingdownrender')); @@ -743,8 +743,9 @@ begin Renderer := nil; end; - for iCurrFlame := 0 to MainForm.ListView1.Items.Count-1 do + for iCurrFlame := 0 to High(FlameNames) {MainForm.ListView1.Items.Count-1} do begin + { MainForm.ListView1.ItemIndex := iCurrFlame; cp.Free; cp := TControlPoint.Create; @@ -753,20 +754,27 @@ begin zoom := maincp.zoom; Center[0] := MainForm.center[0]; Center[1] := MainForm.center[1]; - FileName := path + cp.name + ext; + } + 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])); - if SingleBuffer then - 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'])); + + {$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(ExtractFileExt(FileName)) = '.PNG') and + if (UpperCase(ext) = '.PNG') and (ImageWidth * ImageHeight >= 20000000) then begin Output.Lines.Add(TextByKey('render-status-log-largepng-message1')); @@ -783,20 +791,27 @@ begin 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 - MainForm.SaveXMLFlame(cp, ExtractFileName(FileName), renderPath + rendersAV); + 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) ); + 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 = MainForm.ListView1.Items.Count-1 then bRenderAll := false; + if iCurrFlame = High(FlameNames){MainForm.ListView1.Items.Count-1} then + bRenderAll := false; Renderer := TRenderThread.Create; assert(Renderer <> nil); @@ -806,8 +821,8 @@ begin else Renderer.SetPriority(tpNormal); } - Renderer.ExportBuffer := chkBinary.Checked; - // Renderer.BitsPerSample := BitsPerSample; + //Renderer.ExportBuffer := chkBinary.Checked; + if (ilm) then Renderer.MaxMem := lim; //StrToInt(cbMaxMemory.text); Renderer.OnProgress := OnProgress; @@ -815,7 +830,7 @@ begin Renderer.SetCP(cp); if chkEmbedFlame.checked then - Renderer.EmbedText(Trim(MainForm.RetrieveXML(cp))); // AV + Renderer.EmbedText(Trim(FlameToXML(cp))); // AV Renderer.Priority := tpLower; // tpNormal; Renderer.NrThreads := NrTreads; @@ -827,21 +842,23 @@ begin except Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-rendererror-log')); - //Application.MessageBox('Error while rendering!', 'Apophysis', 48); end; end; end; - end else - begin + + 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])); - if SingleBuffer then - 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'])); + {$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])) @@ -873,28 +890,33 @@ begin cp.AdjustScale(ImageWidth, ImageHeight); cp.Transparency := (PNGTransparency <> 0) and (UpperCase(ExtractFileExt(FileName)) = '.PNG'); renderPath := ExtractFilePath(Filename); - if chkSave.checked then - MainForm.SaveXMLFlame(cp, ExtractFileName(FileName), renderPath + rendersAV); - oldProg:=0; - oldElapsed:=0; - edt:=0; - ApproxSamples := Round(sample_density * sqr(power(2, cp.zoom)) * int64(ImageHeight) * int64(ImageWidth) / sqr(oversample) ); + 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); - // Renderer.BitsPerSample := BitsPerSample; if (ilm) then Renderer.MaxMem := lim; //StrToInt(cbMaxMemory.text); - Renderer.ExportBuffer := chkBinary.Checked; + //Renderer.ExportBuffer := chkBinary.Checked; Renderer.OnProgress := OnProgress; Renderer.TargetHandle := self.Handle; Renderer.SetCP(cp); if chkEmbedFlame.checked then - Renderer.EmbedText(Trim(MainForm.RetrieveXML(cp))); // AV + Renderer.EmbedText(Trim(FlameToXML(cp))); // AV { if chkThreadPriority.Checked then Renderer.SetPriority(tpLower) @@ -909,7 +931,7 @@ begin except Output.Lines.Add(TimeToStr(Now) + ' : ' + TextByKey('render-status-rendererror-log')); - Application.MessageBox(PChar(TextByKey('render-status-rendererror-message')), 'Apophysis', 48); + Application.MessageBox(PChar(TextByKey('render-status-rendererror-message')), ApophysisSVN, 48); end; end; end; @@ -951,16 +973,24 @@ begin txtOversample.Text := IntToStr(renderOversample); Filter_Radius := max(renderFilterRadius, 0.1); // AV: fixed! txtFilterRadius.Text := FloatToStr(RoundTo(Filter_Radius, -3)); // AV - cbWidth.Text := IntToStr(cp.Width); - cbHeight.Text := IntToStr(cp.Height); - ImageWidth := StrToInt(cbWidth.Text); - ImageHeight := StrToInt(cbHeight.Text); - // AV: fixed "Floating point division by zero" bug + // AV: fixed 'Floating point division by zero' bug sample_density := max(renderDensity, 10); txtDensity.Text := FloatToStr(sample_density); - // BitsPerSample := renderBitsPerSample; - ShowMemoryStatus; + + // 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; @@ -1041,7 +1071,8 @@ begin end; if ConfirmStopRender then begin - if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), 'Apophysis', 36) = ID_NO then exit; + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), + ApophysisSVN, 36) = ID_NO then exit; end; bRenderAll := false; @@ -1056,6 +1087,7 @@ begin ProgressTaskBar.ProgressValue := 0; // AV ProgressTaskBar.ProgressState := TTaskBarProgressState.None; // AV + end else Close; end; @@ -1099,10 +1131,13 @@ begin renderHeight := ImageHeight; renderDensity := Sample_density; renderOversample := Oversample; - // renderBitsPerSample := BitsPerSample; + 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 @@ -1121,16 +1156,16 @@ procedure TRenderForm.btnPauseClick(Sender: TObject); begin if Assigned(Renderer) then if Renderer.Suspended = false then begin - renderer.Suspend; + 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; + Renderer.Resume; btnPause.caption := TextByKey('common-pause'); btnSnapshot.Visible := false; // AV - // AV: restore the taskbar progress + // AV: restore the taskbar progress ProgressTaskBar.ProgressState := TTaskBarProgressState.Normal; end; end; @@ -1139,8 +1174,8 @@ procedure TRenderForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if Assigned(Renderer) then - if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), 'Apophysis', 36) = ID_NO then - CanClose := False + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), + ApophysisSVN, 36) = ID_NO then CanClose := False else begin if Assigned(Renderer) then @@ -1187,14 +1222,13 @@ begin else WriteLn(IFile, 'false'); WriteLn(IFile, IntToStr(cbMaxMemory.ItemIndex)); - WriteLn(IFile, cbMaxMemory.Text); WriteLn(IFile, '}'); WriteLn(IFile, ''); CloseFile(IFile); except on EInOutError do begin Application.MessageBox(PChar(TextByKey('render-prestatus-saveerror-preset')), - PChar('Apophysis'), 16); + ApophysisSVN, 16); Exit; end; end; @@ -1216,7 +1250,8 @@ begin Renderer.DoSnapshot; // AV: to save mid-render images Renderer.SaveImage(FileName); - if ShowRenderImage then // AV + // 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), @@ -1236,8 +1271,7 @@ end; procedure TRenderForm.btnBrowseClick(Sender: TObject); var - fn: string; - ext: string; + fn, ext: string; begin SaveDialog.Filename := Filename; case renderFileFormat of @@ -1245,28 +1279,19 @@ begin 2: SaveDialog.DefaultExt := 'png'; 3: SaveDialog.DefaultExt := 'jpg'; end; - SaveDialog.filterIndex := renderFileFormat; - SaveDialog.Filter := Format('%s|*.bmp;*.dib;*.jpg;*.jpeg|%s|*.bmp;*.dib|%s|*.jpg;*.jpeg|%s|*.png|%s|*.*', - [TextByKey('common-filter-allimages'), TextByKey('common-filter-bitmap'), - TextByKey('common-filter-jpeg'), TextByKey('common-filter-png'), - TextByKey('common-filter-allfiles')]); - if OpenSaveFileDialog(RenderForm, SaveDialog.DefaultExt, SaveDialog.Filter, SaveDialog.InitialDir, TextByKey('common-browse'), fn, false, true, false, false) then - //if SaveDialog.Execute then + SaveDialog.FilterIndex := renderFileFormat; + if SaveDialog.Execute then begin - SaveDialog.FileName := fn; + fn := SaveDialog.FileName; ext := LowerCase(ExtractFileExt(fn)); - if (ext = '.bmp') then renderFileFormat := 1; - if (ext = '.png') then renderFileFormat := 2; - if ((ext = '.jpg') or (ext = '.jpeg')) then renderFileFormat := 3; - {case SaveDialog.FilterIndex of - 1: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.bmp'); - 2: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.png'); - 3: txtFilename.Text := ChangeFileExt(SaveDialog.Filename, '.jpg'); - end; } + 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); - //renderFileFormat := SaveDialog.FilterIndex; - renderPath := ExtractFilePath(SaveDialog.Filename); - + renderPath := ExtractFilePath(fn); end; end; @@ -1312,7 +1337,7 @@ end; procedure TRenderForm.cmbPresetChange(Sender: TObject); var - chk: byte; //boolean; // AV + chk: shortint; // AV i, j: integer; FStrings: TStringList; Title, Filename: string; @@ -1329,15 +1354,12 @@ begin for i := 0 to FStrings.Count - 1 do if Pos(LowerCase(Title) + ' {', Lowercase(FStrings[i])) <> 0 then begin - //chk := chkMaintain.checked; - //chkMaintain.Checked := False; chk := cbAspectRatio.ItemIndex; // AV cbAspectRatio.ItemIndex := 0; j := i + 1; cbWidth.Text := FStrings[j]; inc(j); cbHeight.text := FStrings[j]; - //chkMaintain.Checked := chk; cbAspectRatio.ItemIndex := chk; inc(j); txtDensity.text := FStrings[j]; @@ -1347,13 +1369,9 @@ begin txtOversample.text := FStrings[j]; inc(j); txtFileName.Text := ChangeFileExt(txtFileName.Text, FStrings[j]); - inc(j); - //if Fstrings[j] = 'true' then (not IsLimitingMemory) else chkLimitMem.checked := false; - inc(j); - cbMaxMemory.ItemIndex := StrToInt(Fstrings[j]); - //cbMaxMemory.enabled := chkLimitMem.checked; - inc(j); - cbMaxMemory.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 @@ -1366,13 +1384,6 @@ begin ShowMemoryStatus; end; -{ -procedure TRenderForm.chkMaintainClick(Sender: TObject); -begin - Ratio := ImageWidth / ImageHeight; -end; -} - procedure TRenderForm.DoPostProcess; begin frmPostProcess.cp := cp; @@ -1382,6 +1393,40 @@ begin 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; @@ -1390,15 +1435,17 @@ var rTTokenPvg: TTokenPrivileges; pcbtpPreviousRequired: DWORD; tpResult: Boolean; + WinVersion: TWin32Version; // AV const SE_SHUTDOWN_NAME = 'SeShutdownPrivilege'; begin - if ((GetWinVersion = wvWinNT) or - (GetWinVersion = wvWin2000) or - (GetWinVersion = wvWinXP) or - (GetWinVersion = wvWinVista) or - (GetWinVersion = wvWin7) or - (GetWinVersion = wvWinFutureFromOuterSpace)) then + 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, @@ -1436,7 +1483,7 @@ end; procedure TRenderForm.btnGoToClick(Sender: TObject); var - path:string; + path: string; begin path := ExtractFilePath(txtFilename.Text); if (path <> '') then WinShellExecute('open', path); @@ -1486,10 +1533,10 @@ var fn: string; sl: TStringList; begin - if OpenSaveFileDialog(RenderForm, '.log', + 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 + then begin sl := TStringList.Create; sl.Text := Output.Text; sl.SaveToFile(fn); diff --git a/Forms/Fullscreen.pas b/Forms/Fullscreen.pas index d2d7dcf..d5ea45e 100644 --- a/Forms/Fullscreen.pas +++ b/Forms/Fullscreen.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,7 +27,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - Menus, ExtCtrls, ControlPoint, RenderThread, Translation; + Menus, ExtCtrls, ControlPoint, RenderThread; type TFullscreenForm = class(TForm) @@ -50,8 +50,7 @@ type private Remainder, StartTime, t: double; - imgLeft, imgTop, - imgWidth, imgHeight: integer; + imgLeft, imgTop, imgWidth, imgHeight: integer; Closing: boolean; Renderer: TRenderThread; @@ -68,8 +67,6 @@ type public Calculate : boolean; cp: TControlPoint; - Zoom: double; - center: array[0..1] of double; ActiveForm: TForm; end; @@ -80,8 +77,7 @@ var implementation uses - Main, Math, Global, - Tracer; + Main, Math, Global, Tracer, Translation; {$R *.DFM} @@ -118,9 +114,6 @@ begin end; cp.AdjustScale(imgWidth, imgHeight); -// cp.Zoom := MainForm.Zoom; -// cp.center[0] := MainForm.center[0]; -// cp.center[1] := MainForm.center[1]; cp.sample_density := defSampleDensity; StartTime := Now; t := now; @@ -294,6 +287,12 @@ begin RenderMore.Caption := TextByKey('fullscreen-popup-rendermore'); RenderStop.Caption := TextByKey('fullscreen-popup-stoprender'); cp := TControlPoint.Create; + + // AV: moved following here from MainForm.mnuFullScreenClick + self.Width := Screen.Width; + self.Height := Screen.Height; + self.Top := 0; + self.Left := 0; end; procedure TFullscreenForm.FormDestroy(Sender: TObject); diff --git a/Forms/Main.dfm b/Forms/Main.dfm index 046164d..d74da9c 100644 --- a/Forms/Main.dfm +++ b/Forms/Main.dfm @@ -81,16 +81,9 @@ object MainForm: TMainForm OnKeyDown = FormKeyUpDown OnKeyPress = FormKeyPress OnKeyUp = FormKeyUpDown - OnResize = FormResize OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 - object Image1: TImage - Left = 48 - Top = 104 - Width = 105 - Height = 105 - end object Splitter: TSplitter Left = 161 Top = 22 @@ -139,16 +132,6 @@ object MainForm: TMainForm Ctl3D = True ParentCtl3D = False TabOrder = 1 - object Shape1: TShape - Left = 1 - Top = 1 - Width = 159 - Height = 649 - Align = alClient - Brush.Color = clWindow - Pen.Color = clWindow - ExplicitHeight = 748 - end object ListView1: TListView Left = 1 Top = 1 @@ -175,6 +158,7 @@ object MainForm: TMainForm OnColumnClick = ListViewColumnClick OnDblClick = ListViewDblClick OnEdited = ListViewEdited + OnSelectItem = ListViewSelectItem end end object cbMain: TCoolBar @@ -212,6 +196,7 @@ object MainForm: TMainForm ParentShowHint = False ShowHint = True TabOrder = 0 + OnResize = ToolBarResize object btNew: TToolButton Left = 0 Top = 0 @@ -425,9 +410,24 @@ object MainForm: TMainForm ImageIndex = 69 OnClick = tbCurvesClick end - object tbMutate: TToolButton + object tbImageSize: TToolButton Left = 462 Top = 0 + Hint = 'Image size | Change the image size' + Caption = 'tbImageSize' + ImageIndex = 14 + OnClick = mnuImageSizeClick + end + object tbAnimate: TToolButton + Left = 485 + Top = 0 + Caption = 'Animator' + ImageIndex = 76 + MenuItem = mnuAnimator + end + object tbMutate: TToolButton + Left = 508 + Top = 0 Hint = 'Mutation | Show randomly generated modifications of the current ' + 'flame' @@ -435,23 +435,15 @@ object MainForm: TMainForm ImageIndex = 17 OnClick = mnuMutateClick end - object tbImageSize: TToolButton - Left = 485 - Top = 0 - Hint = 'Image size | Change the image size' - Caption = 'tbImageSize' - ImageIndex = 14 - OnClick = mnuImageSizeClick - end object tbMessages: TToolButton - Left = 508 + Left = 531 Top = 0 Hint = 'Messages | Show error messages' ImageIndex = 63 OnClick = tbMessagesClick end object tbOptions: TToolButton - Left = 531 + Left = 554 Top = 0 Hint = 'Options | Change Apophysis default settings' Caption = 'tbOptions' @@ -459,7 +451,7 @@ object MainForm: TMainForm OnClick = mnuOptionsClick end object ToolButton15: TToolButton - Left = 554 + Left = 577 Top = 0 Width = 8 Caption = 'ToolButton15' @@ -467,7 +459,7 @@ object MainForm: TMainForm Style = tbsSeparator end object tbShowAlpha: TToolButton - Left = 562 + Left = 585 Top = 0 Hint = 'Show transparency | Show the flame on a transparent background' Caption = 'Show Alpha' @@ -476,7 +468,7 @@ object MainForm: TMainForm OnClick = tbShowAlphaClick end object tbGuides: TToolButton - Left = 585 + Left = 608 Top = 0 Hint = 'Show guidelines | Show flame thirds, center and golden ratio' Caption = 'Show guides' @@ -486,7 +478,7 @@ object MainForm: TMainForm OnClick = tbGuidesClick end object ToolButton16: TToolButton - Left = 608 + Left = 631 Top = 0 Width = 8 Caption = 'ToolButton16' @@ -494,7 +486,7 @@ object MainForm: TMainForm Style = tbsSeparator end object tbEditScript: TToolButton - Left = 616 + Left = 639 Top = 0 Hint = 'Edit script | Edit the script code' Caption = 'tbEditScript' @@ -502,7 +494,7 @@ object MainForm: TMainForm OnClick = mnuEditScriptClick end object btnRunScript: TToolButton - Left = 639 + Left = 662 Top = 0 Hint = 'Run script | Execute the current script' Caption = 'btnRunScript' @@ -510,7 +502,7 @@ object MainForm: TMainForm OnClick = mnuRunClick end object btnStopScript: TToolButton - Left = 662 + Left = 685 Top = 0 Hint = 'Stop script | To stop an animation script, you can press any key' + @@ -520,7 +512,7 @@ object MainForm: TMainForm OnClick = mnuStopClick end object ToolButton18: TToolButton - Left = 685 + Left = 708 Top = 0 Width = 8 Caption = 'ToolButton18' @@ -528,7 +520,7 @@ object MainForm: TMainForm Style = tbsSeparator end object tbDrag: TToolButton - Left = 693 + Left = 716 Top = 0 Hint = 'Translate the image | Translate the fractal image using mouse' Caption = 'tbDrag' @@ -539,7 +531,7 @@ object MainForm: TMainForm OnClick = tbDragClick end object tbRotate: TToolButton - Left = 716 + Left = 739 Top = 0 Hint = 'Rotate the camera | Rotate the fractal image using mouse' Caption = 'tbRotate' @@ -549,7 +541,7 @@ object MainForm: TMainForm OnClick = tbRotateClick end object tbZoomIn: TToolButton - Left = 739 + Left = 762 Top = 0 Hint = 'Zoom in | Scale up the fractal image using mouse' Caption = 'tbZoomIn' @@ -559,7 +551,7 @@ object MainForm: TMainForm OnClick = tbzoomwindowClick end object tbZoomOut: TToolButton - Left = 762 + Left = 785 Top = 0 Hint = 'Zoom out | Scale down the fractal image using mouse' Caption = 'tbZoomOut' @@ -569,7 +561,7 @@ object MainForm: TMainForm OnClick = tbzoomoutwindowClick end object ToolButton23: TToolButton - Left = 785 + Left = 808 Top = 0 Width = 8 Caption = 'ToolButton23' @@ -630,131 +622,131 @@ object MainForm: TMainForm Left = 104 Top = 280 Bitmap = { - 494C01014C005000040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 + 494C01014D005000040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000004001000001002000000000000040 0100000000000000000000000000000000000000000000000000000000000000 + 000018435A002B6289004C8ABE0070A9CC00E3EDF50000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000004E4E4E002D2D2D00505050000000 + 00002E67850094C7F90091C9F9004185C900276BAE002D3B4700050505002525 + 2500000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000038383800B0B0B000353535005757 + 57004389AA00E0F2FF00549AD8001A7ABE004998C5003177B0009EACB8001515 + 1500000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000003A3A3A0062626200383838006FDF + 9D0055B2A0007AB6D50090B7D10055C9E4005BDFF50078D0ED004491D1000F1B + 2500000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000063636300ACACAC00575757004FCB + 5C0057D77A0035B8830073B8D300C2F6FD0063DFF7005DE2F80079D3F0004392 + D500E6F1FA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000005C5C5C006D6D6D005F5F5F004FC4 + 45004BBA2C00D8BD6000B1A87F0077CBE700C7F7FD005EDCF5005AE1F7007BD4 + F1004C9ADE00D6E8F70000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006565650089898900656565007FBF + 3600DDC56900FFC27000FFBF670086C3BA0079D3EE00C7F7FD005FDCF5005BE2 + F7007AD6F20051A2E200DCEAF600000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006E6E6E00A4A4A4006C6C6C00F8C6 + 6E00FFC87700FFC57200FFC46C0098D8CF0078D7E9007BD3EC00C4F6FD006CDD + F6006DCAED0063A3D70069A2D500E5EFF7000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006969690071717100686868005757 + 570057575700575757005757570057575700575757002C5D6D007DD2EA00B2E3 + F9008BC0E700AED3F600C4E0FC006BA2D4000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000077777700AAAAAA007474740072E2 + 9E007CE3A40078E3A00063E095005AE1950055E29300565656006CA1B00077BE + E700B4D2F000E5F3FF00ACD2EF005996CC000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000007777770097979700777777004FCB + 5C0057D77A0042D16A0070C75E00B6B85000CBAE3F005B5B5B007C7C7C00426C + 7A0058A5D80085B1DB00469DD000B1D8EE000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000077777700858585007A7A7A004FC4 + 45004BBA2C00D8BD6000FFBA6200FFB96500DBBB7D005E5E5E00656565004B4B + 4B00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000083838300AFAFAF007C7C7C007FBF + 3600DDC56900FFC27000FFBF6700AECBAC0068E0F90060606000ACACAC005C5C + 5C00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000006C6C6C007474740068686800E6BC + 7100EDBE7900ECBB7300ECB96D0084CDCF0084D8EB004B4B4B00686868003D3D + 3D00000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000073737300A6A6A600696969005757 + 570057575700575757005757570057575700575757004D4D4D009A9A9A006262 + 6200000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000008989890076767600808080000000 + 000000000000000000000000000000000000000000006E6E6E00515151006666 + 6600000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 @@ -3194,11 +3186,11 @@ object MainForm: TMainForm 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000400100000100010000000000000A00000000000000000000 - 000000000000000000000000FFFFFF0000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000FFFFFFFFFFFFFFFFFF9FF80F81FFFFFF + 000000000000000000000000FFFFFF00F07F000000000000100F000000000000 + 000F000000000000000F00000000000000070000000000000003000000000000 + 0001000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000F000000000000000F000000000000000F000000000000 + 000F0000000000001F8F000000000000FFFFFFFFFFFFFFFFFF9FF80F81FFFFFF F187E0078007C7FFE083C003C103C2FFC213C001C411F207C7138001C801F187 F111800188C8F10FC00080018308F903800C80019019F89387018001CC23F8FF 800380018027F07FC0818003240FFCFFC683C003203FFC1FFC17E00707FFFE1F @@ -3283,7 +3275,6 @@ object MainForm: TMainForm Top = 168 object MainFile: TMenuItem Caption = '&File' - OnClick = MainMenuClick object New1: TMenuItem Caption = 'New...' ImageIndex = 65 @@ -3374,7 +3365,6 @@ object MainForm: TMainForm end object MainEdit: TMenuItem Caption = '&Edit' - OnClick = MainMenuClick object mnuUndo: TMenuItem Caption = '&Undo' Enabled = False @@ -3461,6 +3451,12 @@ object MainForm: TMainForm ShortCut = 119 OnClick = tbCurvesClick end + object mnuAnimator: TMenuItem + Caption = 'Animator' + ImageIndex = 76 + ShortCut = 122 + OnClick = mnuAnimatorClick + end object N5: TMenuItem Caption = '-' end @@ -3477,7 +3473,6 @@ object MainForm: TMainForm end object MainFlame: TMenuItem Caption = 'Flame' - OnClick = MainMenuClick object mnuResetLocation: TMenuItem Caption = 'Reset Location' ImageIndex = 12 @@ -3629,7 +3624,6 @@ object MainForm: TMainForm end object AddTile: TMenuItem Caption = 'Add equiaffine tile...' - OnClick = AddTileClick object Rhombic1: TMenuItem Tag = 1 Caption = 'Rhombus' @@ -3863,9 +3857,7 @@ object MainForm: TMainForm end end object OpenDialog: TOpenDialog - Filter = - 'Apophysis Parameter Files (*.apo)|*.apo|Apophysis 1.0 Parameters' + - ' (*fla)|*.fla|IFS Files (*.ifs)|*.ifs' + Filter = 'Apophysis Parameter Files (*.flame)|*.flame' Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] Left = 24 Top = 456 diff --git a/Forms/Main.pas b/Forms/Main.pas index e425288..346113d 100644 --- a/Forms/Main.pas +++ b/Forms/Main.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -32,46 +32,41 @@ interface uses Windows, Forms, Dialogs, Menus, Controls, ComCtrls, - ToolWin, StdCtrls, Classes, Messages, ExtCtrls, ImgList, - Jpeg, SyncObjs, SysUtils, Graphics, Math, - ExtDlgs, AppEvnts, ShellAPI, Registry, Curves, + StdCtrls, Classes, Messages, ExtCtrls, ImgList, System.ImageList, + Vcl.Imaging.Jpeg, SyncObjs, SysUtils, Graphics, Math, Vcl.ToolWin, + ExtDlgs, AppEvnts, ShellAPI, Registry, Global, Xform, XFormMan, ControlPoint, CMap, RenderThread, RenderingCommon, RenderingInterface, - LibXmlParser, LibXmlComps, Vcl.Imaging.PngImage, XPMan, - StrUtils, LoadTracker, CheckLst, - CommandLine, RegularExpressionsCore, Translation, - RegexHelper, System.ImageList, Vcl.Themes, Vcl.Styles; // AV + LibXmlParser, LibXmlComps, Vcl.Imaging.PngImage, + StrUtils, LoadTracker, CommandLine, Translation, + RegularExpressionsCore, RegexHelper, Vcl.Themes, Vcl.Styles; // AV const - PixelCountMax = 32768; - RS_A1 = 0; - RS_DR = 1; - RS_XO = 2; - RS_VO = 3; + mbHeight = 30; // AV: height (in items) of all styled submenus - {$ifndef Apo7X64} + {$ifdef CPUX86} randFilename = 'ApophysisAV.rand'; undoFilename = 'ApophysisAV.undo'; + ApophysisSVN = 'Apophysis AV (32 bit)'; // AV: the caption for all dialogs {$else} randFilename = 'ApophysisAV_64.rand'; // AV undoFilename = 'ApophysisAV_64.undo'; // AV + ApophysisSVN = 'Apophysis AV (64 bit)'; {$endif} templateFilename = 'ApophysisAV.temp'; - templatePath = '\templates'; - scriptPath = '\scripts'; + //templatePath = '\templates'; + // AV: hmm, we have a global variable with the same name... + // scriptPath = '\scripts'; type TMouseMoveState = (msUsual, msZoomWindow, msZoomOutWindow, msZoomWindowMove, - msZoomOutWindowMove, msDrag, msDragMove, msRotate, msRotateMove, msPitchYaw, msHeight); - -type - TWin32Version = (wvUnknown, wvWin95, wvWin98, wvWinNT, wvWin2000, wvWinXP, - wvWinVista, wvWin7, wvWinFutureFromOuterSpace); + msZoomOutWindowMove, msDrag, msDragMove, msRotate, + msRotateMove, msPitchYaw, msHeight); type TThumbnailThread = class(TThread) private - FCount: integer; + FlameItems: TListItems; class var FPreviewDensity: double; // AV FThumbnailSize : integer; // AV: added F to avoid of name conflicts @@ -81,10 +76,6 @@ type destructor Destroy; override; end; -type - pRGBTripleArray = ^TRGBTripleArray; - TRGBTripleArray = array[0..PixelCountMax - 1] of TRGBTriple; - TMainForm = class(TForm) Buttons: TImageList; MainMenu: TMainMenu; @@ -174,10 +165,8 @@ type mnuBuiltinVars: TMenuItem; mnuPluginVars: TMenuItem; UsedThumbnails: TImageList; - Image1: TImage; Splitter: TSplitter; ListBackPanel: TPanel; - Shape1: TShape; ListView1: TListView; cbMain: TCoolBar; ToolBar: TToolBar; @@ -293,7 +282,9 @@ type EnumerateFlames: TMenuItem; DownloadPlugins: TMenuItem; N27: TMenuItem; - mnuRefreshAllThumbs: TMenuItem; // AV + mnuRefreshAllThumbs: TMenuItem; + mnuAnimator: TMenuItem; + tbAnimate: TToolButton; // AV procedure mnuManualClick(Sender: TObject); procedure mnuReportFlameClick(Sender: TObject); procedure mnuTurnFlameToScriptClick(Sender: TObject); @@ -314,7 +305,6 @@ type procedure mnuOptionsClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure mnuHelpTopicsClick(Sender: TObject); - procedure mnuRefreshClick(Sender: TObject); procedure mnuNormalWeightsClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure mnuCopyUPRClick(Sender: TObject); @@ -323,12 +313,9 @@ type var S: string); procedure mnuListRenameClick(Sender: TObject); procedure BackPanelResize(Sender: TObject); - procedure mnuNextClick(Sender: TObject); - procedure mnuPreviousClick(Sender: TObject); procedure RedrawTimerTimer(Sender: TObject); procedure FormShow(Sender: TObject); procedure ShowStyledWindows(Sender: TObject); - procedure MainMenuClick(Sender: TObject); procedure mnuVRandomClick(Sender: TObject); procedure mnuSaveAsClick(Sender: TObject); procedure mnuOpenClick(Sender: TObject); @@ -361,7 +348,6 @@ type procedure mnuStopClick(Sender: TObject); // procedure mnuImportGimpClick(Sender: TObject); // AV: rudiment from Apo 2.02 procedure mnuManageFavoritesClick(Sender: TObject); - procedure mnuShowFullClick(Sender: TObject); procedure mnuImageSizeClick(Sender: TObject); procedure ApplicationEventsActivate(Sender: TObject); procedure mnuPasteClick(Sender: TObject); @@ -371,6 +357,7 @@ type procedure ListXmlScannerStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); + procedure XmlScannerComment(Sender: TObject; Comment: string); // AV procedure XMLScannerStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); procedure XMLScannerEmptyTag(Sender: TObject; TagName: string; @@ -393,14 +380,12 @@ type procedure tbShowTraceClick(Sender: TObject); procedure XmlScannerContent(Sender: TObject; Content: String); procedure mnuRenderAllClick(Sender: TObject); -{ procedure ListViewChanging(Sender: TObject; Item: TListItem; - Change: TItemChange; var AllowChange: Boolean); } procedure btnViewIconsClick(Sender: TObject); procedure btnViewListClick(Sender: TObject); procedure XmlScannerEndTag(Sender: TObject; TagName: String); procedure tbMessagesClick(Sender: TObject); procedure btNewClick(Sender: TObject); - procedure FormResize(Sender: TObject); + procedure ToolBarResize(Sender: TObject); procedure mnuResetUIClick(Sender: TObject); procedure AutoSaveTimerTimer(Sender: TObject); procedure Restorelastautosave1Click(Sender: TObject); @@ -428,6 +413,9 @@ type procedure EnumerateFlamesClick(Sender: TObject); procedure ListViewDblClick(Sender: TObject); procedure DownloadPluginsClick(Sender: TObject); + procedure mnuAnimatorClick(Sender: TObject); + procedure ListViewSelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); private SubstSource: TStringList; SubstTarget: TStringList; @@ -465,12 +453,15 @@ type procedure DrawZoomWindow; procedure DrawRotatelines(Angle: double); // procedure DrawPitchYawLines(YawAngle: double; PitchAngle:double); + procedure SetAutoSaveTimer; // AV + procedure RunThumbnailThread; inline; procedure FillVariantMenu; procedure VariantMenuClick(Sender: TObject); procedure FavoriteClick(Sender: TObject); procedure ScriptItemClick(Sender: TObject); + procedure StopScripter; // AV // AV: for Apo GUI themes procedure CreateStyleList; @@ -485,9 +476,7 @@ type { Public declarations } UndoIndex, UndoMax: integer; Center: array[0..1] of double; - //MainZoom: double; StartTime: TDateTime; - CurrentFileName: string; ParseLoadingBatch : boolean; SurpressHandleMissingPlugins : boolean; @@ -497,7 +486,6 @@ type XmlScanner : TXmlScanner; function ReadWithSubst(Attributes: TAttrList; attrname: string): string; - procedure InvokeLoadXML(xmltext:string); // AV: added 3-rd parameter to be able to discard multiple updates procedure LoadXMLFlame(filename, name: string; upd: boolean = true); procedure DisableFavorites; @@ -508,7 +496,7 @@ type procedure DisplayHint(Sender: TObject); procedure OnProgress(prog: double); procedure ResizeImage; - procedure DrawPreview; + // procedure DrawPreview; procedure DrawFlame; procedure UpdateUndo; procedure LoadUndoFlame(index: integer; filename: string); @@ -526,7 +514,7 @@ type function ApplicationOnHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; function SystemErrorMessage: string; function SystemErrorMessage2(errno: cardinal): string; - function RetrieveXML(cp : TControlPoint):string; + // function RetrieveXML(cp : TControlPoint): string; // AV: we can call it directly procedure ApplyThemedColors; // AV: for reading / writing embedded parameters @@ -538,57 +526,62 @@ type procedure SetThumbnailProperties; procedure RefreshThumbnail; procedure UpdateThumbnails; + procedure AddFlameToList(const title: string = ''); end; procedure ListXML(FileName: string; sel: integer; selname: string = ''); // AV +procedure ListIFS(FileName: string; sel: integer); // AV: for loading Undo flame files +function FlameToXML(const cp1: TControlPoint; exporting: boolean = false; title: string = ''): string; // AV: make global +function LoadXMLFlameText(filename, name: string) : string; +function FindFlameXML(const FlameStr: string; const Title: string) : Integer; // AV +procedure FlameFromUndo(cp: TControlPoint; const FlameName: string; const ParamFile: string); // AV + function EntryExists(En, Fl: string): boolean; function XMLEntryExists(title, filename: string): boolean; function DeleteEntry(Entry, FileName: string): boolean; function CleanIdentifier(ident: string): string; function CleanUPRTitle(ident: string): string; + function GradientString(c: TColorMap): string; -procedure ListFlames(FileName: string; sel: integer); // AV: outdated, for affine coefs only -procedure ListIFS(FileName: string; sel: integer); // AV: for loading Undo flame files -procedure NormalizeVariations(var cp1: TControlPoint); -function GetWinVersion: TWin32Version; -function LoadXMLFlameText(filename, name: string) : string; -function FindFlameXML(const FlameStr: string; const Title: string) : Integer; // AV +procedure RotateCMapHue(var cp: TControlPoint); // AV function FlameInClipboard: boolean; // AV function RemoveExt(filename: string): string; // AV +function WinShellExecute(const Operation, AssociatedFile: string): Boolean; // AV + // AV: for making window screenshots procedure GetFormScreenShot(const AFileName: string); procedure SaveScreenShot(const AFormName: string); var MainForm: TMainForm; - pname, ptime: String; - //pversion: string; + pname, ptime: string; + // pversion: string; nxform: integer; - TbBreakWidth: integer; MainCp: TControlPoint; ParseCp: TControlPoint; MemCp: TControlPoint; - CurrentFlame, FlameString: string; ThumbnailSize: integer; - AboutToExit: boolean; GeneratingThumbs: boolean; // AV - ApophysisSVN: string; //APP_VERSION; - AppVersionString: string; //APP_NAME+'.'+ APP_VERSION; + AppVersionString: string; implementation uses - ClipBrd, Editor, Options, Settings, Template, MissingPlugin, Base64, Chaotica, + ClipBrd, Editor, Options, Settings, Template, MissingPlugin, Chaotica, FullScreen, FormRender, Mutate, Adjust, Browser, Save, About, CmapData, - ScriptForm, FormFavorites, FormExport, RndFlame, Tracer, Types, SplashForm; + ScriptForm, FormFavorites, FormExport, RndFlame, Tracer, Types, SplashForm, + Animate; + +const + TbBreakWidth = 810; // AV {$R *.DFM} -procedure AssignBitmapProperly(var Bitmap:TBitmap; Source:TBitmap); +procedure AssignBitmapProperly(var Bitmap: TBitmap; Source: TBitmap); begin Bitmap.Dormant; Bitmap.FreeImage; @@ -596,7 +589,7 @@ begin Bitmap.Assign(Source); end; -procedure FreeBitmapProperly(var Bitmap:TBitmap); +procedure FreeBitmapProperly(var Bitmap: TBitmap); begin try Bitmap.Dormant; @@ -645,41 +638,16 @@ begin try GetFormScreenShot(s); Application.MessageBox(PChar(Format(TextByKey('common-screenshot-saved'), - [ExtractFileName(s), ExtractFilePath(s)])), PChar('Apophysis AV'), MB_ICONINFORMATION); + [ExtractFileName(s), ExtractFilePath(s)])), + ApophysisSVN, MB_ICONINFORMATION); except - Application.MessageBox(PChar(TextByKey('common-screenshot-error')), PChar('Apophysis AV'), MB_ICONERROR); + Application.MessageBox(PChar(TextByKey('common-screenshot-error')), + ApophysisSVN, MB_ICONERROR); end; end; {//////////////////////////////////////////////////////////////////////////////} -procedure NormalizeVariations(var cp1: TControlPoint); -var - totvar, v: double; - i, j: integer; -begin - for i := 0 to NXFORMS - 1 do - begin - totvar := 0; - for j := 0 to NRVAR - 1 do - begin - v := cp1.xform[i].GetVariation(j); // AV - if v < 0 then - cp1.xform[i].SetVariation(j, -v); - totvar := totvar + v; - end; - if totVar = 0 then - begin - cp1.xform[i].SetVariation(0, 1) - end - else - for j := 0 to NRVAR - 1 do begin - if totVar <> 0 then - cp1.xform[i].SetVariation(j, cp1.xform[i].GetVariation(j) / totvar); - end; - end; -end; - function FlameInClipboard: boolean; var flamestr: string; @@ -697,36 +665,6 @@ begin end; end; -function GetWinVersion: TWin32Version; -{ Returns current version of a host Win32 platform } -begin - Result := wvUnknown; - if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then - if (Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and (Win32MinorVersion > 0)) then - Result := wvWin98 - else - Result := wvWin95 - else - if Win32MajorVersion <= 4 then - Result := wvWinNT - else if Win32MajorVersion = 5 then - begin // AV - if Win32MinorVersion = 0 then - Result := wvWin2000 - else if Win32MinorVersion >= 1 then - Result := wvWinXP - end - else if Win32MajorVersion = 6 then - begin // AV - if Win32MinorVersion = 0 then - Result := wvWinVista - else if Win32MinorVersion >= 1 then - Result := wvWin7 - end - else if Win32MajorVersion >= 7 then - Result := wvWinFutureFromOuterSpace; -end; - { ************************************* Help ********************************* } procedure ShowHelp(Pt: TPoint; ContextId: Integer); @@ -755,33 +693,6 @@ begin inherited; end; -(* -procedure TMainForm.RebuildListView; -var - i: integer; - item: TListItem; -begin - ListView.Items.Clear; - - /// backup in old lv - for i := 0 to ListView1.Items.Count-1 do begin - item := ListView.Items.Add; - item.Caption := ListView1.Items[i].Caption; - end; - - // rebuild new lv - ListView1.Items.Clear; - - for i := 0 to ListView.Items.Count-1 do begin - item := ListView1.Items.Add; - item.Caption := ListView.Items[i].Caption; - if (not ClassicListMode) then item.ImageIndex := i; - end; - - ListView.Items.Clear; -end; -*) - procedure TMainForm.InsertStrings; begin mnuCopy.Caption := TextByKey('common-copy'); @@ -830,8 +741,6 @@ begin mnuSaveUPR.Caption := TextByKey('main-menu-file-exportupr'); mnuExportFlame.Caption := TextByKey('main-menu-file-exportflame'); mnuExportChaotica.Caption := TextByKey('main-menu-file-exportchaotica'); - // mnuImportGimp.Caption := TextByKey('main-menu-file-importgimp'); - // mnuImportGimp.Hint := TextByKey('main-menu-file-importgimphint'); mnuRandomBatch.Caption := TextByKey('main-menu-file-randombatch'); mnuExit.Caption := TextByKey('main-menu-file-exit'); mnuExit.Hint := TextByKey('main-menu-file-exithint'); @@ -870,6 +779,9 @@ begin tbCurves.Hint := TextByKey('main-toolbar-curves'); mnuCurves.Hint := TextByKey('main-toolbar-curves'); mnuCurves.Caption := TextByKey('main-menu-view-curves'); + tbAnimate.Hint := TextByKey('main-toolbar-animator'); + mnuAnimator.Caption := TextByKey('main-menu-view-animator'); // AV + mnuAnimator.Hint := GetLongHint(tbAnimate.Hint); // AV MainFlame.Caption := TextByKey('main-menu-flame-title'); mnuResetLocation.Caption := TextByKey('main-menu-flame-reset'); mnuPopResetLocation.Caption := TextByKey('main-menu-flame-reset'); @@ -986,11 +898,6 @@ begin DihedralSym.Caption := TextByKey('options-tab-random-type-dihedral') + TextByKey('main-menu-flame-symorder'); end; -procedure TMainForm.InvokeLoadXML(xmltext: string); -begin - ParseXML(MainCP, PCHAR(xmltext), false); -end; - function TMainForm.ApplicationOnHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; var Pos: TPoint; @@ -1012,7 +919,7 @@ var AStyle: TCustomStyleServices; MenuC1, MenuC2: TColor; mb: TMenuBreak; - i: integer; + i: smallint; begin AStyle := TStyleManager.ActiveStyle; CurrentStyle := AStyle.Name; @@ -1044,12 +951,19 @@ begin or (CurrentStyle = 'Cobalt XEMedia') or (CurrentStyle = 'Onyx Blue') or (CurrentStyle = 'Ruby Graphite') or (CurrentStyle = 'Golden Graphite'); + if (CurrentStyle = 'Windows') then mb := mbNone + else mb := mbBreak; i := 0; - if (CurrentStyle = 'Windows') then mb := mbNone else mb := mbBreak; - while i < length(VarMenus) do + while i < mnuBuiltinVars.Count do begin - VarMenus[i].Break := mb; - inc(i, 30); + mnuBuiltinVars[i].Break := mb; + inc(i, mbHeight); + end; + i := 0; + while i < mnuPluginVars.Count do + begin + mnuPluginVars[i].Break := mb; + inc(i, mbHeight); end; end; @@ -1092,6 +1006,9 @@ begin end; *) +(* +// AV: commented out since we have the same methods in RndFlame unit! + procedure RandomVariation(cp: TControlPoint); { Randomise variation parameters } var @@ -1138,6 +1055,7 @@ begin cp.xform[i].SetVariation(integer(Variation), 1); end; end; +*) function FindFlameXML(const FlameStr: string; const Title: string) : Integer; var @@ -1164,7 +1082,7 @@ end; procedure TMainForm.RandomizeColorSpeed1Click(Sender: TObject); var - i: integer; + i: smallint; begin inc(MainSeed); RandSeed := MainSeed; @@ -1216,23 +1134,6 @@ begin end; end; -function CleanIdentifier(ident: string): string; -{ Strips unwanted characters from an identifier} -var - i: integer; -begin - for i := 0 to Length(ident) do - begin - if ident[i] = #32 then - ident[i] := '_' - else if ident[i] = '}' then - ident[i] := '_' - else if ident[i] = '{' then - ident[i] := '_'; - end; - Result := ident; -end; - procedure TMainForm.OnProgress(prog: double); var Elapsed, Remaining: TDateTime; @@ -1283,6 +1184,7 @@ begin AdjustForm.btnRedo.enabled := false; end; +(* function GradientEntries(gFilename: string): string; var i, p: integer; @@ -1317,6 +1219,15 @@ begin end; end; +function GradTitle(str: string): string; +var + p: integer; +begin + p := pos('{', str); + GradTitle := Trim(copy(str, 1, p - 1)); +end; +*) + { ********************************* File ************************************* } function EntryExists(En, Fl: string): boolean; @@ -1342,23 +1253,6 @@ begin Result := False; end; -function CleanEntry(ident: string): string; -{ Strips unwanted characters from an identifier} -var - i: integer; -begin - for i := 1 to Length(ident) do - begin - if ident[i] = #32 then - ident[i] := '_' - else if ident[i] = '}' then - ident[i] := '_' - else if ident[i] = '{' then - ident[i] := '_'; - end; - Result := ident; -end; - function CleanXMLName(ident: string): string; var i: integer; @@ -1373,6 +1267,16 @@ begin Result := ident; end; +function CleanIdentifier(ident: string): string; +{ Strips unwanted characters from an identifier} +var + i: integer; +begin + for i := 1 to Length(ident) do + if (ident[i] = #32) or (ident[i] = '}') or (ident[i] = '{') then + ident[i] := '_'; + Result := ident; +end; function CleanUPRTitle(ident: string): string; { Strips braces but leave spaces } @@ -1380,12 +1284,9 @@ var i: integer; begin for i := 1 to Length(ident) do - begin - if ident[i] = '}' then - ident[i] := '_' - else if ident[i] = '{' then + if (ident[i] = '}') or (ident[i] = '{') then ident[i] := '_'; - end; + Result := ident; end; @@ -1432,14 +1333,15 @@ begin ReWrite(UPRFile); WriteLn(UPRFile, MainForm.UPRString(MainCp, Entry)); CloseFile(UPRFile); - except on E: EInOutError do + except on EInOutError do begin - Application.MessageBox(PChar(Format(TextByKey('common-genericsavefailure'), [FileName])), 'Apophysis', 16); Result := False; + raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]); end; end; end; +(* // AV: outdated, for affine coefs only function IFSToString(cp: TControlPoint; Title: string): string; { Creates a string containing a formated IFS parameter set } var @@ -1449,7 +1351,7 @@ var begin Strings := TStringList.Create; try - Strings.Add(CleanEntry(Title) + ' {'); + Strings.Add(CleanIdentifier(Title) + ' {'); for i := 0 to Transforms - 1 do begin a := cp.xform[i].c[0][0]; @@ -1468,170 +1370,22 @@ begin Strings.Free; end; end; +*) -function GetTitle(str: string): string; +procedure RotateCMapHue(var cp: TControlPoint); // AV var - p: integer; + i: byte; + h, s, v: real; + hue: double; begin - str := Trim(str); - p := Pos(' ', str); - GetTitle := Trim(Copy(str, 1, p)); -end; - -function GetComment(str: string): string; -{ Extracts comment form line of IFS file } -var - p: integer; -begin - str := Trim(str); - p := Pos(';', str); - if p <> 0 then - GetComment := Trim(Copy(str, p + 1, Length(str) - p)) - else - GetComment := ''; -end; - -function GetParameters(str: string; var a, b, c, d, e, f, p: double): boolean; -var - Tokens: TStringList; -begin - GetParameters := False; - Tokens := TStringList.Create; - try - try - GetTokens(str, tokens); - if Tokens.Count >= 7 then {enough tokens} - begin - a := StrToFloat(Tokens[0]); - b := StrToFloat(Tokens[1]); - c := StrToFloat(Tokens[2]); - d := StrToFloat(Tokens[3]); - e := StrToFloat(Tokens[4]); - f := StrToFloat(Tokens[5]); - p := StrToFloat(Tokens[6]); - Result := True; - end; - except on E: EConvertError do - begin - Result := False - end; - end; - finally - Tokens.Free; - end; -end; - -function StringToIFS(strng: string): boolean; -{ Loads an IFS parameter set from string} -var - Strings: TStringList; - Comments: TStringList; - i, sTransforms: integer; - cmnt, sTitle: string; - a, b, c, d: double; - e, f, p: double; -begin - MainCp.clear; - StringToIFS := True; - sTransforms := 0; - Strings := TStringList.Create; - Comments := TStringList.Create; - try - try - Strings.Text := strng; - if Pos('}', Strings.Text) = 0 then - raise EFormatInvalid.Create('No closing brace'); - if Pos('{', Strings[0]) = 0 then - raise EFormatInvalid.Create('No opening brace.'); - {To Do ... !!!!} - sTitle := GetTitle(Strings[0]); - if sTitle = '' then raise EFormatInvalid.Create('No identifier.'); - cmnt := GetComment(Strings[0]); - if cmnt <> '' then Comments.Add(cmnt); - i := 1; - try - repeat - cmnt := GetComment(Strings[i]); - if cmnt <> '' then Comments.Add(cmnt); - if (Pos(';', Trim(Strings[i])) <> 1) and (Trim(Strings[i]) <> '') then - if GetParameters(Strings[i], a, b, c, d, e, f, p) then - begin - MainCp.xform[sTransforms].c[0][0] := a; - MainCp.xform[sTransforms].c[0][1] := c; - MainCp.xform[sTransforms].c[1][0] := b; - MainCp.xform[sTransforms].c[1][1] := d; - MainCp.xform[sTransforms].c[2][0] := e; - MainCp.xform[sTransforms].c[2][1] := f; - MainCp.xform[sTransforms].density := p; - inc(sTransforms); - end - else - EFormatInvalid.Create('Insufficient parameters.'); - inc(i); - until (Pos('}', Strings[i]) <> 0) or (sTransforms = NXFORMS); - except on E: EMathError do - end; - if sTransforms < 2 then - raise EFormatInvalid.Create('Insufficient parameters.'); - MainCp.name := sTitle; - Transforms := sTransforms; - for i := 1 to Transforms - 1 do - MainCp.xform[i].color := 0; - MainCp.xform[0].color := 1; - - except on E: EFormatInvalid do - begin - Application.MessageBox(PChar(TextByKey('common-invalidformat')), PChar('Apophysis'), 16); - end; - end; - finally - Strings.Free; - Comments.Free; - end; -end; - - -function SaveIFS(cp: TControlPoint; Title, FileName: string): boolean; -{ Saves IFS parameters to end of file } -var - a, b, c: double; - d, e, f, p: double; - m: integer; - IFile: TextFile; -begin - Result := True; - try - AssignFile(IFile, FileName); - if FileExists(FileName) then + hue := cp.hue_rotation; + if (hue > 0) and (hue < 1) then // has visual effect + for i := 0 to 255 do begin - if EntryExists(Title, FileName) then DeleteEntry(Title, FileName); - Append(IFile); - end - else - ReWrite(IFile); - WriteLn(IFile, Title + ' {'); - for m := 0 to Transforms - 1 do - begin - a := cp.xform[m].c[0][0]; - c := cp.xform[m].c[0][1]; - b := cp.xform[m].c[1][0]; - d := cp.xform[m].c[1][1]; - e := cp.xform[m].c[2][0]; - f := cp.xform[m].c[2][1]; - p := cp.xform[m].density; - Write(IFile, Format('%.6g %.6g %.6g %.6g %.6g %.6g %.6g', - [a, b, c, d, e, f, p])); - WriteLn(IFile, ''); + RGBToHSV(cp.cmap[i][0], cp.cmap[i][1], cp.cmap[i][2], h, s, v); + h := Round(360 + h + (hue * 360)) mod 360; + HSVToRGB(h, s, v, cp.cmap[i][0], cp.cmap[i][1], cp.cmap[i][2]); end; - WriteLn(IFile, '}'); - WriteLn(IFile, ' '); - CloseFile(IFile); - except on E: EInOutError do - begin - Application.MessageBox(PChar(Format(TextByKey('common-genericsavefailure'), [FileName])), 'Apophysis', 16); - Result := False; - end; - end; end; function TMainForm.SaveFlame(cp1: TControlPoint; title, filename: string): boolean; @@ -1672,8 +1426,8 @@ begin except on EInOutError do begin - Application.MessageBox(PChar(Format(TextByKey('common-genericsavefailure'), [FileName])), 'Apophysis', 16); Result := False; + raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]); end; end; end; @@ -1706,140 +1460,7 @@ begin end; end; - -function FlameToXMLAS(const cp1: TControlPoint; title: string; exporting: boolean): string; -var - t, i{, j}: integer; - FileList: TStringList; - x, y: double; - parameters: string; - curves, str: string; -begin - FileList := TStringList.create; - x := cp1.center[0]; - y := cp1.center[1]; - -// if cp1.cmapindex >= 0 then pal := pal + 'gradient="' + IntToStr(cp1.cmapindex) + '" '; - - try - parameters := 'version="' + AppVersionString + '" '; - if cp1.time <> 0 then - parameters := parameters + format('time="%g" ', [cp1.time]); - - parameters := parameters + - 'size="' + IntToStr(cp1.width) + ' ' + IntToStr(cp1.height) + - format('" center="%g %g" ', [x, y]) + - format('scale="%g" ', [cp1.pixels_per_unit]); - - if cp1.FAngle <> 0 then - parameters := parameters + format('angle="%g" ', [cp1.FAngle]) + - format('rotate="%g" ', [-180 * cp1.FAngle/Pi]); - if cp1.zoom <> 0 then - parameters := parameters + format('zoom="%g" ', [cp1.zoom]); - -// 3d - if cp1.cameraPitch <> 0 then - parameters := parameters + format('cam_pitch="%g" ', [cp1.cameraPitch]); - if cp1.cameraYaw <> 0 then - parameters := parameters + format('cam_yaw="%g" ', [cp1.cameraYaw]); - if cp1.cameraRoll <> 0 then - parameters := parameters + format('cam_roll="%g" ', [cp1.cameraRoll]); - if cp1.cameraPersp <> 0 then - parameters := parameters + format('cam_perspective="%g" ', [cp1.cameraPersp]); - if cp1.cameraZpos <> 0 then - parameters := parameters + format('cam_zpos="%g" ', [cp1.cameraZpos]); - if cp1.cameraDOF <> 0 then - parameters := parameters + format('cam_dof="%g" ', [cp1.cameraDOF]); -// - parameters := parameters + format( - 'oversample="%d" filter="%g" quality="%g" ', - [cp1.spatial_oversample, - cp1.spatial_filter_radius, - cp1.sample_density] - ); - if cp1.nbatches <> 1 then parameters := parameters + 'batches="' + IntToStr(cp1.nbatches) + '" '; - if cp1.hue_rotation <> 1 then parameters := parameters + format('hue="%g" ', [cp1.hue_rotation]); // AV - - parameters := parameters + - format('background="%g %g %g" ', [cp1.background[0] / 255, cp1.background[1] / 255, cp1.background[2] / 255]) + - format('brightness="%g" ', [cp1.brightness]) + - format('gamma="%g" ', [cp1.gamma]); - - if cp1.contrast <> 1 then // AV - parameters := parameters + format('contrast="%g" ', [cp1.contrast]); - - if cp1.vibrancy <> 1 then - parameters := parameters + format('vibrancy="%g" ', [cp1.vibrancy]); - - if cp1.gamma_threshold <> 0 then - parameters := parameters + format('gamma_threshold="%g" ', [cp1.gamma_threshold]); - - if cp1.soloXform >= 0 then - parameters := parameters + format('soloxform="%d" ', [cp1.soloXform]); - - parameters := parameters + - format('estimator_radius="%g" ', [cp1.estimator]) + - format('estimator_minimum="%g" ', [cp1.estimator_min]) + - format('estimator_curve="%g" ', [cp1.estimator_curve]); - if (cp1.enable_de) then - parameters := parameters + ('enable_de="1" ') - else parameters := parameters + ('enable_de="0" '); - - str := ''; - for i := 0 to cp1.used_plugins.Count-1 do begin - str := str + cp1.used_plugins[i]; - if (i = cp1.used_plugins.Count-1) then break; - str := str + ' '; - end; - parameters := parameters + format('plugins="%s" new_linear="1" ', [str]); - - for i := 0 to 3 do - begin - curves := curves + FloatToStr(cp1.curvePoints[i][0].x) + ' '; - curves := curves + FloatToStr(cp1.curvePoints[i][0].y) + ' '; - curves := curves + FloatToStr(cp1.curveWeights[i][0]) + ' '; - - curves := curves + FloatToStr(cp1.curvePoints[i][1].x) + ' '; - curves := curves + FloatToStr(cp1.curvePoints[i][1].y) + ' '; - curves := curves + FloatToStr(cp1.curveWeights[i][1]) + ' '; - - curves := curves + FloatToStr(cp1.curvePoints[i][2].x) + ' '; - curves := curves + FloatToStr(cp1.curvePoints[i][2].y) + ' '; - curves := curves + FloatToStr(cp1.curveWeights[i][2]) + ' '; - - curves := curves + FloatToStr(cp1.curvePoints[i][3].x) + ' '; - curves := curves + FloatToStr(cp1.curvePoints[i][3].y) + ' '; - curves := curves + FloatToStr(cp1.curveWeights[i][3]) + ' '; - end; - - curves := trim(curves); - parameters := parameters + format('curves="%s" ', [curves]); - - FileList.Add(''); - { Write transform parameters } - t := cp1.NumXForms; - for i := 0 to t - 1 do - FileList.Add(cp1.xform[i].ToXMLString); - if cp1.HasFinalXForm then - begin - // 'enabled' flag disabled in this release - FileList.Add(cp1.xform[t].FinalToXMLString(cp1.finalXformEnabled)); - end; - - { Write palette data } - if exporting or OldPaletteFormat then - FileList.Add(ColorToXml(cp1)) - else - FileList.Add(ColorToXmlCompact(cp1)); - - FileList.Add(''); - result := FileList.text; - finally - FileList.free - end; -end; - -/////////// AV: working with embedded PNG-parameters //////////////////////// +//************ AV: working with embedded PNG-parameters ***********************// procedure TMainForm.ImportFromPNGClick(Sender: TObject); begin @@ -1862,7 +1483,7 @@ begin PasteFlameXML(flameXML); except Application.MessageBox(PChar(Format(TextByKey('common-openpngerror1'), - [ExtractFileName(FileName)])), PChar('Apophysis AV'), MB_ICONWARNING or MB_OK); + [ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK); end; end; end; @@ -1873,7 +1494,6 @@ var ChunkList: TPngList; TextChunk: TChunkTEXT; flameXML: string; - label loadedFlame; begin Result := ''; PngObject := TPngObject.Create; @@ -1888,29 +1508,29 @@ begin begin if TextChunk.Keyword = 'ApoFlame' then begin - if FindFlameXML(String(TextChunk.Text), '') > 0 then + flameXML := string(TextChunk.Text); + if FindFlameXML(flameXML, '') > 0 then begin - Result := String(TextChunk.Text); - goto loadedFlame; + PngObject.Free; // AV: free the memory if search is succeed + Exit(flameXML); // AV: XML-flame is found end; break; end else - ChunkList.RemoveChunk(TextChunk); + ChunkList.RemoveChunk(TextChunk); // AV: text is not an XML-flame end; + // AV: XML-parameters are not found Application.MessageBox(PChar(Format(TextByKey('common-openpngerror2'), - [ExtractFileName(FileName)])), PChar('Apophysis AV'), MB_ICONWARNING or MB_OK); - loadedFlame: + [ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK); end; - except + except // AV: error in reading parameters Application.MessageBox(PChar(Format(TextByKey('common-openpngerror3'), - [ExtractFileName(FileName)])), PChar('Apophysis AV'), MB_ICONWARNING or MB_OK); + [ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK); end; - PngObject.Free; + PngObject.Free; // AV: free the memory if search is failed end; -/////////////////////////////// - - +//*************************************************************************// +(* function GetThumbnailBase64(const cp1: TControlPoint) : string; var st: TMemoryStream; @@ -1944,8 +1564,8 @@ begin tempcp.Copy(cp1); tempcp.AdjustScale(round(w), round(h)); - tempcp.Width := round(w); - tempcp.Height := round(h); + // tempcp.Width := round(w); + // tempcp.Height := round(h); tempcp.spatial_oversample := defOversample; tempcp.spatial_filter_radius := defFilterRadius; tempcp.sample_density := 10; @@ -1971,20 +1591,25 @@ begin result := base64; end; + *) -function FlameToXML(const cp1: TControlPoint; exporting, embedthumb: boolean): String; +// AV: added default parameter values to get rid of duplicated code +function FlameToXML(const cp1: TControlPoint; exporting: boolean = false; title: string = ''): string; var - t, i{, j}, pos: integer; + t, i: integer; FileList: TStringList; x, y: double; parameters: string; - curves, str, buf, xdata: string; + curves, str, cpName: string; begin FileList := TStringList.create; x := cp1.center[0]; y := cp1.center[1]; -// if cp1.cmapindex >= 0 then pal := pal + 'gradient="' + IntToStr(cp1.cmapindex) + '" '; + if title = '' then // AV + cpName := CleanXMLName(cp1.name) + else + cpName := CleanXMLName(title); try parameters := 'version="' + AppVersionString + '" '; @@ -2042,7 +1667,6 @@ begin if cp1.soloXform >= 0 then parameters := parameters + format('soloxform="%d" ', [cp1.soloXform]); - // parameters := parameters + format('estimator_radius="%g" ', [cp1.estimator]) + format('estimator_minimum="%g" ', [cp1.estimator_min]) + @@ -2083,7 +1707,10 @@ begin curves := trim(curves); parameters := parameters + format('curves="%s" ', [curves]); - FileList.Add(''); + FileList.Add(''); + + if cp1.comment <> '' then FileList.Add(''); // AV + { Write transform parameters } t := cp1.NumXForms; for i := 0 to t - 1 do @@ -2094,7 +1721,9 @@ begin FileList.Add(cp1.xform[t].FinalToXMLString(cp1.finalXformEnabled)); end; - if (embedthumb and EmbedThumbnails) then begin + (* + // AV: too bugged... and not extremely useful thing + if (embedthumb and EmbedThumbnails) then begin xdata := GetThumbnailBase64(cp1); buf := ''; for i := 1 to length(xdata) do begin @@ -2106,6 +1735,7 @@ begin end; if (Length(buf) > 0) then FileList.Add(' '); end; + *) { Write palette data } if exporting or OldPaletteFormat then @@ -2114,9 +1744,9 @@ begin FileList.Add(ColorToXmlCompact(cp1)); FileList.Add(''); - result := FileList.text; + Result := FileList.text; finally - FileList.free + FileList.Free; end; end; @@ -2128,7 +1758,7 @@ begin filename := ExtractFileName(filename); ext := ExtractFileExt(filename); p := Pos(ext, filename); - Result := Copy(filename, 0, p - 1); + Result := Copy(filename, 1, p - 1); // AV: 1 <-- 0 end; function XMLEntryExists(title, filename: string): boolean; @@ -2147,7 +1777,7 @@ begin FileList.Free; end end else - result := false; + Result := false; end; procedure DeleteXMLEntry(title, filename: string); @@ -2159,7 +1789,9 @@ begin try i := 0; Strings.LoadFromFile(FileName); - while Pos('name="' + title + '"', Trim(Strings[i])) = 0 do + { AV: fixed a bug with data corruption when the name of file or transform + is the same as the flame name! Was: 'name="'} + while Pos(' 0) then begin //FileList[0] := ''; - // AV: fix fixed :-) - if (pos(' 0) then + // AV: fix fixed :-) Apo 2.09 uses capital F in this tag + if (pos(' 0) then FileList[0] := '' else // single-flame support FileList.Insert(0, ''); - end; + end + else // AV: if the existing file is empty + FileList.Add(''); // AV if FileList.Count > 2 then begin // AV fix last line :-) if (pos('', FileList[FileList.Count - 1]) = 0) then - FileList.Add(''); + FileList.Add(''); if pos(' 0 then repeat FileList.Delete(FileList.Count - 1); until (Pos('', FileList[FileList.count - 1]) <> 0) else - repeat + repeat // AV: now condition will be true anyway FileList.Delete(FileList.Count - 1); - until (Pos('<' + Tag + '>', FileList[FileList.count - 1]) <> 0) or - (Pos('', FileList[FileList.count - 1]) <> 0); - end else - begin + until (Pos('', FileList[FileList.count - 1]) <> 0) or + (Pos('<' + Tag + '>', FileList[FileList.count - 1]) <> 0); + end else if (FileList.count > 1) then // AV FileList.Delete(FileList.Count - 1); - end; - FileList.Add(Trim(FlameToXML(cp1, false, true))); + FileList.Add(Trim(FlameToXML(cp1, false, title))); FileList.Add(''); FileList.SaveToFile(filename); @@ -2256,15 +1887,16 @@ begin begin // New file ... easy FileList := TStringList.Create; - FileList.Text := '' + #$0D#$0A + - FlameToXML(cp1, false, true) + #$0D#$0A + ''; + FileList.Add(''); + FileList.Add(FlameToXML(cp1, false, title)); + FileList.Add(''); FileList.SaveToFile(filename, TEncoding.UTF8); - FileList.Destroy; + FileList.Free; end; - except // AV: fixed multi-updating + + except // AV: fixed multi-updating of the flame Result := False; // AV: first assign the value, then exit - raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]); // AV - //Application.MessageBox(PChar(Format(TextByKey('common-genericsavefailure'), [FileName])), 'Apophysis', 16); + raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]); end; end; @@ -2302,7 +1934,7 @@ var s: string; begin Result := True; - NewIdent := CleanEntry(NewIdent); + NewIdent := CleanIdentifier(NewIdent); Strings := TStringList.Create; try try @@ -2367,7 +1999,7 @@ end; procedure ListIFS(FileName: string; sel: integer); -{ List identifiers in file } +{ AV: List identifiers in Undo file } var i, p: integer; Title: string; @@ -2386,7 +2018,7 @@ begin begin p := Pos('{', FStrings[i]); // AV: why do we use 2-nd condition? A rudiment from 3D-hack? - if (p <> 0) and (Pos('(3D)', FStrings[i]) = 0) then + if (p <> 0) {and (Pos('(3D)', FStrings[i]) = 0)} then begin Title := Trim(Copy(FStrings[i], 1, p - 1)); if Title <> '' then @@ -2395,14 +2027,20 @@ begin MainForm.LoadSaveProgress.Position := round(100 * i / FStrings.Count); // AV ListItem := MainForm.ListView1.Items.Add; - Listitem.Caption := Title; // Trim(Copy(FStrings[i], 1, p - 1)); + ListItem.Caption := Title; + // AV: hack - remember the creation order in an unused field + ListItem.OverlayIndex := MainForm.ListView1.Items.Count; end; end; end; end; MainForm.LoadSaveProgress.Position := 0; // AV - MainForm.ListView1.Items.EndUpdate; + if ClassicListMode then // AV: thumbs are useless + GeneratingThumbs := False + else // AV: added thumbnails support for Undo list + MainForm.RunThumbnailThread; + with MainForm.ListView1 do if Items.Count > 0 then // AV case sel of @@ -2410,11 +2048,15 @@ begin 1: Selected := Items[0]; end; finally - FStrings.Free; + MainForm.ListView1.Items.EndUpdate; + FStrings.Free; end; MainForm.ParseLoadingBatch := false; // AV + + if AnimateForm.Visible then AnimateForm.UpdateControls; // AV end; +(* procedure ListFlames(FileName: string; sel: integer); { List identifiers in file } var @@ -2450,6 +2092,7 @@ begin FStrings.Free; end; end; +*) { ****************************** Display ************************************ } @@ -2538,6 +2181,7 @@ begin Trace1(''); end; +(* procedure TMainForm.DrawPreview; var cp : TControlPoint; @@ -2559,13 +2203,19 @@ begin BM.Assign(Render.GetImage); Image.Picture.Graphic := bm; end; +*) procedure TMainForm.DrawFlame; +const +{$ifdef CPUX86} + bs = 16; +{$else} + bs = 32; +{$endif} var GlobalMemoryInfo: TMemoryStatus; // holds the global memory status information RenderCP: TControlPoint; Mem, ApproxMem: cardinal; - bs: integer; begin RedrawTimer.Enabled := False; if Assigned(Renderer) then begin @@ -2589,11 +2239,6 @@ begin RenderCP := MainCP.Clone; RenderCp.AdjustScale(Image.width, Image.height); - // following needed ? -// cp.Zoom := Zoom; -// cp.center[0] := center[0]; -// cp.center[1] := center[1]; - RenderCP.sample_density := defSampleDensity; // oversample and filter are just slowing us down here... RenderCP.spatial_oversample := 1; // defOversample; @@ -2604,9 +2249,6 @@ begin GlobalMemoryStatus(GlobalMemoryInfo); Mem := GlobalMemoryInfo.dwAvailPhys; - if (singleBuffer) then bs := 16 - else bs := 32; - // if Output.Lines.Count >= 1000 then Output.Lines.Clear; Trace1('--- Previewing "' + RenderCP.name + '" ---'); Trace1(Format(' Available memory: %f Mb', [Mem / (1024*1024)])); @@ -2648,37 +2290,8 @@ begin end; end; -{ ************************** IFS and triangle stuff ************************* } - -function FlameToString(Title: string): string; -{ Creates a string containing the formated flame parameter set } -var - I: integer; - sl, Strings: TStringList; -begin - Strings := TStringList.Create; - sl := TStringList.Create; - try - Strings.Add(CleanEntry(Title) + ' {'); - MainCp.SaveToStringList(sl); - Strings.Add(sl.text); - Strings.Add('palette:'); - for i := 0 to 255 do - begin - Strings.Add(IntToStr(MainCp.cmap[i][0]) + ' ' + - IntToStr(MainCp.cmap[i][1]) + ' ' + - IntToStr(MainCp.cmap[i][2])) - end; - Strings.Add('}'); - Result := Strings.Text; - finally - sl.Free; - Strings.Free; - end; -end; - procedure TMainForm.RandomBatch; -{ Write a series of random ifs to a file } +{ Write a series of random flames to a file } var i: integer; F: TextFile; @@ -2687,9 +2300,10 @@ begin b := IntToStr(BatchSize); inc(MainSeed); RandSeed := MainSeed; + RandFile := AppPath + randFilename; try - AssignFile(F, AppPath + randFilename); - OpenFile := AppPath + randFilename; + AssignFile(F, RandFile); + OpenFile := RandFile; ReWrite(F); WriteLn(F, ''); // AV: fixed ''); for i := 0 to BatchSize - 1 do @@ -2703,15 +2317,16 @@ begin RandomizeCP(MainCp); MainCp.CalcBoundbox; MainCp.name := RandomPrefix + RandomDate + '-' + IntToStr(RandomIndex); - Write(F, FlameToXML(MainCp, False, false)); + Write(F, FlameToXML(MainCp)); end; Write(F, ''); // AV: fixed ''); CloseFile(F); except on EInOutError do - Application.MessageBox(PChar(TextByKey('main-status-batcherror')), PChar('Apophysis'), 16); + Application.MessageBox(PChar(TextByKey('main-status-batcherror')), + ApophysisSVN, 16); end; - RandFile := AppPath + randFilename; + MainCp.name := ''; end; @@ -2750,7 +2365,7 @@ begin p := Pos(' 0) then begin - MainForm.ListXMLScanner.LoadFromBuffer(TCharType(TStringType(FileStrings[i]))); + MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FileStrings[i]))); MainForm.ListXMLScanner.Execute; if pname <> '' then begin @@ -2786,40 +2401,12 @@ begin end; end; -procedure AddThumbnail(renderer : TRenderer; width, height : double); -var - Bmp: TBitmap; - x, y : double; -begin - Bmp := TBitmap.Create; - Bmp.PixelFormat := pf24bit; - Bmp.HandleType := bmDIB; - Bmp.Width := ThumbnailSize; - Bmp.Height := ThumbnailSize; - - x := ThumbnailSize / 2; - y := ThumbnailSize / 2; - - x := x - width / 2; - y := y - height / 2; - - with Bmp.Canvas do begin - Brush.Color := GetSysColor(5); // window background - FillRect(Rect(0, 0, Bmp.Width, Bmp.Height)); - Draw(round(x), round(y), renderer.GetImage); - end; - - MainForm.UsedThumbnails.Add(bmp, nil); - - if (Bmp <> nil) then Bmp.Free; -end; - function ScanVariations(name:string):boolean; var - i,count:integer; - vname:string; + i,count: integer; + vname: string; begin - count:=NrVar; + count := NrVar; for i:=0 to count - 1 do begin vname := VarNames(i); @@ -2829,6 +2416,7 @@ begin exit; end; end; + for i := 0 to MainForm.SubstSource.Count - 1 do begin vname := MainForm.SubstSource[i]; @@ -2840,12 +2428,13 @@ begin end; Result := false; end; + function ScanVariables(name:string):boolean; var - i,count:integer; + i, count: integer; begin - count:=GetNrVariableNames; - for i:=0 to count - 1 do + count := GetNrVariableNames; + for i :=0 to count - 1 do begin if (GetVariableNameAt(i) = name) then begin @@ -2868,8 +2457,7 @@ procedure TMainForm.mnuOpenClick(Sender: TObject); var fn: string; begin - //ScriptEditor.Stopped := True; - MainMenuClick(nil); // AV + StopScripter; // AV OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*.xml|' + TextByKey('common-filter-templatefiles') + ' |*.template;*.temp|' @@ -2877,35 +2465,34 @@ begin + TextByKey('common-filter-allfiles') + '|*.*'; OpenDialog.InitialDir := ParamFolder; OpenDialog.FileName := ''; - if OpenSaveFileDialog(MainForm, '.flame', OpenDialog.Filter, OpenDialog.InitialDir, - TextByKey('common-browse'), fn, true, false, false, true) then + OpenDialog.Title := ''; // AV +// AV: turn back classic dialog since OpenSaveFileDialog looks ugly then themed + if OpenDialog.Execute then begin - OpenDialog.FileName := fn; - MainForm.CurrentFileName := OpenDialog.FileName; - LastOpenFile := OpenDialog.FileName; + fn := OpenDialog.FileName; // AV + LastOpenFile := fn; Maincp.name := ''; - ParamFolder := ExtractFilePath(OpenDialog.FileName); - OpenFile := OpenDialog.FileName; - //MainForm.Caption := AppVersionString + ' - ' + OpenFile; // --Z-- - if APP_BUILD = '' then MainForm.Caption := AppVersionString + ' - ' + openFile - else MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + openFile; - OpenFileType := ftXML; - (* if UpperCase(ExtractFileExt(OpenDialog.FileName)) = '.IFS' then - begin - OpenFileType := ftIfs; - Variation := vLinear; - VarMenus[0].Checked := True; - end; *) - if (UpperCase(ExtractFileExt(OpenDialog.FileName)) = '.UNDO') or - (UpperCase(ExtractFileExt(OpenDialog.FileName)) = '.APO') then - OpenFileType := ftFla; // AV - if OpenFileType = ftXML then - ListXML(OpenDialog.FileName, 1) + ParamFolder := ExtractFilePath(fn); + OpenFile := fn; + if APP_BUILD = '' then + MainForm.Caption := AppVersionString + ' - ' + OpenFile else + MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + OpenFile; + + fn := UpperCase(ExtractFileExt(fn)); + if (fn = '.UNDO') or (fn = '.APO') then + begin + OpenFileType := ftApo; // AV ListIFS(OpenDialog.FileName, 1); + end + else begin + OpenFileType := ftXML; + ListXML(OpenDialog.FileName, 1); + end; end; end; +(* procedure TMainForm.mnuNextClick(Sender: TObject); begin with ListView1 do @@ -2925,18 +2512,12 @@ begin Selected := Items[i]; end; end; +*) procedure TMainForm.mnuListRenameClick(Sender: TObject); -var - i: integer; begin - if ListView1.SelCount <> 0 then - begin - if (UndoIndex <> 0) then // AV - if Application.MessageBox(PChar(Format(TextByKey('common-confirmrename'), - [ListView1.Selected.Caption])), 'Apophysis AV', 36) <> IDYES then exit; + if ListView1.Selected <> nil then ListView1.Items[ListView1.Selected.Index].EditCaption; - end; end; procedure TMainForm.mnuCopyUPRClick(Sender: TObject); @@ -2955,10 +2536,11 @@ begin if (UndoIndex <> 0) then // AV: if the flame is not saved in the list c := Application.MessageBox( PChar(Format(TextByKey('common-confirmdelete'), [ListView1.Selected.Caption]) - + #32 + TextByKey('common-deletecurrent')), 'Apophysis', 36) = IDYES + + #32 + TextByKey('common-deletecurrent')), ApophysisSVN, 36) = IDYES else c := Application.MessageBox( - PChar(Format(TextByKey('common-confirmdelete'), [ListView1.Selected.Caption])), 'Apophysis', 36) = IDYES + PChar(Format(TextByKey('common-confirmdelete'), [ListView1.Selected.Caption])), + ApophysisSVN, 36) = IDYES end else c := True; @@ -2971,6 +2553,7 @@ begin else DeleteEntry(ListView1.Selected.Caption, OpenFile); { + // AV: do not change the sequence in order to display all icons properly if (ListView1.Selected.Index >= 0) and (ListView1.Selected.Index < UsedThumbnails.Count) and (not ClassicListMode) then UsedThumbnails.Delete(ListView1.Selected.Index); @@ -2980,6 +2563,8 @@ begin ListView1.Selected := ListView1.ItemFocused; // AV: re-adjust the displayed numbers... if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); + + if AnimateForm.Visible then AnimateForm.UpdateControls; // AV (* // AV: I set ListView1.IconOptions.AutoArrange := True; // for auto-updating the flame list without redrawing the thumbs. @@ -3006,26 +2591,29 @@ procedure TMainForm.mnuOptionsClick(Sender: TObject); var isSmallThumb: boolean; begin isSmallThumb := UseSmallThumbnails; // AV - OptionsForm.ShowModal; - // --Z-- - StopThread; - RedrawTimer.Enabled := True; - tbQualityBox.Text := FloatToStr(defSampleDensity); - tbShowAlpha.Down := ShowTransparency; - if (isSmallThumb <> UseSmallThumbnails) then // update the thumbs + // AV: update flame ONLY if settings were changed + if OptionsForm.ShowModal = mrOK then begin - SetThumbnailProperties; // AV - UpdateThumbnails; // AV + StopThread; // --Z-- + RedrawTimer.Enabled := True; + tbQualityBox.Text := FloatToStr(defSampleDensity); + tbShowAlpha.Down := ShowTransparency; + if (isSmallThumb <> UseSmallThumbnails) then // update the thumbs + begin + SetThumbnailProperties; // AV + UpdateThumbnails; // AV + end; + if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); // AV + SetAutoSaveTimer; // AV: to enable autosave without restarting Apophysis + + if ConfirmResetUndo then + ListView1.OnSelectItem := ListViewSelectItem + else + ListView1.OnSelectItem := nil; + + DrawImageView; + UpdateWindows; end; - if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); // AV - - DrawImageView; - UpdateWindows; -end; - -procedure TMainForm.mnuRefreshClick(Sender: TObject); -begin - RedrawTimer.enabled := true; end; procedure TMainForm.mnuRefreshThumbClick(Sender: TObject); @@ -3045,20 +2633,21 @@ begin end; procedure TMainForm.mnuRWeightsClick(Sender: TObject); +var i: smallint; begin StopThread; UpdateUndo; inc(MainSeed); RandSeed := MainSeed; - MainCp.RandomizeWeights; + for i := 0 to Transforms - 1 do + maincp.xform[i].density := random; RedrawTimer.Enabled := True; UpdateWindows; end; procedure TMainForm.mnuRandomBatchClick(Sender: TObject); begin - //ScriptEditor.Stopped := True; - MainMenuClick(nil); // AV + // StopScripter; inc(MainSeed); RandSeed := MainSeed; @@ -3114,7 +2703,7 @@ begin Strings := TStringList.Create; GradStrings := TStringList.Create; try - Strings.Add(CleanEntry(Entry) + ' {'); + Strings.Add(CleanIdentifier(Entry) + ' {'); Strings.Add('fractal:'); Strings.Add(' title="' + CleanUPRTitle(Entry) + '" width=' + IntToStr(UPRWidth) + ' height=' + IntToStr(UPRHeight) + ' layers=1'); @@ -3208,11 +2797,13 @@ begin end; procedure TMainForm.mnuEqualizeClick(Sender: TObject); +var i: smallint; begin StopThread; UpdateUndo; - MainCP.EqualizeWeights; RedrawTimer.Enabled := True; + for i := 0 to Transforms - 1 do + maincp.xform[i].density := 0.5; UpdateWindows; end; @@ -3223,8 +2814,6 @@ end; procedure TMainForm.mnuExitClick(Sender: TObject); begin - MainMenuClick(nil); // AV - Close; end; @@ -3232,7 +2821,7 @@ procedure TMainForm.mnuSaveUPRClick(Sender: TObject); { Write a UPR to a file } begin SaveForm.SaveType := stExportUPR; - SaveForm.Filename := UPRPath + 'Apophysis.upr'; // AV + SaveForm.Filename := UPRPath; SaveForm.Title := maincp.name; if SaveForm.ShowModal = mrOK then begin @@ -3241,33 +2830,98 @@ begin end; end; +procedure FlameFromUndo(cp: TControlPoint; const FlameName: string; const ParamFile: string); +{ AV: common method for loading internal-formatted flames } +var + FStrings, IFSStrings, EntryStrings, Tokens: TStringList; + SavedPal: Boolean; + i, j: integer; + floatcolor: double; + s: string; + Palette: TColorMap; +begin + SavedPal := false; + + FStrings := TStringList.Create; + IFSStrings := TStringList.Create; + Tokens := TStringList.Create; + EntryStrings := TStringList.Create; + + try + FStrings.LoadFromFile(ParamFile); + for i := 0 to FStrings.count - 1 do + if Pos(FlameName + ' {', Trim(FStrings[i])) = 1 then + break; + IFSStrings.Add(FStrings[i]); + repeat + inc(i); + IFSStrings.Add(FStrings[i]); + until Pos('}', FStrings[i]) <> 0; + + for i := 0 to FStrings.count - 1 do + begin + if Pos(FlameName + ' {', Trim(FStrings[i])) = 1 then + break; + end; + inc(i); + while (Pos('}', FStrings[i]) = 0) and (Pos('palette:', FStrings[i]) = 0) do + begin + EntryStrings.Add(FStrings[i]); + inc(i); + end; + if Pos('palette:', FStrings[i]) = 1 then + begin + SavedPal := True; + inc(i); + for j := 0 to 255 do begin + s := FStrings[i]; + GetTokens(s, tokens); + floatcolor := StrToFloat(Tokens[0]); + Palette[j][0] := round(floatcolor); + floatcolor := StrToFloat(Tokens[1]); + Palette[j][1] := round(floatcolor); + floatcolor := StrToFloat(Tokens[2]); + Palette[j][2] := round(floatcolor); + inc(i); + end; + end; + cp.ParseString(EntryStrings.Text); + if SavedPal then cp.cmap := Palette; + cp.name := FlameName; + finally + IFSStrings.Free; + FStrings.Free; + Tokens.free; + EntryStrings.free; + end; +end; + procedure TMainForm.mnuSaveAsClick(Sender: TObject); -{ Save parameters to a file } -var saved: boolean; // AV +{ Save fractal parameters to a file } +var + saved: boolean; // AV + ext: string; begin SaveForm.SaveType := stSaveParameters; SaveForm.Filename := SavePath; SaveForm.Title := maincp.name; + SaveForm.Comment := maincp.comment; // AV if SaveForm.ShowModal = mrOK then begin maincp.name := SaveForm.Title; SavePath := SaveForm.Filename; - if ExtractFileExt(SavePath) = '' then + maincp.comment := SaveForm.Comment; + ext := LowerCase(ExtractFileExt(SavePath)); + if ext = '' then SavePath := SavePath + '.flame'; - if (LowerCase(ExtractFileExt(SaveForm.Filename)) = '.undo') or - (LowerCase(ExtractFileExt(SaveForm.Filename)) = '.apo') then + if (ext = '.undo') or (ext = '.apo') then saved := SaveFlame(maincp, maincp.name, SavePath) // AV else saved := SaveXMLFlame(maincp, maincp.name, SavePath); StatusBar.Panels[3].Text := maincp.name; if (SavePath = OpenFile) and saved then // AV: added status check - begin - if OpenFileType = ftXML then // AV: fixed re-saving error with OpenDialog.FileName! - ListXML(OpenFile, 2, maincp.name) // AV: remember the current position - else - ListIFS(OpenFile, 0); // AV: fixed re-saving error! - end; + AddFlameToList; // AV: show the new item end; end; @@ -3276,33 +2930,55 @@ procedure TMainForm.mnuSaveAllAsClick(Sender: TObject); var i, current: integer; currentXML : string; + cp: TControlPoint; begin + SaveForm.SaveType := stSaveAllParameters; SaveForm.Filename := SavePath; if SaveForm.ShowModal = mrOK then begin - SavePath := SaveForm.Filename; + SavePath := SaveForm.Filename; if ExtractFileExt(SavePath) = '' then SavePath := SavePath + '.flame'; - current := ListView1.ItemIndex; - currentXML := Trim(FlameToXML(Maincp, false, true)); + + // AV: added support for saving all Undo flames as XML + if OpenFileType = ftApo then + begin + cp := TControlPoint.Create; + try + for i := 0 to ListView1.Items.Count-1 do + begin + cp.Clear; + FlameFromUndo(cp, ListView1.Items[i].Caption, OpenFile); + SaveXMLFlame(cp, cp.name, SavePath); + LoadSaveProgress.Position := round(100 * i /(ListView1.Items.Count - 1)); + end; + finally + LoadSaveProgress.Position := 0; // AV + cp.Free; + end; + exit; + end; + + current := ListView1.ItemIndex; // AV: hmm, what if ListView1.Selected = nil? + currentXML := Trim(FlameToXML(Maincp)); for i := 0 to ListView1.Items.Count-1 do begin // -X- what if there are unsaved changes at the current CP? // AV: this only can be if UndoIndex <> 0 if (i = current) and (UndoIndex <> 0) then begin - ParseXML(maincp, PCHAR(currentXML), true); + ParseXML(maincp, currentXML, true); // AV: fixed - was PChar instead String SaveXMLFlame(maincp, maincp.name, SavePath); end else begin - // AV: cancel unneseccary multiple preview updated - LoadXMLFlame(OpenFile, ListView1.Items.Item[i].Caption, false); + // AV: cancel useless multiple preview updated + LoadXMLFlame(OpenFile, ListView1.Items[i].Caption, false); SaveXMLFlame(maincp, maincp.name, SavePath); end; - MainForm.LoadSaveProgress.Position := - round(100 * i / (ListView1.Items.Count - 1)); // AV + LoadSaveProgress.Position := + round(100 * i / (ListView1.Items.Count - 1)); // AV: display progress end; - MainForm.LoadSaveProgress.Position := 0; // AV + LoadSaveProgress.Position := 0; // AV // AV: we don't need to do this because it resets the Undo history! { ListXML(SavePath, 2); @@ -3313,14 +2989,6 @@ begin end; end; -function GradTitle(str: string): string; -var - p: integer; -begin - p := pos('{', str); - GradTitle := Trim(copy(str, 1, p - 1)); -end; - procedure TMainForm.DisplayHint(Sender: TObject); var T: TComponent; @@ -3343,16 +3011,18 @@ end; procedure TMainForm.DownloadPluginsClick(Sender: TObject); begin - AboutForm.lblPluginsClick(nil); + AboutForm.lblPluginsClick(Sender); end; -procedure TMainForm.MainMenuClick(Sender: TObject); +procedure TMainForm.StopScripter; begin - try // AV: sometimes this damn Stopped causes AccessViolations... - if ScriptEditor.btnPause.Down then ScriptEditor.btnPause.Click; // AV - ScriptEditor.Stopped := True; + try + with ScriptEditor do begin + if btnPause.Down then btnPause.Click; + Stopped := True; + end; except - // ? + // Beep; end; end; @@ -3409,13 +3079,12 @@ end; procedure TMainForm.GetScripts; var - NewItem, NewItem2, MenuItem: TMenuItem; + NewItem, MenuItem: TMenuItem; searchResult: TSearchRec; i: integer; - s, path, path1: string; + s, path: string; sl: TStringList; begin - sl := TStringList.Create; if FileExists(AppPath + scriptFavsFilename) then begin @@ -3449,7 +3118,7 @@ begin NewItem.Caption := s; NewItem.Hint := Format(TextByKey('main-menu-script-run3'), [s]); NewItem.OnClick := FavoriteClick; - OnClick := FavoriteClick; + //OnClick := FavoriteClick; // AV: MainForm.OnClick - why?! FavouriteScripts1.Add(NewItem); end; end; @@ -3468,16 +3137,16 @@ begin begin Directory1.Enabled := True; repeat - NewItem2 := TMenuItem.Create(Directory1); // (Self); + NewItem := TMenuItem.Create(Directory1); // (Self); s := searchResult.Name; if (sl.IndexOf(s) < 0) then begin s := RemoveExt(s); - NewItem2.AutoHotkeys := maManual; // AV: to prevent underlined letters - NewItem2.Caption := s; - NewItem2.Hint := Format(TextByKey('main-menu-script-run3'), [s]); - NewItem2.OnClick := ScriptItemClick; - if (Directory1.Find(s) = nil) then Directory1.Add(NewItem2); + NewItem.AutoHotkeys := maManual; // AV: to prevent underlined letters + NewItem.Caption := s; + NewItem.Hint := Format(TextByKey('main-menu-script-run3'), [s]); + NewItem.OnClick := ScriptItemClick; + if (Directory1.Find(s) = nil) then Directory1.Add(NewItem); end; until (FindNext(searchResult) <> 0); FindClose(searchResult); @@ -3488,29 +3157,41 @@ begin begin Directory1.Enabled := True; repeat - NewItem2 := TMenuItem.Create(Directory1); // (Self); + NewItem := TMenuItem.Create(Directory1); // (Self); s := searchResult.Name; if (sl.IndexOf(s) < 0) then begin s := RemoveExt(s); - NewItem2.AutoHotkeys := maManual; // AV: to prevent underlined letters - NewItem2.Caption := s; - NewItem2.Tag := 1; // AV: to identify scripts with different extensions - NewItem2.Hint := Format(TextByKey('main-menu-script-run3'), [s]); - NewItem2.OnClick := ScriptItemClick; - if (Directory1.Find(s) = nil) then Directory1.Add(NewItem2); + NewItem.AutoHotkeys := maManual; // AV: to prevent underlined letters + NewItem.Caption := s; + NewItem.Tag := 1; // AV: to identify scripts with different extensions + NewItem.Hint := Format(TextByKey('main-menu-script-run3'), [s]); + NewItem.OnClick := ScriptItemClick; + if (Directory1.Find(s) = nil) then Directory1.Add(NewItem); end; until (FindNext(searchResult) <> 0); FindClose(searchResult); end; if (Directory1.Count = 0) then Directory1.Enabled := False; // AV sl.Free; + + i := 0; + while i < FavouriteScripts1.Count do + begin + FavouriteScripts1[i].Break := mbBreak; + inc(i, mbHeight); + end; + i := 0; + while i < Directory1.Count do + begin + Directory1[i].Break := mbBreak; + inc(i, mbHeight); + end; end; procedure TMainForm.FormCreate(Sender: TObject); var dte: string; - cmdl : TCommandLine; Registry: TRegistry; apoUI: string; Layouts: array[0..7] of THandle; @@ -3518,14 +3199,12 @@ var ExtSM: HMenu; extStyle: TSearchRec; begin - ApophysisSVN := APP_VERSION; - AppVersionString := APP_NAME +' '+ APP_VERSION; + AppVersionString := APP_NAME + ' ' + APP_VERSION; SubstSource := TStringList.Create; SubstTarget := TStringList.Create; CreateSubstMap; - TbBreakWidth := 802; ListXmlScanner := TEasyXmlScanner.Create(nil); XmlScanner := TXmlScanner.Create(nil); @@ -3538,13 +3217,11 @@ begin MainForm.XmlScanner.OnEmptyTag := XMLScannerEmptyTag; MainForm.XmlScanner.OnEndTag := XmlScannerEndTag; MainForm.XmlScanner.OnStartTag := XMLScannerStartTag; + MainForm.XmlScanner.OnComment := XmlScannerComment; // AV AppPath := ExtractFilePath(Application.ExeName); // AV: moved here ReadSettings; - InternalBitsPerSample := 0; // AV: now unused - // renderBitsPerSample := 0; - //SaveSettings; LoadLanguage(LanguageFile); InsertStrings; @@ -3553,19 +3230,18 @@ begin AvailableLanguages.Add(''); ListLanguages; + SplashWindow.SetInfo(TextByKey('splash-loadingplugins')); MissingPluginList := TStringList.Create; // AV - - C_SyncDllPlugins; - - cmdl := TCommandLine.Create; - cmdl.Load; + C_SyncDllPlugins; // for Chaotica export if (NXFORMS > 100) then AppVersionString := AppVersionString + ' (' + TextByKey('main-common-title-t500') + ')' - else if (NXFORMS < 100) or (cmdl.Lite) then + else if (NXFORMS < 100) then AppVersionString := AppVersionString + ' (' + TextByKey('main-common-title-lite') + ')'; SplashWindow.SetInfo(TextByKey('splash-loadingui')); + // AV: prevent reloading of the splash window after style changing + SplashWindow.OnShow := nil; { //*************** GUI Style Stuff *****************************// } @@ -3647,7 +3323,6 @@ begin end; end; - SplashWindow.SetInfo(TextByKey('splash-loadingplugins')); FillVariantMenu; tbQualityBox.Text := FloatToStr(defSampleDensity); @@ -3681,21 +3356,12 @@ begin { *******************************************************************} - if not cmdl.Lite then - begin - if ClassicListMode = true then - btnViewListClick(nil) - else - btnViewIconsClick(nil); - end else - begin // AV: Lite version from command line cannot change NXFORM const :( - ListView1.ViewStyle := vsReport; - ToolBar.Perform(CM_CONTROLCHANGE, WPARAM(btnViewList), 0); - ToolBar.Perform(CM_CONTROLCHANGE, WPARAM(btnViewIcons), 0); - ToolBar.Perform(CM_CONTROLCHANGE, WPARAM(ToolButton9), 0); - TbBreakWidth := TbBreakWidth - (2 * 26 + 1 * 8); - end; - cmdl.Free; // <-- AV: fixed memory leak + if ClassicListMode = true then + btnViewListClick(nil) + else + btnViewIconsClick(nil); + + if ConfirmResetUndo = False then ListView1.OnSelectItem := nil; // AV SaveSettings; // AV: moved back from top to the end end; @@ -3705,7 +3371,6 @@ var Registry: TRegistry; i: integer; index: integer; - mins:integer; cmdl : TCommandLine; fn, flameXML : string; openScript: string; @@ -3746,9 +3411,12 @@ begin finally Registry.Free; end; - { Synchronize menus etc..} - // should be defaults.... + SplashWindow.SetInfo(TextByKey('splash-initrenderer')); + Application.ProcessMessages; // AV: added to update the status properly + + { Synchronize menus etc..} + // should be defaults.... UndoIndex := 0; UndoMax := 0; index := 1; @@ -3793,16 +3461,19 @@ begin GetCMap(cmap_index, 1, maincp.cmap); DefaultPalette := maincp.cmap; end; - if FileExists(AppPath + randFilename) then - DeleteFile(AppPath + randFilename); + + fn := AppPath + randFilename; + if FileExists(fn) then DeleteFile(fn); + fn := AppPath + ChangeFileExt(randFilename, '.bak'); // AV + if FileExists(fn) then DeleteFile(fn); cmdl := TCommandLine.Create; cmdl.Load; openScript := ''; - // get filename from command line argument SplashWindow.SetInfo(TextByKey('splash-initbatch')); + // get filename from command line argument if ParamCount > 0 then openFile := ParamStr(1) else @@ -3813,17 +3484,16 @@ begin index := LastOpenFileEntry; end; - // if FileExists(openFile) and ((LowerCase(ExtractFileExt(OpenFile)) <> '.asc') or (LowerCase(ExtractFileExt(OpenFile)) <> '.aposcript')) then begin - // AV: something's wrong here... - if FileExists(openFile) and (not ((LowerCase(ExtractFileExt(OpenFile)) = '.asc') or (LowerCase(ExtractFileExt(OpenFile)) = '.aposcript'))) then begin + // AV: we must precalc the string that is used so often + fn := LowerCase(ExtractFileExt(OpenFile)); + + if FileExists(openFile) and (not ((fn = '.asc') or (fn = '.aposcript'))) then begin LastOpenFile := openFile; LastOpenFileEntry := index; end; - // if (openFile = '') or (not FileExists(openFile)) and ((LowerCase(ExtractFileExt(OpenFile)) <> '.asc') or (LowerCase(ExtractFileExt(OpenFile)) <> '.aposcript')) then - // AV: something's wrong here... if (openFile = '') or (not FileExists(openFile)) and - (not ((LowerCase(ExtractFileExt(OpenFile)) = '.asc') or (LowerCase(ExtractFileExt(OpenFile)) = '.aposcript'))) then + (not ((fn = '.asc') or (fn = '.aposcript'))) then begin MainCp.Width := Image.Width; MainCp.Height := Image.Height; @@ -3833,18 +3503,18 @@ begin else MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + TextByKey('main-common-randombatch'); OpenFile := AppPath + randFilename; - ListXML(OpenFile, 1); - OpenFileType := ftXML; + OpenFileType := ftXML; + ListXML(OpenFile, 1); if batchsize = 1 then DrawFlame; end else begin - if (LowerCase(ExtractFileExt(OpenFile)) = '.apo') or (LowerCase(ExtractFileExt(OpenFile)) = '.undo') then + if (fn = '.apo') or (fn = '.undo') then begin - ListFlames(OpenFile, 1); - OpenFileType := ftFla; + OpenFileType := ftApo; // AV: we must choose a file type BEFORE updating list view + ListIFS(OpenFile, 1); // ListFlames(OpenFile, 1); end else - if (LowerCase(ExtractFileExt(OpenFile)) = '.asc') or (LowerCase(ExtractFileExt(OpenFile)) = '.aposcript') then + if (fn = '.asc') or (fn = '.aposcript') then begin openScript := OpenFile; RandomBatch; @@ -3853,12 +3523,12 @@ begin else MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + TextByKey('main-common-randombatch'); OpenFile := AppPath + randFilename; - ListXML(OpenFile, 1); OpenFileType := ftXML; + ListXML(OpenFile, 1); if batchsize = 1 then DrawFlame; end else begin - ListXML(OpenFile, 2); OpenFileType := ftXML; + ListXML(OpenFile, 2); MainForm.ListView1.Selected := MainForm.ListView1.Items[index - 1]; end; if APP_BUILD = '' then MainForm.Caption := AppVersionString + ' - ' + openFile @@ -3876,18 +3546,7 @@ begin // ExportDialog.cmbDepth.ItemIndex := 2; // AV: changed inside ExportForm // DoNotAskAboutChange := false; - if (AutoSaveFreq = 0) then mins := 1 - else if (AutoSaveFreq = 1) then mins := 2 - else if (AutoSaveFreq = 2) then mins := 5 - else if (AutoSaveFreq = 3) then mins := 10 - else begin - mins := 5; - AutoSaveFreq := 2; - AutoSaveEnabled := false; - end; - - AutoSaveTimer.Interval := 60 * 1000 * mins; - AutoSaveTimer.Enabled := AutoSaveEnabled; + SetAutoSaveTimer; // AV: a code block is replaced by a method // loading done..now do what is told by cmdline ... if (cmdl.CreateFromTemplate) then begin @@ -3899,14 +3558,13 @@ begin ScriptEditor.Stopped := True; StopThread; - InvokeLoadXML(flameXML); + ParseXML(MainCP, flameXML, false); //InvokeLoadXML(flameXML); Transforms := MainCp.TrianglesFromCP(MainTriangles); Statusbar.Panels[3].Text := MainCp.name; ResizeImage; RedrawTimer.Enabled := True; Application.ProcessMessages; UpdateWindows; - //AdjustForm.TemplateRandomizeGradient; AdjustForm.mnuRandomize.Click; end; end; @@ -3984,18 +3642,21 @@ end; procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); var Registry: TRegistry; + fn: string; begin if ConfirmExit and (UndoIndex <> 0) then - if Application.MessageBox(PChar(TextByKey('common-confirmexit')), 'Apophysis', MB_ICONWARNING or MB_YESNO) <> IDYES then + if Application.MessageBox(PChar(TextByKey('common-confirmexit')), + ApophysisSVN, MB_ICONWARNING or MB_YESNO) <> IDYES then begin Action := caNone; exit; end; - if ScriptEditor.btnPause.Down then ScriptEditor.btnPause.Click; // AV - ScriptEditor.Stopped := True; + AutoSaveTimer.Enabled := False; // AV + StopScripter; // AV: stopping the scripter's animation + + // HtmlHelp(0, nil, HH_CLOSE_ALL, 0); - HtmlHelp(0, nil, HH_CLOSE_ALL, 0); { To capture secondary window positions } if EditForm.visible then EditForm.Close; if AdjustForm.visible then AdjustForm.close; @@ -4027,17 +3688,24 @@ begin finally Registry.Free; end; + Application.ProcessMessages; CanDrawOnResize := False; - if FileExists(AppPath + randFilename) then - DeleteFile(AppPath + randFilename); - if FileExists(AppPath + undoFilename) then - DeleteFile(AppPath + undoFilename); + + fn := AppPath + randFilename; + if FileExists(fn) then DeleteFile(fn); + fn := AppPath + ChangeFileExt(randFilename, '.bak'); // AV + if FileExists(fn) then DeleteFile(fn); + fn := AppPath + undoFilename; + if FileExists(fn) then DeleteFile(fn); + fn := APPDATA + export_flame; // AV + if FileExists(fn) then DeleteFile(fn); if KeepBackGround then // AV - RandBackColor := MainCp.background[2] * 65536 + MainCp.background[1] * 256 + MainCp.background[0]; + RandBackColor := MainCp.background[2] * 65536 + + MainCp.background[1] * 256 + MainCp.background[0]; // AV: remember the flame position if the list was sorted - if assigned(ListView1.Selected) then + if assigned(ListView1.Selected) then LastOpenFileEntry := ListView1.Selected.Index + 1; SaveSettings; @@ -4046,8 +3714,8 @@ end; procedure TMainForm.FormDestroy(Sender: TObject); var i: word; begin - if assigned(Renderer) then Renderer.Terminate; - if assigned(Renderer) then Renderer.WaitFor; + //if assigned(Renderer) then Renderer.Terminate; + //if assigned(Renderer) then Renderer.WaitFor; if assigned(Renderer) then Renderer.Free; if assigned(FViewImage) then FViewImage.Free; @@ -4109,12 +3777,15 @@ end; procedure TMainForm.BackPanelResize(Sender: TObject); begin + try StopThread; if CanDrawOnResize then reDrawTimer.Enabled := True; - ResizeImage; + ResizeImage; DrawImageView; + except + end; end; // AV: added the third parameter to prevent multiple updates of the previews @@ -4146,8 +3817,8 @@ begin p := Pos(' 0) then begin - MainForm.ListXMLScanner.LoadFromBuffer(TCharType(TStringType(FileStrings[i]))); - MainForm.ListXMLScanner.Execute; + ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FileStrings[i]))); // AV + ListXMLScanner.Execute; if pname <> '' then begin if (Trim(pname) = Trim(name)) then @@ -4172,12 +3843,12 @@ begin ParamStrings.Add(FileStrings[i]); until pos('', Lowercase(FileStrings[i])) <> 0; - //ScriptEditor.Stopped := True; // AV: I hate this... - // If script preview isnit visible, it's useless, + //ScriptEditor.Stopped := True; // <-- AV: I hate this... + // If script preview isn't visible, it's useless, // otherwise it loads wrong flame from sripter... StopThread; - ParseXML(MainCp,ParamStrings.Text, true); + ParseXML(MainCp, ParamStrings.Text, true); if upd then begin // AV: to prevent redrawing when saving a batch @@ -4269,20 +3940,22 @@ begin if not (ClassicListMode or ParseLoadingBatch) then UpdateThumbnails; end; +procedure TMainForm.ListViewSelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); +begin + if (UndoIndex <> 0) and (not Selected) then + if Application.MessageBox(PChar(TextByKey('common-confirmselect')), + ApophysisSVN, 36) = IDYES then + mnuSaveUndo.Click; // AV +end; + procedure TMainForm.ListViewChange(Sender: TObject; Item: TListItem; Change: TItemChange); var - FStrings: TStringList; - IFSStrings: TStringList; - EntryStrings, Tokens: TStringList; - SavedPal: Boolean; - i, j: integer; - floatcolor: double; - s: string; - Palette: TcolorMap; - name:string; + i: smallint; begin - if (ListView1.SelCount <> 0) and (Trim(ListView1.Selected.Caption) <> Trim(maincp.name)) then + if (ListView1.Selected <> nil) and + (Trim(ListView1.Selected.Caption) <> Trim(maincp.name)) then begin LastOpenFileEntry := ListView1.Selected.Index + 1; RedrawTimer.Enabled := False; //? @@ -4290,114 +3963,51 @@ begin if OpenFileType = ftXML then begin - name := ListView1.Selected.caption; - ParseLoadingBatch := false; - LoadXMLFlame(OpenFile, name); + // ParseLoadingBatch := false; // AV: ? + LoadXMLFlame(OpenFile, ListView1.Selected.caption); AnnoyUser; end - else + else // if OpenFileType = ftApo then // AV: Undo flame list begin - SavedPal := false; - //ScriptEditor.Stopped := True; + maincp.Clear; // initialize control point for new flame; - FStrings := TStringList.Create; - IFSStrings := TStringList.Create; - Tokens := TStringList.Create; - EntryStrings := TStringList.Create; - try - FStrings.LoadFromFile(OpenFile); - for i := 0 to FStrings.count - 1 do - if Pos(ListView1.Selected.Caption + ' {', Trim(FStrings[i])) = 1 then - break; - IFSStrings.Add(FStrings[i]); - repeat - inc(i); - IFSStrings.Add(FStrings[i]); - until Pos('}', FStrings[i]) <> 0; - maincp.Clear; // initialize control point for new flame; - maincp.background[0] := 0; - maincp.background[1] := 0; - maincp.background[2] := 0; - maincp.sample_density := defSampleDensity; - maincp.spatial_oversample := defOversample; - maincp.spatial_filter_radius := defFilterRadius; - if OpenFileType = ftFla then // AV: Undo flame list - begin - for i := 0 to FStrings.count - 1 do - begin - if Pos(ListView1.Selected.Caption + ' {', Trim(FStrings[i])) = 1 then - break; - end; - inc(i); - while (Pos('}', FStrings[i]) = 0) and (Pos('palette:', FStrings[i]) = 0) do - begin - EntryStrings.Add(FStrings[i]); - inc(i); - end; - if Pos('palette:', FStrings[i]) = 1 then - begin - SavedPal := True; - inc(i); - for j := 0 to 255 do begin - s := FStrings[i]; - GetTokens(s, tokens); - floatcolor := StrToFloat(Tokens[0]); - Palette[j][0] := round(floatcolor); - floatcolor := StrToFloat(Tokens[1]); - Palette[j][1] := round(floatcolor); - floatcolor := StrToFloat(Tokens[2]); - Palette[j][2] := round(floatcolor); - inc(i); - end; - end; - FlameString := EntryStrings.Text; - maincp.ParseString(FlameString); - Transforms := MainCP.NumXForms; - end - else - begin - { Open *.ifs File } - Variation := vLinear; - VarMenus[0].Checked := True; - StringToIFS(IFSStrings.Text); - SetVariation(maincp); - maincp.CalcBoundBox; - end; - Center[0] := maincp.Center[0]; - Center[1] := maincp.Center[1]; - mnuSaveUndo.Enabled := false; - mnuUndo.Enabled := False; - mnuPopUndo.Enabled := False; - mnuRedo.enabled := False; - mnuPopRedo.enabled := False; - EditForm.mnuUndo.Enabled := False; - EditForm.mnuRedo.enabled := False; - EditForm.tbUndo.enabled := false; - EditForm.tbRedo.enabled := false; - AdjustForm.btnUndo.enabled := false; - AdjustForm.btnRedo.enabled := false; - btnUndo.Enabled := false; - btnRedo.enabled := false; - Transforms := MainCp.TrianglesFromCP(MainTriangles); + // AV: deleted all duplicated code here + FlameFromUndo(maincp, ListView1.Selected.caption, OpenFile); + + maincp.sample_density := defSampleDensity; + maincp.spatial_oversample := defOversample; + maincp.spatial_filter_radius := defFilterRadius; + + //Transforms := MainCP.NumXForms; // we'll change it later + Center[0] := maincp.Center[0]; + Center[1] := maincp.Center[1]; + mnuSaveUndo.Enabled := false; + mnuUndo.Enabled := False; + mnuPopUndo.Enabled := False; + mnuRedo.enabled := False; + mnuPopRedo.enabled := False; + EditForm.mnuUndo.Enabled := False; + EditForm.mnuRedo.enabled := False; + EditForm.tbUndo.enabled := false; + EditForm.tbRedo.enabled := false; + AdjustForm.btnUndo.enabled := false; + AdjustForm.btnRedo.enabled := false; + btnUndo.Enabled := false; + btnRedo.enabled := false; + Transforms := MainCp.TrianglesFromCP(MainTriangles); // Fix Apophysis 1.0 parameters with negative color parameteres! - for i := 0 to Transforms - 1 do - if maincp.xform[i].color < 0 then maincp.xform[i].color := 0; - if SavedPal then maincp.cmap := Palette; - UndoIndex := 0; - UndoMax := 0; - if fileExists(AppPath + undoFilename) then - DeleteFile(AppPath + undoFilename); - maincp.name := ListView1.Selected.Caption; // AV: fixed Apo7X bug - Statusbar.Panels[3].Text := maincp.name; - RedrawTimer.Enabled := True; - Application.ProcessMessages; - UpdateWindows; - finally - IFSStrings.Free; - FStrings.Free; - Tokens.free; - EntryStrings.free; - end; + for i := 0 to Transforms - 1 do + if maincp.xform[i].color < 0 then maincp.xform[i].color := 0; + + UndoIndex := 0; + UndoMax := 0; + if fileExists(AppPath + undoFilename) then + DeleteFile(AppPath + undoFilename); + maincp.name := ListView1.Selected.Caption; // AV: fixed Apo7X bug + Statusbar.Panels[3].Text := maincp.name; + RedrawTimer.Enabled := True; + Application.ProcessMessages; + UpdateWindows; end; {if ResizeOnLoad then} ResizeImage; @@ -4409,7 +4019,6 @@ begin if AdjustForm.visible then AdjustForm.UpdateDisplay; if EditForm.visible then EditForm.UpdateDisplay; if MutateForm.visible then MutateForm.UpdateDisplay; - if CurvesForm.Visible then CurvesForm.SetCp(MainCp); end; procedure TMainForm.LoadUndoFlame(index: integer; filename: string); @@ -4464,11 +4073,10 @@ begin end; end; maincp.Clear; - FlameString := EntryStrings.Text; maincp.zoom := 0; maincp.center[0] := 0; maincp.center[0] := 0; - maincp.ParseString(FlameString); + maincp.ParseString(EntryStrings.Text); maincp.sample_density := defSampleDensity; Center[0] := maincp.Center[0]; Center[1] := maincp.Center[1]; @@ -4490,7 +4098,7 @@ begin end; procedure TMainForm.ResetColorSpeedClick(Sender: TObject); -var i: integer; +var i: smallint; begin StopThread; UpdateUndo; @@ -4501,7 +4109,7 @@ begin end; procedure TMainForm.ResetColorValuesClick(Sender: TObject); -var i: integer; +var i: smallint; begin StopThread; UpdateUndo; @@ -4532,12 +4140,12 @@ begin // AV: fixed 'List index out of bounds' bugs if (s = '') then begin - MessageBox(Handle, PChar(TextByKey('save-status-notitle')), PCHar('Apophysis AV'), 48); + MessageBox(Handle, PChar(TextByKey('save-status-notitle')), ApophysisSVN, 48); Discard := True; end else if (ListView1.FindCaption(0, s, false, true, false) <> nil) then begin MessageBox(Handle, PChar(Format(TextByKey('save-status-alreadyexists3'), - [s])), PChar('Apophysis AV'), 48); + [s])), ApophysisSVN, 48); Discard := True; end else if OpenFileType = ftXML then @@ -4547,9 +4155,16 @@ begin if Discard then s := Item.Caption - else + else begin + MainCp.name := s; // AV: prevent unnecessary flame redrawing + StatusBar.Panels[3].Text := s; // AV + + Application.ProcessMessages; + + if AnimateForm.Visible then AnimateForm.Close; // TODO if SortFlames.Checked and EnumerateFlames.Checked then - EnumerateFlamesClick(EnumerateFlames); + EnumerateFlamesClick(EnumerateFlames); // hmm + end; end; end; @@ -4563,14 +4178,14 @@ begin end; procedure TMainForm.mnuVRandomClick(Sender: TObject); -var i: integer; begin mnuVRandom.Checked := True; // AV: only one variation can be active here - for i := 0 to NRVAR - 1 do - VarMenus[i].Checked := False; - mnuBuiltinVars.Checked := False; - mnuPluginVars.Checked := False; + if Variation > vRandom then begin + VarMenus[Variation].Checked := False; + mnuBuiltinVars.Checked := False; + mnuPluginVars.Checked := False; + end; StopThread; UpdateUndo; inc(MainSeed); @@ -4594,7 +4209,7 @@ begin AdjustForm.Show; end; -/////////////////////////////////////////////////////////////////////////////// +//**************** Smooth Palette *********************// procedure swapcolor(var clist: array of cardinal; i, j: integer); var @@ -4629,6 +4244,7 @@ procedure TMainForm.SmoothPalette; var Bitmap: TBitMap; JPEG: TJPEGImage; + PNG: TPNGImage; // AV pal: TColorMap; strings: TStringlist; ident, FileName: string; @@ -4640,36 +4256,52 @@ begin //Total := Trunc(NumTries * TryLength / 100); //p := 0; Bitmap := TBitmap.Create; - JPEG := TJPEGImage.Create; strings := TStringList.Create; try begin inc(MainSeed); RandSeed := MainSeed; - OpenDialog.Filter := Format('%s|*.bmp;*.dib;*.jpg;*.jpeg|%s|*.bmp;*.dib|%s|*.jpg;*.jpeg|%s|*.*', - [TextByKey('common-filter-allimages'), TextByKey('common-filter-bitmap'), - TextByKey('common-filter-jpeg'), TextByKey('common-filter-allfiles')]); + OpenDialog.Filter := RenderForm.SaveDialog.Filter; // AV: added precalc OpenDialog.InitialDir := ImageFolder; - OpenDialog.Title := TextByKey('common-browse'); + OpenDialog.Title := TextByKey('common-selectimage'); // AV OpenDialog.FileName := ''; - if OpenSaveFileDialog(MainForm, OpenDialog.DefaultExt, OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then + if OpenDialog.Execute then begin - OpenDialog.FileName := fn; - ImageFolder := ExtractFilePath(OpenDialog.FileName); + fn := OpenDialog.FileName; // AV + ImageFolder := ExtractFilePath(fn); Application.ProcessMessages; len_best := 0; - if (UpperCase(ExtractFileExt(Opendialog.FileName)) = '.BMP') - or (UpperCase(ExtractFileExt(Opendialog.FileName)) = '.DIB') then - Bitmap.LoadFromFile(Opendialog.FileName); - if (UpperCase(ExtractFileExt(Opendialog.FileName)) = '.JPG') - or (UpperCase(ExtractFileExt(Opendialog.FileName)) = '.JPEG') then + ident := UpperCase(ExtractFileExt(fn)); // AV: added precalc + if (ident = '.BMP') or (ident = '.DIB') then + Bitmap.LoadFromFile(fn) + else if (ident = '.JPG') or (ident = '.JPEG') then begin - JPEG.LoadFromFile(Opendialog.FileName); - with Bitmap do - begin - Width := JPEG.Width; - Height := JPEG.Height; - Canvas.Draw(0, 0, JPEG); + JPEG := TJPEGImage.Create; + try + JPEG.LoadFromFile(fn); + with Bitmap do + begin + Width := JPEG.Width; + Height := JPEG.Height; + Canvas.Draw(0, 0, JPEG); + end; + finally + JPEG.Free; + end; + end + else // if (ident = '.PNG') then // <-- AV: added PNG support here + begin + PNG := TPNGImage.Create; // AV + try + PNG.LoadFromFile(fn); + with Bitmap do + begin + Width := PNG.Width; + Height := PNG.Height; + Canvas.Draw(0, 0, PNG); + end; + finally + PNG.Free; end; end; iw := Bitmap.Width; @@ -4748,7 +4380,7 @@ begin end; { Convert to TColorMap, Gradient and save } FileName := lowercase(ExtractFileName(Opendialog.FileName)); - ident := CleanEntry(FileName); + ident := CleanIdentifier(FileName); strings.add(ident + ' {'); strings.add('gradient:'); strings.add(' title="' + CleanUPRTitle(FileName) + '" smooth=no'); @@ -4783,37 +4415,10 @@ begin end; finally Bitmap.Free; - JPEG.Free; strings.Free; end; end; -procedure TMainForm.SortFlamesClick(Sender: TObject); -begin - StopThread; - SortFlames.Checked := not SortFlames.Checked; - if SortFlames.Checked then - begin - ListView1.SortType := stText; - // AV: to use Morph scripting method properly - ScriptForm.FileList.Sorted := True; - if ListView1.Items.Count > 1 then ListView1.AlphaSort; - EnumerateFlamesClick(EnumerateFlames); - end - else begin - ListView1.SortType := stNone; - ScriptForm.FileList.Sorted := False; - if (OpenFile <> '') then - if OpenFileType = ftXML then - begin - if assigned(ListView1.Selected) then - ListXML(OpenFile, 2, ListView1.Selected.Caption) - else - ListXML(OpenFile, 1); - end; - end; -end; - procedure TMainForm.Smoothize(const oldpal: TColorMap; const a, b: byte); { AV: this one applies Smooth palette to the current gradient or its part } var @@ -4910,11 +4515,46 @@ begin if EditForm.Visible then EditForm.UpdateDisplay; if MutateForm.Visible then MutateForm.UpdateDisplay; RedrawTimer.enabled := true; - + finally end; end; +//**********************************************************************// + +{ AV: quick sort to switch between alphabetical and chronological flame order } +function ChronoSort(Item1, Item2: TListItem; ParamSort: integer): integer; stdcall; +begin + Result := (Item1.OverlayIndex - Item2.OverlayIndex); // hacky, but fast... +end; + +procedure TMainForm.SortFlamesClick(Sender: TObject); +begin + SortFlames.Checked := not SortFlames.Checked; + if SortFlames.Checked then + begin + ListView1.SortType := stText; + // AV: to use Morph scripting method properly + ScriptForm.ScFileList.Sorted := True; + if ListView1.Items.Count > 1 then begin + ListView1.AlphaSort; + if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); + end; + end + else begin + ListView1.SortType := stNone; + ScriptForm.ScFileList.Sorted := False; + if ListView1.Items.Count > 1 then begin + ListView1.CustomSort(@ChronoSort, 0); + if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); + end; + end; + + if AnimateForm.Visible then AnimateForm.UpdateControls; +end; + +//**********************************************************************// + procedure TMainForm.mnuThumbnailQualityClick(Sender: TObject); // AV begin if TMenuItem(Sender).Checked then exit; // prevent unneseccary updating @@ -4928,7 +4568,7 @@ begin ThumbPrevQual := TMenuItem(Sender).Tag; // refresh the list of flame previews - if (OpenFile <> '') and (OpenFileType = ftXML) then + if (OpenFile <> '') then if not ParseLoadingBatch then UpdateThumbnails; end; @@ -4993,7 +4633,7 @@ end; procedure TMainForm.mnuUnflattenClick(Sender: TObject); var - i, t: integer; + i, t: smallint; refresh: boolean; begin StopThread; @@ -5048,7 +4688,7 @@ end; // AV: added support for fast preview and params saving without rendering // for absolute beginners :) procedure TMainForm.mnuExportBitmapClick(Sender: TObject); -var pic: TPNGObject; +var pic: TPNGImage; begin SaveDialog.DefaultExt := 'png'; SaveDialog.Filter := Format('%s|*.png', [TextByKey('common-filter-png')]); @@ -5056,10 +4696,10 @@ begin if SaveDialog.Execute then begin try - pic := TPNGObject.Create; + pic := TPNGImage.Create; try pic.Assign(Image.Picture.Bitmap); - pic.AddtEXt('ApoFlame', AnsiString(Trim(FlameToXML(Maincp, false, false)))); + pic.AddtEXt('ApoFlame', AnsiString(Trim(FlameToXML(Maincp)))); pic.SaveToFile(SaveDialog.Filename); finally pic.Free; @@ -5072,15 +4712,16 @@ end; procedure TMainForm.mnuFullScreenClick(Sender: TObject); begin - FullScreenForm.ActiveForm := Screen.ActiveForm; + // AV: screen size never changed while app works - moved into OnCreate handler + { FullScreenForm.Width := Screen.Width; FullScreenForm.Height := Screen.Height; FullScreenForm.Top := 0; FullScreenForm.Left := 0; + } + FullScreenForm.ActiveForm := Screen.ActiveForm; FullScreenForm.cp.Copy(maincp); FullScreenForm.cp.cmap := maincp.cmap; - FullScreenForm.center[0] := center[0]; - FullScreenForm.center[1] := center[1]; FullScreenForm.Calculate := True; FullScreenForm.Show; end; @@ -5093,7 +4734,7 @@ begin NewRender := True; if Assigned(RenderForm.Renderer) then - if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), 'Apophysis', 36) = ID_NO then + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then NewRender := false; if NewRender then @@ -5110,16 +4751,17 @@ begin 3: Ext := '.jpg'; end; + RenderForm.bRenderAll := False; + //RenderForm.caption := 'Render ' + #39 + maincp.name + #39 + ' to Disk'; + RenderForm.Caption := RenderForm.Hint; // AV RenderForm.Filename := RenderPath + maincp.name + Ext; RenderForm.SaveDialog.FileName := RenderPath + maincp.name + Ext; RenderForm.txtFilename.Text := ChangeFileExt(RenderForm.SaveDialog.Filename, Ext); RenderForm.cp.Copy(MainCP); RenderForm.cp.cmap := maincp.cmap; - RenderForm.zoom := maincp.zoom; - RenderForm.Center[0] := center[0]; - RenderForm.Center[1] := center[1]; + if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2 end; RenderForm.Show; @@ -5129,11 +4771,12 @@ procedure TMainForm.mnuRenderAllClick(Sender: TObject); var Ext: string; NewRender: Boolean; + i: smallint; begin NewRender := True; if Assigned(RenderForm.Renderer) then - if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), 'Apophysis', 36) = ID_NO then + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then NewRender := false; if NewRender then @@ -5150,17 +4793,24 @@ begin 3: Ext := '.jpg'; end; - //RenderForm.caption := 'Render all flames to disk'; + RenderForm.Caption := GetShortHint(tbRenderAll.Hint); // AV RenderForm.bRenderAll := true; RenderForm.Filename := RenderPath + maincp.name + Ext; RenderForm.SaveDialog.FileName := RenderForm.Filename; RenderForm.txtFilename.Text := ChangeFileExt(RenderForm.SaveDialog.Filename, Ext); + //AV: added support here for any flame-file (not only opened) + RenderForm.RenderFlameFile := OpenFile; + SetLength(RenderForm.FlameNames, ListView1.Items.Count); + for i := 0 to ListView1.Items.Count - 1 do + RenderForm.FlameNames[i] := ListView1.Items[i].Caption; + { RenderForm.cp.Copy(MainCP); RenderForm.cp.cmap := maincp.cmap; RenderForm.zoom := maincp.zoom; RenderForm.Center[0] := center[0]; RenderForm.Center[1] := center[1]; + } if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2 end; RenderForm.Show; @@ -5179,6 +4829,12 @@ begin AdjustForm.Show; end; +procedure TMainForm.mnuAnimatorClick(Sender: TObject); +begin + StopScripter; + AnimateForm.Show; +end; + procedure TMainForm.mnuResetLocationClick(Sender: TObject); var scale: double; @@ -5234,8 +4890,9 @@ procedure TMainForm.mnuSaveUndoClick(Sender: TObject); begin if FileExists(AppPath + undoFilename) then begin - SaveDialog.DefaultExt := 'undo'; + SaveDialog.DefaultExt := 'apo'; SaveDialog.Filter := TextByKey('common-filter-undofiles') + '|*undo;*.apo'; + SaveDialog.InitialDir := ParamFolder; SaveDialog.Filename := maincp.name; if SaveDialog.Execute then begin @@ -5248,10 +4905,11 @@ end; procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if Assigned(RenderForm.Renderer) then - if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), 'Apophysis', 36) = ID_NO then - CanClose := False; + if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), + ApophysisSVN, 36) = ID_NO then + CanClose := False; - AboutToExit := CanClose; + // AboutToExit := CanClose; end; procedure TMainForm.FormActivate(Sender: TObject); @@ -5267,19 +4925,22 @@ end; procedure TMainForm.mnuCalculateColorsClick(Sender: TObject); var - i: integer; + i: smallint; begin StopThread; UpdateUndo; - for i := 0 to Transforms - 1 do - maincp.xform[i].color := i / (transforms - 1); + if Transforms > 1 then // AV: fixed divide-by-zero bug + for i := 0 to Transforms - 1 do + maincp.xform[i].color := i / (transforms - 1) + else + maincp.xform[0].color := 0; // AV RedrawTimer.Enabled := True; UpdateWindows; end; procedure TMainForm.mnuRandomizeColorValuesClick(Sender: TObject); var - i: integer; + i: smallint; begin inc(MainSeed); RandSeed := MainSeed; @@ -5352,7 +5013,7 @@ var begin if FavoritesForm.ShowModal = mrOK then begin - if favorites.count <> 0 then + if Favorites.Count <> 0 then begin for i := 0 to Favorites.Count - 1 do begin @@ -5422,16 +5083,10 @@ begin end; end; -procedure TMainForm.mnuShowFullClick(Sender: TObject); -begin - FullScreenForm.Calculate := False; - FullScreenForm.Show; -end; - procedure TMainForm.mnuImageSizeClick(Sender: TObject); begin AdjustForm.UpdateDisplay; - AdjustForm.PageControl.TabIndex:=3; + AdjustForm.PageControl.TabIndex := 3; AdjustForm.Show; end; @@ -5470,8 +5125,10 @@ begin if ShowModal = mrOK then begin maincp.name := Title; - SaveXMLFlame(maincp, maincp.name, Filename); StatusBar.Panels[3].Text := maincp.name; + + if SaveXMLFlame(maincp, maincp.name, Filename) and (FileName = OpenFile) then + AddFlameToList; end; end; end; @@ -5523,9 +5180,7 @@ end; procedure TMainForm.ParseXML(var cp1: TControlPoint; const params: string; const ignoreErrors : boolean); var i: integer; - h, s, v: real; begin - CurrentFlame := cp1.name; nxform := 0; FinalXformLoaded := false; ActiveXformSet := 0; @@ -5536,7 +5191,7 @@ begin ParseCp.Free; // we're creating this CP from the scratch ParseCp := TControlPoint.create; // to reset variables properly (randomize) - XMLScanner.LoadFromBuffer(TCharType(TStringType(params))); + XMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(params))); XMLScanner.Execute; cp1.copy(ParseCp); @@ -5548,13 +5203,7 @@ begin {else ShowMessage('Palette index too high')}; - if (cp1.hue_rotation > 0) and (cp1.hue_rotation < 1) then - for i := 0 to 255 do - begin - RGBToHSV(cp1.cmap[i][0], cp1.cmap[i][1], cp1.cmap[i][2], h, s, v); - h := Round(360 + h + (cp1.hue_rotation * 360)) mod 360; - HSVToRGB(h, s, v, cp1.cmap[i][0], cp1.cmap[i][1], cp1.cmap[i][2]); - end; + RotateCMapHue(cp1); // AV end; if FinalXformLoaded = false then begin @@ -5582,25 +5231,23 @@ begin if (flameXML <> '') then begin UpdateUndo; - //ScriptEditor.Stopped := True; - MainMenuClick(nil); // AV + // StopScripter; StopThread; - ParseXML(MainCP, PCHAR(flameXML), false); + ParseXML(MainCP, flameXML, false); // AV: fixed - was PChar instead String AnnoyUser; Transforms := MainCp.TrianglesFromCP(MainTriangles); Statusbar.Panels[3].Text := MainCp.name; if AutoSaveXML then // AV: saving loaded parameters in the current file begin - if XMLEntryExists(MainCp.name, OpenFile) then + while XMLEntryExists(MainCp.name, OpenFile) do MainCp.name := MainCp.name + ' (new)'; // hmm... if (OpenFile = AppPath + randfilename) then // random batch will be deleted - SaveXMLFlame(MainCp, MainCp.name, - IfThen(DirectoryExists(ExtractFilePath(AutoSavePath)), ExtractFilePath(AutoSavePath), - AppPath) + 'Saved by ApophysisAV.flame'); // :) + SaveXMLFlame(MainCp, MainCp.name, IfThen(DirectoryExists(ExtractFilePath(AutoSavePath)), + ExtractFilePath(AutoSavePath), AppPath) + 'Saved by ApophysisAV.flame'); // :) // AV: display these changes and scroll to the selected item if SaveXMLFlame(MainCp, MainCp.name, OpenFile) then - ListXML(OpenFile, 2, MainCp.name); + AddFlameToList; // AV: show the new item end; ResizeImage; RedrawTimer.Enabled := True; @@ -5621,7 +5268,7 @@ var txt: string; i: integer; begin - txt := Trim(FlameToXML(Maincp, false, false)); + txt := Trim(FlameToXML(Maincp)); Clipboard.SetTextBuf(PChar(txt)); mnuPaste.enabled := true; @@ -5632,7 +5279,7 @@ begin MemCp.Clear; for i := 0 to Maincp.NumXForms - 1 do //FIXME: skip final transform! MemCp.xform[i].Assign(Maincp.xform[i]); - EditForm.PasteTransform1.Enabled := True; + EditForm.PasteTransform.Enabled := True; end; function WinShellExecute(const Operation, AssociatedFile: string): Boolean; @@ -5645,12 +5292,12 @@ begin a1 := 'open'; r := ShellExecute( - application.handle - , pchar(a1) - , pchar(AssociatedFile) - , '' - , '' - , SW_SHOWNORMAL + application.handle, + pchar(a1), + pchar(AssociatedFile), + '', + '', + SW_SHOWNORMAL ); if (r > 32) then WinShellExecute := true else WinShellExecute := false; @@ -5664,21 +5311,21 @@ end; procedure TMainForm.mnuExportFlameClick(Sender: TObject); var FileList: Tstringlist; - Ext, ex, Path: string; + Ext: string; cp1: TControlPoint; begin if not FileExists(flam3Path) then begin - Application.MessageBox(PChar(TextByKey('main-status-noflam3')), 'Apophysis', 16); + Application.MessageBox(PChar(TextByKey('main-status-noflam3')), ApophysisSVN, 16); exit; end; // AV: we really don't need to waste the memory and create it at startup ExportDialog := TExportDialog.Create(Application); // AV case ExportFileFormat of - 1: Ext := 'jpg'; - 2: Ext := 'ppm'; - 3: Ext := 'png'; + 1: Ext := '.jpg'; + 2: Ext := '.ppm'; + 3: Ext := '.png'; end; FileList := TstringList.Create; cp1 := TControlPoint.Create; @@ -5689,44 +5336,49 @@ begin ExportDialog.Filter_Radius := ExportFilter; ExportDialog.Oversample := ExportOversample; try - ExportDialog.Filename := RenderPath + Maincp.name + '.' + Ext; + ExportDialog.Filename := RenderPath + Maincp.name + Ext; if ExportDialog.ShowModal = mrOK then begin - ex := ExtractFileExt(ExportDialog.Filename); - if ExtractFileExt(ExportDialog.Filename) = '.ppm' then + Ext := ExtractFileExt(ExportDialog.Filename); + if Ext = '.ppm' then ExportFileFormat := 2 - else if ExtractFileExt(ExportDialog.Filename) = '.png' then + else if Ext = '.png' then ExportFileFormat := 3 - else + else // if Ext = '.jpg' then ExportFileFormat := 1; + Delete(Ext, 1, 1); + { case ExportFileFormat of 1: Ext := 'jpg'; 2: Ext := 'ppm'; 3: Ext := 'png'; end; + } + ExportWidth := ExportDialog.ImageWidth; ExportHeight := ExportDialog.ImageHeight; ExportDensity := ExportDialog.Sample_density; ExportFilter := ExportDialog.Filter_Radius; ExportOversample := ExportDialog.Oversample; - ExportBatches := ExportDialog.Batches; ExportEstimator := ExportDialog.Estimator; ExportEstimatorMin := ExportDialog.EstimatorMin; ExportEstimatorCurve := ExportDialog.EstimatorCurve; - ExportJitters := ExportDialog.Jitters; ExportGammaTreshold := ExportDialog.GammaTreshold; + // AV: user cannot change the following, anyway + //ExportJitters := ExportDialog.Jitters; + //ExportBatches := ExportDialog.Batches; cp1.sample_density := ExportDensity; cp1.spatial_oversample := ExportOversample; cp1.spatial_filter_radius := ExportFilter; - cp1.nbatches := ExportBatches; + cp1.nbatches := 1; //ExportBatches; + cp1.jitters := 1; //ExportJitters; if (cp1.width <> ExportWidth) or (cp1.Height <> ExportHeight) then cp1.AdjustScale(ExportWidth, ExportHeight); cp1.estimator := ExportEstimator; cp1.estimator_min := ExportEstimatorMin; cp1.estimator_curve := ExportEstimatorCurve; - cp1.jitters := ExportJitters; cp1.gamma_threshold := ExportGammaTreshold; - FileList.Text := FlameToXML(cp1, true, false); + FileList.Text := FlameToXML(cp1, true); FileList.SaveToFile(ChangeFileExt(ExportDialog.Filename, '.flame')); FileList.Clear; FileList.Add('@echo off'); @@ -5750,19 +5402,17 @@ begin FileList.Add('@echo Rendering "' + ExportDialog.Filename + '"'); FileList.Add('"' + flam3Path + '" < "' + ChangeFileExt(ExportDialog.Filename, '.flame') + '"'); - Path := ExtractFilePath(ExtractFileDir(ExportDialog.Filename) + '\'); - FileList.SaveToFile(ChangeFileExt(ExportDialog.Filename, '.bat')); if ExportDialog.chkRender.Checked then begin - SetCurrentDir(Path); + SetCurrentDir(ExtractFilePath(ExportDialog.Filename)); WinShellOpen(ChangeFileExt(ExportDialog.Filename, '.bat')); end; end; finally FileList.Free; cp1.free; - ExportDialog.Free; // AV + ExportDialog.Free; // AV: destroying unnecessary form end; end; @@ -5814,16 +5464,18 @@ end; procedure TMainForm.ListXmlScannerStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); begin - pname := String(Attributes.value(TStringType('name'))); - ptime := String(Attributes.value(TStringType('time'))); - // pversion := String(Attributes.value(TStringType('version'))); + if (TagName = 'flame') then begin // AV: fixed + pname := string(Attributes.value('name')); + ptime := string(Attributes.value('time')); + // pversion := string(Attributes.value('version')); + end; end; procedure TMainForm.XMLScannerStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); var Tokens: TStringList; - v: TStringType; + v: string; //TStringType; ParsePos, i : integer; begin Tokens := TStringList.Create; @@ -5831,8 +5483,8 @@ begin if TagName='xformset' then // unused in this release... begin - v := Attributes.Value(TStringType('enabled')); - if v <> '' then ParseCP.finalXformEnabled := (StrToInt(String(v)) <> 0) + v := string(Attributes.Value('enabled')); + if v <> '' then ParseCP.finalXformEnabled := (StrToInt(v) <> 0) else ParseCP.finalXformEnabled := true; inc(activeXformSet); @@ -5841,110 +5493,110 @@ begin begin BeginParsing; - v := Attributes.value(TStringType('version')); // AV - if (pos('Apophysis 2.0', String(v)) > 0) or (v = '') then + v := string(Attributes.value('version')); // AV + if (pos('Apophysis 2.0', v) > 0) or (v = '') then oldApo := true else oldApo := false; - v := Attributes.value(TStringType('name')); - if v <> '' then Parsecp.name := String(v) else Parsecp.name := 'untitled'; - v := Attributes.Value('time'); - if v <> '' then Parsecp.Time := StrToFloat(String(v)); - v := Attributes.value('palette'); + v := string(Attributes.value('name')); + if v <> '' then Parsecp.name := v else Parsecp.name := 'untitled'; + v := string(Attributes.Value('time')); + if v <> '' then Parsecp.Time := StrToFloat(v); + v := string(Attributes.value('palette')); if v <> '' then - Parsecp.cmapindex := StrToInt(String(v)) + Parsecp.cmapindex := StrToInt(v) else Parsecp.cmapindex := -1; - v := Attributes.value('gradient'); + v := string(Attributes.value('gradient')); if v <> '' then - Parsecp.cmapindex := StrToInt(String(v)) + Parsecp.cmapindex := StrToInt(v) else Parsecp.cmapindex := -1; //ParseCP.hue_rotation := 1; - v := Attributes.value('hue'); // AV: to animate the palette + v := string(Attributes.value('hue')); // AV: to animate the palette if v <> '' then - Parsecp.hue_rotation := StrToFloat(String(v)) + Parsecp.hue_rotation := StrToFloat(v) else ParseCP.hue_rotation := 1; - v := Attributes.Value('brightness'); - if v <> '' then Parsecp.Brightness := StrToFloat(String(v)); - v := Attributes.Value('gamma'); - if v <> '' then Parsecp.gamma := StrToFloat(String(v)); - v := Attributes.Value('contrast'); // AV - if v <> '' then Parsecp.contrast := StrToFloat(String(v)); - v := Attributes.Value('vibrancy'); - if v <> '' then Parsecp.vibrancy := StrToFloat(String(v)); + v := string(Attributes.Value('brightness')); + if v <> '' then Parsecp.Brightness := StrToFloat(v); + v := string(Attributes.Value('gamma')); + if v <> '' then Parsecp.gamma := StrToFloat(v); + v := string(Attributes.Value('contrast')); // AV + if v <> '' then Parsecp.contrast := StrToFloat(v); + v := string(Attributes.Value('vibrancy')); + if v <> '' then Parsecp.vibrancy := StrToFloat(v); if (LimitVibrancy) and (Parsecp.vibrancy > 1) then Parsecp.vibrancy := 1; - v := Attributes.Value('gamma_threshold'); - if v <> '' then Parsecp.gamma_threshold := StrToFloat(String(v)) + v := string(Attributes.Value('gamma_threshold')); + if v <> '' then Parsecp.gamma_threshold := StrToFloat(v) else Parsecp.gamma_threshold := 0; - v := Attributes.Value('zoom'); - if v <> '' then Parsecp.zoom := StrToFloat(String(v)); - v := Attributes.Value('scale'); - if v <> '' then Parsecp.pixels_per_unit := StrToFloat(String(v)); - v := Attributes.Value('rotate'); - if v <> '' then Parsecp.FAngle := -PI * StrToFloat(String(v))/180; - v := Attributes.Value('angle'); - if v <> '' then Parsecp.FAngle := StrToFloat(String(v)); + v := string(Attributes.Value('zoom')); + if v <> '' then Parsecp.zoom := StrToFloat(v); + v := string(Attributes.Value('scale')); + if v <> '' then Parsecp.pixels_per_unit := StrToFloat(v); + v := string(Attributes.Value('rotate')); + if v <> '' then Parsecp.FAngle := -PI * StrToFloat(v)/180; + v := string(Attributes.Value('angle')); + if v <> '' then Parsecp.FAngle := StrToFloat(v); // 3d - v := Attributes.Value('cam_pitch'); - if v <> '' then Parsecp.cameraPitch := StrToFloat(String(v)); - v := Attributes.Value('cam_yaw'); - if v <> '' then Parsecp.cameraYaw := StrToFloat(String(v)); - v := Attributes.Value('cam_roll'); - if v <> '' then Parsecp.cameraRoll := StrToFloat(String(v)); - v := Attributes.Value('cam_dist'); - if v <> '' then Parsecp.cameraPersp := 1/StrToFloat(String(v)); - v := Attributes.Value('cam_perspective'); - if v <> '' then Parsecp.cameraPersp := StrToFloat(String(v)); - v := Attributes.Value('cam_zpos'); - if v <> '' then Parsecp.cameraZpos := StrToFloat(String(v)); - v := Attributes.Value('cam_dof'); - if v <> '' then Parsecp.cameraDOF := abs(StrToFloat(String(v))); + v := string(Attributes.Value('cam_pitch')); + if v <> '' then Parsecp.cameraPitch := StrToFloat(v); + v := string(Attributes.Value('cam_yaw')); + if v <> '' then Parsecp.cameraYaw := StrToFloat(v); + v := string(Attributes.Value('cam_roll')); + if v <> '' then Parsecp.cameraRoll := StrToFloat(v); + v := string(Attributes.Value('cam_dist')); + if v <> '' then Parsecp.cameraPersp := 1/StrToFloat(v); + v := string(Attributes.Value('cam_perspective')); + if v <> '' then Parsecp.cameraPersp := StrToFloat(v); + v := string(Attributes.Value('cam_zpos')); + if v <> '' then Parsecp.cameraZpos := StrToFloat(v); + v := string(Attributes.Value('cam_dof')); + if v <> '' then Parsecp.cameraDOF := abs(StrToFloat(v)); //density estimation - v := Attributes.Value('estimator_radius'); - if v <> '' then Parsecp.estimator := StrToFloat(String(v)); - v := Attributes.Value('estimator_minimum'); - if v <> '' then Parsecp.estimator_min := StrToFloat(String(v)); - v := Attributes.Value('estimator_curve'); - if v <> '' then Parsecp.estimator_curve := StrToFloat(String(v)); - v := Attributes.Value('enable_de'); + v := string(Attributes.Value('estimator_radius')); + if v <> '' then Parsecp.estimator := StrToFloat(v); + v := string(Attributes.Value('estimator_minimum')); + if v <> '' then Parsecp.estimator_min := StrToFloat(v); + v := string(Attributes.Value('estimator_curve')); + if v <> '' then Parsecp.estimator_curve := StrToFloat(v); + v := string(Attributes.Value('enable_de')); if (v = '1') then Parsecp.enable_de := true; - v := Attributes.Value('new_linear'); + v := string(Attributes.Value('new_linear')); if (v = '1') then // AV Parsecp.noLinearFix := true else ParseCp.noLinearFix := false; - v := Attributes.Value('curves'); + v := string(Attributes.Value('curves')); if (v <> '') then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); ParsePos := -1; for i := 0 to 3 do begin - Inc(ParsePos);ParseCp.curvePoints[i][0].x := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][0].y := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curveWeights[i][0] := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][1].x := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][1].y := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curveWeights[i][1] := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][2].x := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][2].y := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curveWeights[i][2] := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][3].x := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curvePoints[i][3].y := StrToFloat(Tokens[ParsePos]); - Inc(ParsePos);ParseCp.curveWeights[i][3] := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][0].x := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][0].y := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curveWeights[i][0] := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][1].x := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][1].y := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curveWeights[i][1] := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][2].x := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][2].y := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curveWeights[i][2] := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][3].x := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curvePoints[i][3].y := StrToFloat(Tokens[ParsePos]); + Inc(ParsePos); ParseCp.curveWeights[i][3] := StrToFloat(Tokens[ParsePos]); end; end; try - v := Attributes.Value('center'); - GetTokens(String(v), tokens); + v := string(Attributes.Value('center')); + GetTokens(v, tokens); Parsecp.center[0] := StrToFloat(Tokens[0]); Parsecp.center[1] := StrToFloat(Tokens[1]); @@ -5953,15 +5605,15 @@ begin Parsecp.center[1] := 0; end; - v := Attributes.Value('size'); - GetTokens(String(v), tokens); + v := string(Attributes.Value('size')); + GetTokens(v, tokens); Parsecp.width := StrToInt(Tokens[0]); Parsecp.height := StrToInt(Tokens[1]); try - v := Attributes.Value('background'); - GetTokens(String(v), tokens); + v := string(Attributes.Value('background')); + GetTokens(v, tokens); Parsecp.background[0] := Floor(StrToFloat(Tokens[0]) * 255); Parsecp.background[1] := Floor(StrToFloat(Tokens[1]) * 255); @@ -5972,11 +5624,11 @@ begin Parsecp.background[2] := 0; end; - v := Attributes.Value('soloxform'); - if v <> '' then Parsecp.soloXform := StrToInt(String(v)); + v := string(Attributes.Value('soloxform')); + if v <> '' then Parsecp.soloXform := StrToInt(v); - v := Attributes.Value('plugins'); - GetTokens(String(v), tokens); + v := string(Attributes.Value('plugins')); + GetTokens(v, tokens); if (tokens.Count > 0) then begin ParseCP.used_plugins.Clear; @@ -5985,23 +5637,38 @@ begin end; (* // AV: commented out since it's useless v := Attributes.Value('nick'); - if Trim(String(v)) = '' then v := TStringType(SheepNick); - Parsecp.Nick := String(v); + if Trim(v) = '' then v := SheepNick; + Parsecp.Nick := v; v := Attributes.Value('url'); - if Trim(String(v)) = '' then v := TStringType(SheepUrl); - Parsecp.URL := String(v); + if Trim(v) = '' then v := SheepUrl; + Parsecp.URL := v; *) end else if TagName='palette' then begin - XMLPaletteFormat := String(Attributes.Value('format')); - XMLPaletteCount := StrToIntDef(String(Attributes.Value('count')), 256); + XMLPaletteFormat := string(Attributes.Value('format')); + XMLPaletteCount := StrToIntDef(string(Attributes.Value('count')), 256); end; finally Tokens.free; end; end; +function GetComment(str: string): string; +{ AV: Extracts comment from XML-file } +begin + try + Result := Trim(Copy(str, 5, Length(str) - 7)); + except + Result := ''; + end; +end; + +procedure TMainForm.XmlScannerComment(Sender: TObject; Comment: string); +begin + ParseCP.comment := GetComment(Comment); +end; + function flatten_val(Attributes: TAttrList): double; var vv: array of double; @@ -6024,7 +5691,7 @@ begin d := false; for i := 0 to High(vn) do begin - s := String(Attributes.Value(TStringType(vn[i]))); + s := string(Attributes.Value(Utf8String(vn[i]))); if (s <> '') then vv[i] := StrToFloat(s) else vv[i] := 0; d := d or (vv[i] <> 0); @@ -6044,15 +5711,15 @@ var vn: array of string; i: integer; s: string; -begin +begin SetLength(vv, 2); vn := ['linear3D', 'linear']; - + Result := 0; - + for i := 0 to 1 do begin - s := String(Attributes.Value(TStringType(vn[i]))); + s := string(Attributes.Value(Utf8String(vn[i]))); if (s <> '') then vv[i] := StrToFloat(s) else vv[i] := 0; Result := Result + vv[i]; @@ -6063,14 +5730,11 @@ begin end; procedure TMainForm.XmlScannerContent(Sender: TObject; Content: String); -var i: byte; - h, s, v, hue: real; begin - if XMLPaletteCount <= 0 then begin + if XMLPaletteCount <= 0 then //ShowMessage('ERROR: No colors in palette!'); - Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR); - exit; - end; + raise Exception.Create(TextByKey('common-invalidformat') + ': palette'); // AV + if XMLPaletteFormat = 'RGB' then begin ParseCompactColors(ParseCP, XMLPaletteCount, Content, false); @@ -6079,21 +5743,13 @@ begin begin ParseCompactColors(ParseCP, XMLPaletteCount, Content); end - else begin - Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR); - exit; - end; + else + raise Exception.Create(TextByKey('common-invalidformat') + ': palette'); // AV + Parsecp.cmapindex := -1; // AV: restored hue rotation support, useful for animation - hue := Parsecp.hue_rotation; - if (hue < 1) and (hue > 0) then - for i := 0 to 255 do - begin - RGBToHSV(Parsecp.cmap[i][0], Parsecp.cmap[i][1], Parsecp.cmap[i][2], h, s, v); - h := Round(360 + h + (hue * 360)) mod 360; - HSVToRGB(h, s, v, Parsecp.cmap[i][0], Parsecp.cmap[i][1], Parsecp.cmap[i][2]); - end; + RotateCMapHue(Parsecp); XMLPaletteFormat := ''; XMLPaletteCount := 0; @@ -6103,7 +5759,7 @@ procedure TMainForm.XMLScannerEmptyTag(Sender: TObject; TagName: string; Attributes: TAttrList); var i, j, k, vindex: integer; // j, k - AV - v, l, s: TStringType; + v, l, s: string; //TStringType; d, floatcolor, vl, n: double; Tokens: TStringList; begin @@ -6111,34 +5767,35 @@ begin Tokens := TStringList.Create; try if (TagName = 'xform') or (TagName = 'finalxform') then - if {(TagName = 'finalxform') and} (FinalXformLoaded) then Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR) + if {(TagName = 'finalxform') and} (FinalXformLoaded) then + Application.MessageBox(PChar(TextByKey('common-invalidformat')), ApophysisSVN, MB_ICONERROR) + // ShowMessage('ERROR: No xforms allowed after FinalXform!') else - begin + begin // AV for i := 0 to Attributes.Count - 1 do begin - if not ScanVariations(String(attributes.Name(i))) and - not ScanVariables(String(attributes.Name(i))) then - CheckAttribute(String(Attributes.Name(i))); + if not ScanVariations(string(attributes.Name(i))) and + not ScanVariables(string(attributes.Name(i))) then + CheckAttribute(string(Attributes.Name(i))); end; if (TagName = 'finalxform') or (activeXformSet > 0) then FinalXformLoaded := true; with ParseCP.xform[nXform] do begin Clear; - v := Attributes.Value('weight'); - if (v <> '') and (TagName = 'xform') then density := StrToFloat(String(v)); + v := string(Attributes.Value('weight')); + if (v <> '') and (TagName = 'xform') then density := StrToFloat(v); if (TagName = 'finalxform') then begin - v := Attributes.Value('enabled'); - if v <> '' then ParseCP.finalXformEnabled := (StrToInt(String(v)) <> 0) + v := string(Attributes.Value('enabled')); + if v <> '' then ParseCP.finalXformEnabled := (StrToInt(v) <> 0) else ParseCP.finalXformEnabled := true; end; if activexformset > 0 then density := 0; // tmp... - ///////////// AV: checking variation order //////////////////// - // TODO: optimize! - v := Attributes.Value('var_order'); + //**************** AV: checking variation order ***********// + v := string(Attributes.Value('var_order')); if v <> '' then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); k := -1; for j := 0 to Tokens.Count-1 do begin @@ -6150,28 +5807,34 @@ begin end; end; end; - ////////////////////////////////////////////////////////////// + //************************************************************// - v := Attributes.Value('color'); - if v <> '' then color := StrToFloat(String(v)); - v := Attributes.Value('var_color'); - if v <> '' then pluginColor := StrToFloat(String(v)); - v := Attributes.Value('symmetry'); - if v <> '' then symmetry := StrToFloat(String(v)); - v := Attributes.Value('coefs'); - GetTokens(String(v), tokens); - if Tokens.Count < 6 then Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR); + v := string(Attributes.Value('color')); + if v <> '' then color := StrToFloat(v); + v := string(Attributes.Value('var_color')); + if v <> '' then pluginColor := StrToFloat(v); + v := string(Attributes.Value('symmetry')); + if v <> '' then symmetry := StrToFloat(v); + v := string(Attributes.Value('coefs')); + if v <> '' then begin + GetTokens(v, tokens); + if Tokens.Count < 6 then + Application.MessageBox(PChar(TextByKey('common-invalidformat') + ': coefs'), + ApophysisSVN, MB_ICONERROR); c[0][0] := StrToFloat(Tokens[0]); c[0][1] := StrToFloat(Tokens[1]); c[1][0] := StrToFloat(Tokens[2]); c[1][1] := StrToFloat(Tokens[3]); c[2][0] := StrToFloat(Tokens[4]); c[2][1] := StrToFloat(Tokens[5]); + end; - v := Attributes.Value('post'); + v := string(Attributes.Value('post')); if v <> '' then begin - GetTokens(String(v), tokens); - if Tokens.Count < 6 then Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR); + GetTokens(v, tokens); + if Tokens.Count < 6 then + Application.MessageBox(PChar(TextByKey('common-invalidformat') + ': post'), + ApophysisSVN, MB_ICONERROR); p[0][0] := StrToFloat(Tokens[0]); p[0][1] := StrToFloat(Tokens[1]); p[1][0] := StrToFloat(Tokens[2]); @@ -6180,31 +5843,31 @@ begin p[2][1] := StrToFloat(Tokens[5]); end; - v := Attributes.Value('chaos'); + v := string(Attributes.Value('chaos')); if v <> '' then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); for i := 0 to Tokens.Count-1 do modWeights[i] := Abs(StrToFloat(Tokens[i])); end; //else for i := 0 to NXFORMS-1 do modWeights[i] := 1; // for 2.09 flames compatibility - v := Attributes.Value('opacity'); + v := string(Attributes.Value('opacity')); if v <> '' then begin - if StrToFloat(String(v)) = 0.0 then begin + if StrToFloat(v) = 0.0 then begin transOpacity := 0; end else begin - transOpacity := StrToFloat(String(v)); + transOpacity := StrToFloat(v); end; end; // 7x.9 name tag - v := Attributes.Value('name'); + v := string(Attributes.Value('name')); if v <> '' then begin - TransformName := String(v); + TransformName := v; end; - v := Attributes.Value('plotmode'); + v := string(Attributes.Value('plotmode')); if v <> '' then begin if v = 'off' then begin transOpacity := 0; @@ -6215,11 +5878,11 @@ begin if ParseCp.noLinearFix then for i := 0 to 1 do begin - SetVariation(i, 0); - v := TStringType(ReadWithSubst(Attributes, varnames(i))); - //v := Attributes.Value(AnsiString(varnames(i))); + v := ReadWithSubst(Attributes, varnames(i)); if v <> '' then - SetVariation(i, StrToFloat(String(v))); + SetVariation(i, StrToFloat(v)) + else + SetVariation(i, 0); end else begin SetVariation(0, linear_val(Attributes)); @@ -6230,40 +5893,40 @@ begin // now parse the rest of the variations...as usual for i := 2 to NRVAR - 1 do begin - SetVariation(i, 0); - v := TStringType(ReadWithSubst(Attributes, varnames(i))); - //v := Attributes.Value(AnsiString(varnames(i))); + v := ReadWithSubst(Attributes, varnames(i)); if v <> '' then - SetVariation(i, StrToFloat(String(v))); + SetVariation(i, StrToFloat(v)) + else + SetVariation(i, 0); end; // and the variables for i := 0 to GetNrVariableNames - 1 do begin - v := TStringType(ReadWithSubst(Attributes, GetVariableNameAt(i))); - //v := Attributes.Value(AnsiString(GetVariableNameAt(i))); + s := GetVariableNameAt(i); + v := ReadWithSubst(Attributes, s); if v <> '' then begin {$ifndef VAR_STR} - d := StrToFloat(String(v)); - SetVariable(GetVariableNameAt(i), d); + d := StrToFloat(v); + SetVariable(s, d); {$else} - SetVariableStr(GetVariableNameAt(i), String(v)); + SetVariableStr(s, v); {$endif} end; end; - + {***** AV: tryig to convert old Apo 2.0x variations into new ones *****} if oldApo then begin // AV: 'perspective' into 'projective' - v := Attributes.Value('perspective'); - s := Attributes.Value('projective'); + v := string(Attributes.Value('perspective')); + s := string(Attributes.Value('projective')); if (v <> '') and (s = '') then // avoid to overwrite begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('projective'), d); - v := Attributes.Value('perspective_dist'); - l := Attributes.Value('perspective_angle'); - vl := StrToFloat(String(v)); // dist - d := StrToFloat(String(l)); // angle + v := string(Attributes.Value('perspective_dist')); + l := string(Attributes.Value('perspective_angle')); + vl := StrToFloat(v); // dist + d := StrToFloat(l); // angle n := 0; SetVariable('pr_A', n); SetVariable('pr_B1', n); @@ -6280,17 +5943,17 @@ begin SetVariable('projective_mode', n); end else if (v <> '') and (s <> '') then - begin + begin MissingPlugin.MissingPluginList.Add('perspective'); - MissingPlugin.MissingPluginList.Add('perspective_angle'); - MissingPlugin.MissingPluginList.Add('perspective_dist'); - end; + MissingPlugin.MissingPluginList.Add('perspective_angle'); + MissingPlugin.MissingPluginList.Add('perspective_dist'); + end; - v := Attributes.Value('rings'); - s := Attributes.Value('rings2'); + v := string(Attributes.Value('rings')); + s := string(Attributes.Value('rings2')); if (v <> '') and (s = '') then begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('rings2'), d); n := c[2][0]; SetVariable('rings2_val', n); @@ -6300,11 +5963,11 @@ begin else if (v <> '') and (s <> '') then MissingPlugin.MissingPluginList.Add('rings'); - v := Attributes.Value('fan'); - s := Attributes.Value('fan2'); + v := string(Attributes.Value('fan')); + s := string(Attributes.Value('fan2')); if (v <> '') and (s = '') then begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('fan2'), d); n := c[2][0]; SetVariable('fan2_x', n); @@ -6316,13 +5979,13 @@ begin else if (v <> '') and (s <> '') then MissingPlugin.MissingPluginList.Add('fan'); - v := Attributes.Value('bent'); + v := string(Attributes.Value('bent')); if (v <> '') then begin - s := Attributes.Value('bent2'); + s := string(Attributes.Value('bent2')); if (s = '') then begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('bent2'), d); n := 2; SetVariable('bent2_x', n); @@ -6334,11 +5997,11 @@ begin else MissingPlugin.MissingPluginList.Add('bent'); end; - v := Attributes.Value('waves'); - s := Attributes.Value('waves2'); + v := string(Attributes.Value('waves')); + s := string(Attributes.Value('waves2')); if (v <> '') and (s = '') then begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('waves2'), d); n := c[1][0]; SetVariable('waves2_scalex', n); @@ -6355,13 +6018,13 @@ begin else if (v <> '') and (s <> '') then MissingPlugin.MissingPluginList.Add('waves'); - v := Attributes.Value('popcorn'); + v := string(Attributes.Value('popcorn')); if (v <> '') then begin - s := Attributes.Value('popcorn2'); + s := string(Attributes.Value('popcorn2')); if (s = '') then begin - d := StrToFloat(String(v)); + d := StrToFloat(v); SetVariation(GetVariationIndex('popcorn2'), d); n := c[2][0]; SetVariable('popcorn2_x', n); @@ -6374,106 +6037,112 @@ begin end; end; // oldApo - // AV: Droste into Escher - v := Attributes.Value('droste'); - s := Attributes.Value('escher'); - if (v <> '') and (s = '') then - begin - d := StrToFloat(String(v)); - SetVariation(GetVariationIndex('escher'), d); - v := Attributes.Value('droste_r1'); - l := Attributes.Value('droste_r2'); - try - vl := StrToFloat(String(v)); // r1 - d := StrToFloat(String(l)); // r2 - if (vl <> d) then - n := 2 * arctan(ln(d / vl) / 2 / pi) - else n := 0; - SetVariable('escher_beta', n); - except - n := 0; - SetVariable('escher_beta', n); - end; - end - else if (v <> '') and (s <> '') then - begin - MissingPlugin.MissingPluginList.Add('droste'); - MissingPlugin.MissingPluginList.Add('droste_r1'); - MissingPlugin.MissingPluginList.Add('droste_r2'); - end; - - // Spherical3D into inversion3D - v := Attributes.Value('Spherical3D'); - if (v <> '') and (GetVariationIndex('Spherical3D')< 0) then - // if plugin is NOT available - begin - s := Attributes.Value('inversion3D'); - if (s = '') then + // AV: Droste into Escher + v := string(Attributes.Value('droste')); + s := string(Attributes.Value('escher')); + if (v <> '') and (s = '') then begin - d := StrToFloat(String(v)); - SetVariation(GetVariationIndex('inversion3D'), d); - n := 1; - SetVariable('inversion3D_radius', n); - n := 0; - SetVariable('inversion3D_x0', n); - SetVariable('inversion3D_y0', n); - SetVariable('inversion3D_z0', n); + d := StrToFloat(v); + SetVariation(GetVariationIndex('escher'), d); + v := string(Attributes.Value('droste_r1')); + l := string(Attributes.Value('droste_r2')); + try + vl := StrToFloat(v); // r1 + d := StrToFloat(l); // r2 + if (vl <> d) then + n := 2 * arctan(ln(d / vl) / 2 / pi) + else n := 0; + SetVariable('escher_beta', n); + except + n := 0; + SetVariable('escher_beta', n); + end; end - else MissingPlugin.MissingPluginList.Add('Spherical3D'); - end; - - // secant into secant2 - v := Attributes.Value('secant'); - if (v <> '') and (GetVariationIndex('secant') < 0) then - // if plugin is NOT available - begin - s := Attributes.Value('secant2'); - if (s = '') then + else if (v <> '') and (s <> '') then begin - d := StrToFloat(String(v)); - SetVariation(GetVariationIndex('secant2'), d); - n := 1; - SetVariable('secant2_old', n); - end - else MissingPlugin.MissingPluginList.Add('secant'); - end; + MissingPlugin.MissingPluginList.Add('droste'); + MissingPlugin.MissingPluginList.Add('droste_r1'); + MissingPlugin.MissingPluginList.Add('droste_r2'); + end; - // arch into Z_arch - v := Attributes.Value('arch'); - if (v <> '') then - begin - s := Attributes.Value('Z_arch'); - if (s = '') then + // Spherical3D into inversion3D + v := string(Attributes.Value('Spherical3D')); + if (v <> '') and (GetVariationIndex('Spherical3D')< 0) then + // if plugin is NOT available begin - d := StrToFloat(String(v)); - SetVariation(GetVariationIndex('Z_arch'), d); - SetVariable('Z_arch_weight', d); - end - else MissingPlugin.MissingPluginList.Add('arch'); - end; + s := string(Attributes.Value('inversion3D')); + if (s = '') then + begin + d := StrToFloat(v); + SetVariation(GetVariationIndex('inversion3D'), d); + n := 1; + SetVariable('inversion3D_radius', n); + n := 0; + SetVariable('inversion3D_x0', n); + SetVariable('inversion3D_y0', n); + SetVariable('inversion3D_z0', n); + end + else MissingPlugin.MissingPluginList.Add('Spherical3D'); + end; - {*****************************************************************************} + // secant into secant2 + v := string(Attributes.Value('secant')); + if (v <> '') and (GetVariationIndex('secant') < 0) then + // if plugin is NOT available + begin + s := string(Attributes.Value('secant2')); + if (s = '') then + begin + d := StrToFloat(v); + SetVariation(GetVariationIndex('secant2'), d); + n := 1; + SetVariable('secant2_old', n); + end + else MissingPlugin.MissingPluginList.Add('secant'); + end; + + // arch into Z_arch + v := string(Attributes.Value('arch')); + if (v <> '') then + begin + s := string(Attributes.Value('Z_arch')); + if (s = '') then + begin + d := StrToFloat(v); + SetVariation(GetVariationIndex('Z_arch'), d); + SetVariable('Z_arch_weight', d); + end + else MissingPlugin.MissingPluginList.Add('arch'); + end; + + {********************************************************} // legacy variation/variable notation - v := Attributes.Value('var1'); + v := string(Attributes.Value('var1')); if v <> '' then begin for i := 0 to NRVAR - 1 do SetVariation(i, 0); - SetVariation(StrToInt(String(v)), 1); + SetVariation(StrToInt(v), 1); end; - v := Attributes.Value('var'); + v := string(Attributes.Value('var')); if v <> '' then begin for i := 0 to NRVAR - 1 do SetVariation(i, 0); - GetTokens(String(v), tokens); - if Tokens.Count > NRVAR then Application.MessageBox(PChar(TextByKey('common-invalidformat')), 'Apophysis', MB_ICONERROR); + GetTokens(v, tokens); + if Tokens.Count > NRVAR then + Application.MessageBox(PChar(TextByKey('common-invalidformat')), + ApophysisSVN, MB_ICONERROR); for i := 0 to Tokens.Count - 1 do SetVariation(i, StrToFloat(Tokens[i])); end; end; - Inc(nXform); + // AV: prevent crash with flames containing over 100 xforms + {$ifndef T500} + if nXform < NXFORMS then + {$endif} + Inc(nXform); end; if TagName = 'color' then begin @@ -6481,9 +6150,9 @@ begin //if Parsecp.cmapindex = -2 then Parsecp.cmapindex := -1; - i := StrToInt(String(Attributes.value('index'))); - v := Attributes.value('rgb'); - GetTokens(String(v), tokens); + i := StrToInt(string(Attributes.value('index'))); + v := string(Attributes.value('rgb')); + GetTokens(v, tokens); floatcolor := StrToFloat(Tokens[0]); Parsecp.cmap[i][0] := round(floatcolor); floatcolor := StrToFloat(Tokens[1]); @@ -6493,19 +6162,21 @@ begin end; if TagName = 'colors' then begin - ParseCompactcolors(Parsecp, StrToInt(String(Attributes.value('count'))), - String(Attributes.value('data'))); + ParseCompactcolors(Parsecp, StrToInt(string(Attributes.value('count'))), + string(Attributes.value('data'))); Parsecp.cmapindex := -1; end; if TagName = 'symmetry' then begin - i := StrToInt(String(Attributes.value('kind'))); + i := StrToInt(string(Attributes.value('kind'))); Parsecp.symmetry := i; end; + { if TagName = 'xdata' then begin - Parsecp.xdata := Parsecp.xdata + String(Attributes.value('content')); + Parsecp.xdata := Parsecp.xdata + string(Attributes.value('content')); end; + } finally Tokens.free; end; @@ -6648,7 +6319,7 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); const snap_angle = 0.261799387799149; // AV: the same as 15*pi/180; @@ -6784,7 +6455,7 @@ begin Result.Bottom := r.Bottom * scale; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.ImageMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var @@ -6889,7 +6560,7 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.DrawImageView; var i, j: integer; @@ -6991,7 +6662,7 @@ begin bm.Free; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// (* procedure TMainForm.DrawPitchYawLines(YawAngle: double; PitchAngle: double); var @@ -7066,7 +6737,7 @@ begin bkuPen.Free; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.DrawZoomWindow; const cornerSize = 32; @@ -7143,42 +6814,43 @@ begin bkuPen.Free; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.tbzoomwindowClick(Sender: TObject); begin FMouseMoveState := msZoomWindow; end; -/////////////////////////////////////////////////////////////////////////////// procedure TMainForm.tbzoomoutwindowClick(Sender: TObject); begin FMouseMoveState := msZoomOutWindow; end; -/////////////////////////////////////////////////////////////////////////////// procedure TMainForm.tbDragClick(Sender: TObject); begin FMouseMoveState := msDrag; end; -/////////////////////////////////////////////////////////////////////////////// procedure TMainForm.tbRotateClick(Sender: TObject); begin FMouseMoveState := msRotate; end; -/////////////////////////////////////////////////////////////////////////////// +//***************************************************************************// procedure TMainForm.FillVariantMenu; var - i: integer; + i, j: smallint; s: string; NewMenuItem : TMenuItem; + svars: TStringList; begin SetLength(VarMenus, NrVar); // AV: to prevent underlined letters with GUI themes mnuBuiltinVars.AutoHotkeys := maManual; mnuPluginVars.AutoHotkeys := maManual; + svars := TStringList.Create; + svars.Sorted := True; + for i := 0 to NRVAR - 1 do begin NewMenuItem := TMenuItem.Create(self); s := varnames(i); @@ -7189,62 +6861,94 @@ begin NewMenuItem.Tag := i; NewMenuItem.GroupIndex := 2; NewMenuItem.RadioItem := True; - // AV: exotic GUI styles not always work well :-/ - if TStyleManager.ActiveStyle.Name <> 'Windows' then - if (i mod 30 = 0) then NewMenuItem.Break := mbBreak; VarMenus[i] := NewMenuItem; - if i < NumBuiltinVars then - mnuBuiltinVars.Add(NewMenuItem) - else + if i < NumBuiltinVars then begin // AV: creating sorted menu + j := svars.Add(NewMenuItem.Caption); // AV: remember the position... + mnuBuiltinVars.Insert(j, NewMenuItem); // ...and put it at the right place + end + else // AV: plugin variations are already sorted mnuPluginVars.Add(NewMenuItem); end; + + svars.Free; + + // AV: exotic GUI styles not always work well :-/ + if TStyleManager.ActiveStyle.Name <> 'Windows' then + begin + i := 0; + while i < mnuBuiltinVars.Count do + begin + mnuBuiltinVars[i].Break := mbBreak; + inc(i, mbHeight); + end; + i := 0; + while i < mnuPluginVars.Count do + begin + mnuPluginVars[i].Break := mbBreak; + inc(i, mbHeight); + end; + end; end; -/////////////////////////////////////////////////////////////////////////////// - procedure TMainForm.VariantMenuClick(Sender: TObject); -var i: integer; begin TMenuItem(Sender).Checked := True; // AV: only one variation type can be active, // but Apo allows to check up to 3 menu items, confusing users... - mnuVRandom.Checked := False; + if Variation > vRandom then + VarMenus[Variation].Checked := False + else + mnuVRandom.Checked := False; if (TMenuItem(Sender).Tag >= NumBuiltinVars) then begin - for i := 0 to NumBuiltinVars-1 do - VarMenus[i].Checked := False; // AV mnuBuiltinVars.Checked := False; mnuPluginVars.Checked := True; end else begin - for i := NumBuiltinVars to NrVar - 1 do - VarMenus[i].Checked := False; // AV mnuBuiltinVars.Checked := True; mnuPluginVars.Checked := False; end; UpdateUndo; - Variation := TVariation(TMenuItem(Sender).Tag); // ? + // AV: changed Variation to integer - no more ugly type-casting here! + Variation := TMenuItem(Sender).Tag; SetVariation(maincp); ResetLocation; RedrawTimer.Enabled := True; UpdateWindows; end; +{ /////////////////////////////////////////////////////////////////////////// } -////////// AV: Apo UI Appearance ///////////////////// +// AV: make it a separate method to be able to call it later +procedure TMainForm.SetAutoSaveTimer; +var mins: shortint; +begin + if (AutoSaveFreq = 0) then mins := 1 + else if (AutoSaveFreq = 1) then mins := 2 + else if (AutoSaveFreq = 2) then mins := 5 + else if (AutoSaveFreq = 3) then mins := 10 + else begin + mins := 5; + AutoSaveFreq := 2; + AutoSaveEnabled := false; + end; + + AutoSaveTimer.Interval := 60 * 1000 * mins; + AutoSaveTimer.Enabled := AutoSaveEnabled; +end; + +// AV: Apo UI Appearance ///////////////////////////// procedure TMainForm.CreateStyleList; -var i: integer; +var i: smallint; s: string; apostyle : TMenuItem; - sm: TStyleManager; begin - sm := TStyleManager.Create; - for i := 0 to Length(sm.StyleNames)-1 do + for i := 0 to Length(TStyleManager.StyleNames)-1 do begin apostyle := TMenuItem.Create(mnuApoStyle); - s := sm.StyleNames[i]; + s := TStyleManager.StyleNames[i]; apostyle.Caption := s; - if (sm.ActiveStyle.Name = s) then + if (TStyleManager.ActiveStyle.Name = s) then apostyle.Checked := True; apostyle.Name := 'style' + IntToStr(i); apostyle.RadioItem := True; @@ -7253,7 +6957,6 @@ begin apostyle.OnClick := StyleItemClick; mnuApoStyle.Add(apostyle); end; - sm.Free; end; procedure TMainForm.ShowStyledWindows(Sender: TObject); @@ -7272,10 +6975,10 @@ begin if not TMenuItem(Sender).Checked then begin TMenuItem(Sender).Checked := True; - newGUI := TStyleManager.StyleNames[TMenuItem(Sender).Tag]; + newGUI := TMenuItem(Sender).Caption; try - StopThread; + StopThread; // ? self.OnShow := ShowStyledWindows; if EditForm.Visible then EditForm.Close; @@ -7286,8 +6989,8 @@ begin TStyleManager.TrySetStyle(newGUI, false); except on EAccessViolation do // hmmm... - Application.MessageBox(PChar(TextByKey('options-restartnotice')), - PChar('Apophysis AV'), MB_ICONWARNING); + MessageBox(0, PChar(TextByKey('options-restartnotice')), + ApophysisSVN, MB_ICONWARNING); end; Registry := TRegistry.Create; @@ -7301,12 +7004,13 @@ begin end; end; end; + //--Z--//////////////////////////////////////////////////////////////////////// procedure TMainForm.tbQualityBoxKeyPress(Sender: TObject; var Key: Char); begin - if (Key = ',') then Key := '.'; // AV - if not CharinSet(Key,['0'..'9', #8, #13, #27, '.']) then Key := #0; // AV + if (Key = ',') then Key := '.'; // AV + if not CharinSet(Key,['0'..'9', #8, #13, #27, '.']) then Key := #0; // AV if key = #13 then begin tbQualityBoxSet(Sender); @@ -7385,112 +7089,7 @@ begin end; end; -{ -procedure TMainForm.ListViewChanging(Sender: TObject; Item: TListItem; - Change: TItemChange; var AllowChange: Boolean); -var sc, fc: string; -begin - if (Item = nil) or (Sender <> ListView1) then exit; - - sc := ''; fc := ''; - if (ListView1.Selected <> nil) then sc := ListView1.Selected.Caption; - if (ListView1.ItemFocused <> nil) then fc := ListView1.ItemFocused.Caption; - - if (Trim(Item.Caption) = Trim(maincp.name)) and (Item.Selected) and - (Item.Selected) and (Change = ctState) then - begin - if (DoNotAskAboutChange = true) then - begin - exit; - end; - if (UndoIndex <> 0) then - begin - // hack - if (LastCaptionSel = sc) and (LastCaptionFoc = fc) then begin - AllowChange := LastDecision; - if Not AllowChange then begin - ListView1.OnChange := nil; - ListView1.OnChanging := nil; - ListView1.Selected := Item; - ListView1.ItemFocused := Item; - ListView1.OnChanging := ListViewChanging; - ListView1.OnChange := ListViewChange; - end; - Exit; - end; - - LastCaptionSel := sc; - LastCaptionFoc := fc; - - if Application.MessageBox('Do you really want to open another flame? All changes made to the current flame will be lost.', 'Apophysis', MB_ICONWARNING or MB_YESNO) <> IDYES then - begin - AllowChange := false; - ListView1.OnChange := nil; - ListView1.OnChanging := nil; - ListView1.Selected := Item; - ListView1.ItemFocused := Item; - ListView1.OnChanging := ListViewChanging; - ListView1.OnChange := ListViewChange; - end - else - begin - AllowChange := true; - end; - - LastDecision := AllowChange; - end; - end; -end; - -procedure TMainForm.ListViewInfoTip(Sender: TObject; Item: TListItem; - var InfoTip: String); -var - Bitmap: TBitmap; - lcp: TControlPoint; -begin - // flame preview in a tooltip... - - BitMap := TBitMap.create; - Bitmap.PixelFormat := pf24bit; - BitMap.Width := 100; - BitMap.Height := 100; - - lcp := TControlPoint.Create; - lcp.Copy(mainCP); - lcp.cmap := mainCP.cmap; - - if Assigned(Renderer) then begin - Renderer.WaitFor; - Renderer.Free; - end; - if not Assigned(Renderer) then - begin - lcp.sample_density := 1; - lcp.spatial_oversample := 1; - lcp.spatial_filter_radius := 0.3; - lcp.AdjustScale(100, 100); - lcp.Transparency := false; - end; - try - Renderer := TRenderThread.Create; - assert(Renderer <> nil); - Renderer.BitsPerSample := 0 - Renderer.TargetHandle := self.Handle; - Renderer.SetCP(lcp); - Renderer.Priority := tpLower; - Renderer.NrThreads := 1 - Renderer.Resume; - Renderer.WaitFor; - except - end; - - lcp.Free; - Bitmap.Free; -end; -} - procedure TMainForm.btnViewIconsClick(Sender: TObject); -var thumbs: TThumbnailThread; begin ListView1.ViewStyle := vsIcon; btnViewList.Down := false; @@ -7498,12 +7097,7 @@ begin ClassicListMode := false; // AV: refresh flame images ONLY if they didn't exist - if not GeneratingThumbs then - begin - thumbs := TThumbnailThread.Create; - thumbs.Start; - GeneratingThumbs := True; - end; + if not GeneratingThumbs then RunThumbnailThread; // AV: scroll down to the selected flame preview if MainForm.ListView1.SelCount > 0 then @@ -7541,28 +7135,29 @@ begin end; procedure TMainForm.btNewClick(Sender: TObject); +var saved: boolean; begin StopThread; // AV if AlwaysCreateBlankFlame then - EditForm.tbResetAll.Click // AV - else + EditForm.mnuResetAllClick(Sender) // AV + else if TemplateForm.ShowModal = mrOK then // AV if AutoSaveXML then // AV: create a flame from scratch (rather than replace the current) if needed begin MainCp.name := MainCp.name + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); - if MainForm.SaveXMLFlame(MainCp, MainCp.name, OpenFile) then - if SortFlames.Checked then - ListXML(OpenFile, 2, MainCp.name) // show the new item - else - ListXML(OpenFile, 0); // show the last item + if (OpenFileType = ftXML) then + saved := SaveXMLFlame(MainCp, MainCp.name, OpenFile) + else + saved := SaveFlame(MainCp, MainCp.name, OpenFile); + if saved then AddFlameToList; // AV: show the new item end; end; -procedure TMainForm.FormResize(Sender: TObject); +procedure TMainForm.ToolBarResize(Sender: TObject); begin - if (MainForm.Width <= TbBreakWidth) then - Toolbar.Height := 26 * 2 + 8 + if (Toolbar.Width <= TbBreakWidth) then + Toolbar.Height := 60 // 26 * 2 + 8 else Toolbar.Height := 26; end; @@ -7618,157 +7213,94 @@ end; procedure TMainForm.AutoSaveTimerTimer(Sender: TObject); var - filename,title : string; - Tag: string; - IFile: TextFile; - FileList, FileListPre: TStringList; - i, p: integer; - erase : boolean; - bakname: string; + filename, title, bakname : string; + FileListPre: TStringList; begin - erase := false; filename := AutoSavePath; - title := CleanXMLName(maincp.name) + ' (' + FormatDateTime('MM-dd-yyyy hh:mm:ss', Now) + ')'; - Tag := RemoveExt(filename); + title := CleanXMLName(maincp.name) + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); if FileExists(filename) then begin FileListPre := TStringList.create; - try - FileListPre.LoadFromFile(filename); - if (FileListPre.Count > 1000) then erase := true; - finally - FileListPre.Free; - end; - - if (erase) then begin - bakname := ChangeFileExt(filename, '.bak'); - if FileExists(bakname) then DeleteFile(bakname); - RenameFile(filename, bakname); - end; - end; - - try - if FileExists(filename) then - begin - bakname := ChangeFileExt(filename, '.temp'); - if FileExists(bakname) then DeleteFile(bakname); - RenameFile(filename, bakname); - - FileList := TStringList.create; - try - FileList.LoadFromFile(bakname); - - if Pos(' 0 then + try + FileListPre.LoadFromFile(filename); + if (FileListPre.Count > 100000) then // increased nr of flames + // AV: if user working on auto-saved flame, we must NOT delete it + if (AutoSavePath <> OpenFile) then begin - i := 0; - while Pos('', FileList[i]); - FileList.Delete(i); - end; + bakname := ChangeFileExt(filename, '.tmp'); + if FileExists(bakname) then DeleteFile(bakname); + RenameFile(filename, bakname); end; - - // fix first line - if (FileList.Count > 0) then begin - FileList[0] := ''; - end; - - if FileList.Count > 2 then - begin - if pos(' 0 then - repeat - FileList.Delete(FileList.Count - 1); - until (Pos('', FileList[FileList.count - 1]) <> 0) - else - repeat - FileList.Delete(FileList.Count - 1); - until (Pos('<' + Tag + '>', FileList[FileList.count - 1]) <> 0) or - (Pos('', FileList[FileList.count - 1]) <> 0); - end else - begin - FileList.Delete(FileList.Count - 1); - end; - - FileList.Add(Trim(FlameToXMLAS(maincp, title, false))); - FileList.Add(''); - FileList.SaveToFile(filename); - - finally - if FileExists(bakname) and not FileExists(filename) then - RenameFile(bakname, filename); - - FileList.Free; - if FileExists(bakname) then DeleteFile(bakname); - end; - end - else - begin - // New file ... easy - AssignFile(IFile, filename); - ReWrite(IFile); - Writeln(IFile, ''); - Write(IFile, FlameToXMLAS(maincp, title, false)); - Writeln(IFile, ''); - CloseFile(IFile); + finally + FileListPre.Free; end; - except on EInOutError do // AV - raise Exception.CreateFmt(TextByKey('common-genericsavefailure'),[title]); end; + + if SaveXMLFlame(maincp, title, filename) then + // AV: added ListView updating + if (FileName = OpenFile) then AddFlameToList(title); + + bakname := ChangeFileExt(filename, '.bak'); + if FileExists(bakname) then DeleteFile(bakname); end; procedure TMainForm.Restorelastautosave1Click(Sender: TObject); -var fn:string; +var fn: string; begin - if (not fileexists(AutoSavePath)) then + if (not FileExists(AutoSavePath)) then raise Exception.Create(TextByKey('main-status-noautosave')); // AV - //ScriptEditor.Stopped := True; - MainMenuClick(nil); // AV - + // StopScripter; fn := AutoSavePath; - MainForm.CurrentFileName := fn; LastOpenFile := fn; - Maincp.name := ''; + Maincp.name := ''; // AV: ? ParamFolder := ExtractFilePath(fn); OpenFile := fn; - //MainForm.Caption := AppVersionString + ' - ' + OpenFile; // --Z-- - if APP_BUILD = '' then MainForm.Caption := AppVersionString + ' - ' + openFile - else MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + openFile; + + if APP_BUILD = '' then + MainForm.Caption := AppVersionString + ' - ' + openFile + else + MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + openFile; OpenFileType := ftXML; ListXML(fn, 1) end; procedure TMainForm.mnuHelpTopicsClick(Sender: TObject); -var - URL, HelpTopic: string; +// var URL, HelpTopic: string; begin - {if EditForm.Active then HelpTopic := 'Transform editor.htm' -// else if GradientForm.Active then HelpTopic := 'Gradient window.htm' + { + if EditForm.Active then HelpTopic := 'Transform editor.htm' else if AdjustForm.Active then HelpTopic := 'Adjust window.htm' else if MutateForm.Active then HelpTopic := 'Mutation window.htm' else if RenderForm.Active then HelpTopic := 'Render window.htm'; HtmlHelp(0, nil, HH_CLOSE_ALL, 0); - URL := AppPath + 'Apophysis 2.0.chm'; + URL := AppPath + Application.HelpFile; if HelpTopic <> '' then URL := URL + '::\' + HelpTopic; - HtmlHelp(0, PChar(URL), HH_DISPLAY_TOC, 0); } - //if (FileExists(HelpPath)) then - if (HelpPath <> '') then begin - if (not WinShellExecute('open', HelpPath)) then begin - MessageBox(self.Handle, PCHAR(Format(TextByKey('common-genericopenfailure'), [HelpPath])), - PCHAR('Apophysis AV'), MB_ICONHAND); - end; - end else MessageBox(self.Handle, PCHAR(TextByKey('main-status-nohelpfile')), - PCHAR('Apophysis AV'), MB_ICONHAND); + HtmlHelp(0, PChar(URL), HH_DISPLAY_TOC, 0); + } + + if (HelpPath <> '') then + begin + if not (FileExists(HelpPath)) then // AV + MessageBox(self.Handle, PCHAR(TextByKey('common-noparamfile')), + ApophysisSVN, MB_ICONHAND) + else + if (not WinShellExecute('open', HelpPath)) then begin + MessageBox(self.Handle, PCHAR(Format(TextByKey('common-genericopenfailure'), + [HelpPath])), ApophysisSVN, MB_ICONHAND); + end; + end else + MessageBox(self.Handle, PCHAR(TextByKey('main-status-nohelpfile')), + ApophysisSVN, 48); end; +{ function TMainForm.RetrieveXML(cp : TControlPoint):string; begin - Result := FlameToXML(cp, false, false); + // AV: commented out since we can call it directly + Result := FlameToXML(cp, false); end; +} procedure TMainForm.tbGuidesClick(Sender: TObject); begin @@ -7811,18 +7343,27 @@ procedure TMainForm.mnuTurnFlameToScriptClick(Sender: TObject); var txt: string; begin - txt := Trim(FlameToXML(Maincp, false, false)); + txt := Trim(FlameToXML(Maincp)); ScriptEditor.ScriptFromFlame(txt); ScriptEditor.Show; end; +procedure TMainForm.RunThumbnailThread; +var + thumbs: TThumbnailThread; +begin + thumbs := TThumbnailThread.Create; + thumbs.Start; // AV: Resume method is deprecated here + GeneratingThumbs := True; +end; + constructor TThumbnailThread.Create; begin inherited create(True); // AV: don't run the thread immediately - FCount := MainForm.ListView1.Items.Count - 1; FreeOnTerminate := true; // AV: fixed - someone forgot to free the memory Trace2('Creating ThumbnailThread #' + IntToStr(self.ThreadID)); + FlameItems := MainForm.ListView1.Items; // AV: keep the reference to flame list end; destructor TThumbnailThread.Destroy; @@ -7842,111 +7383,78 @@ var cp : TControlPoint; Thumbnail : TBitmap; flameXML, fCaption : string; - w, h, i : integer; + w, h: integer; r : double; - { - stored_thumb : TJPegImage; - stored_thumb_data : TBinArray; - stored_thumb_size : integer; - memstream : TMemoryStream; - } + Fitem: TListItem; + FlameProc: TProc; begin inherited; Renderer := TRenderer.Create; cp := TControlPoint.Create; Thumbnail := TBitmap.Create; + try // AV: added try-finally block // AV: moved outside the loop for speed + Thumbnail.SetSize(FThumbnailSize, FThumbnailSize); Thumbnail.PixelFormat := pf24bit; Thumbnail.HandleType := bmDIB; - Thumbnail.Width := FThumbnailSize; - Thumbnail.Height := FThumbnailSize; + + Thumbnail.Canvas.Lock; // AV: added thread-safe handling Thumbnail.Canvas.Brush.Color := WinColor; // AV: theme-aware GetSysColor(5); - for i := 0 to FCount do + if (OpenFileType = ftXML) then + FlameProc := procedure + begin + flameXML := LoadXMLFlameText(Openfile, fCaption); + MainForm.ParseXML(cp, flameXML, true); + end + else // added thumbs support for Undo (*.apo) flames + FlameProc := procedure + begin + FlameFromUndo(cp, fCaption, OpenFile); + end; + + for Fitem in FlameItems do // hope this is more safety loop begin cp.Clear; - fCaption := MainForm.ListView1.Items[i].Caption; - flameXML := LoadXMLFlameText(Openfile, fCaption); - MainForm.ParseXML(cp, PCHAR(flameXML), true); - { - // AV: great idea, but somehow it doesn't work and causes crashes :( - if (cp.xdata <> '') then + fCaption := Fitem.Caption; + + FlameProc; // AV + + r := cp.Width / cp.Height; + w := ThumbnailSize; + h := w; + if (r < 1) then w := round(r * w) + else if (r > 1) then h := round(h / r); + cp.AdjustScale(w, h); + + cp.spatial_oversample := defOversample; + cp.spatial_filter_radius := defFilterRadius; + cp.sample_density := FPreviewDensity; // AV + + Renderer.SetCP(cp); + Renderer.Render; + + Thumbnail.Canvas.FillRect(Rect(0, 0, FThumbnailSize, FThumbnailSize)); + Thumbnail.Canvas.Draw((ThumbnailSize - w) shr 1, + (ThumbnailSize - h) shr 1, Renderer.GetImage); + + // AV: added thread synchronization for updating visual components + Synchronize( + procedure begin - stored_thumb := TJPegImage.Create; - B64Decode(cp.xdata, stored_thumb_data, stored_thumb_size); - memstream := TMemoryStream.Create; - memstream.Size := stored_thumb_size; - stored_thumb_size := Length(stored_thumb_data); - memstream.WriteBuffer(stored_thumb_data[0], stored_thumb_size); - memstream.Seek(0, soBeginning); - //-X- test thumbnail integrity... memstream.SaveToFile('C:\Test.jpg'); - stored_thumb.LoadFromStream(memstream); - memstream.Free; - - w := stored_thumb.Width; - h := stored_thumb.Height; - - Thumbnail.Canvas.FillRect(Rect(0, 0, FThumbnailSize, FThumbnailSize)); - Thumbnail.Canvas.Draw(round(FThumbnailSize / 2 - w / 2), - round(FThumbnailSize / 2 - h / 2), stored_thumb); - - // AV: added thread synchronization for visual components - Synchronize( - procedure - begin - Trace2('Generating thumbnail for "' + fCaption + '"'); - MainForm.UsedThumbnails.Add(Thumbnail, nil); - MainForm.ListView1.Items[i].ImageIndex := MainForm.UsedThumbnails.Count - 1; - end); - - stored_thumb.Free; - end else } - begin - w := cp.Width; - h := cp.Height; - r := w / h; - if (w < h) then - begin - w := round(r * FThumbnailSize); - h := FThumbnailSize; - end else if (w > h) then - begin - h := round(FThumbnailSize / r); - w := FThumbnailSize; - end else - begin - w := FThumbnailSize; - h := FThumbnailSize; - end; - cp.AdjustScale(w, h); - cp.spatial_oversample := defOversample; - cp.spatial_filter_radius := defFilterRadius; - cp.sample_density := FPreviewDensity; // AV - - Renderer.SetCP(cp); - Renderer.Render; - - Thumbnail.Canvas.FillRect(Rect(0, 0, FThumbnailSize, FThumbnailSize)); - Thumbnail.Canvas.Draw(round(FThumbnailSize / 2 - w / 2), - round(FThumbnailSize / 2 - h / 2), Renderer.GetImage); - - // AV: added thread synchronization for updating visual components - Synchronize( - procedure - begin - MainForm.UsedThumbnails.Add(Thumbnail, nil); - MainForm.ListView1.Items[i].ImageIndex := MainForm.UsedThumbnails.Count - 1; - Trace2('Generating thumbnail for "' + fCaption + '"'); - end); - end; + MainForm.UsedThumbnails.Add(Thumbnail, nil); + Fitem.ImageIndex := MainForm.UsedThumbnails.Count - 1; + Trace2('Generating thumbnail for "' + fCaption + '"'); + end); if Terminated then break; // AV end; finally + Thumbnail.Canvas.UnLock; // AV: added thread-safe handling + Thumbnail.Free; + Thumbnail := nil; cp.Free; Renderer.Free; - Thumbnail.Free; - Thumbnail := nil; end; end; @@ -7955,7 +7463,6 @@ var FStrings : TStringList; i, p : integer; title : string; - thread : TThumbnailThread; item : TListItem; begin MainForm.ParseLoadingBatch := true; @@ -7980,7 +7487,7 @@ begin p := Pos(' 0) then begin - MainForm.ListXMLScanner.LoadFromBuffer(TCharType(TStringType(FStrings[i]))); + MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FStrings[i]))); MainForm.ListXMLScanner.Execute; if Trim(pname) = '' then @@ -7995,6 +7502,8 @@ begin item := MainForm.ListView1.Items.Add; item.Caption := Title; item.ImageIndex := 0; // AV: now we can load a hourglass icon + // AV: hack - remember the creation order in an unused field + item.OverlayIndex := MainForm.ListView1.Items.Count; end; end; end; @@ -8002,13 +7511,10 @@ begin MainForm.LoadSaveProgress.Position := 0; //MainForm.ListView1.AllocBy := MainForm.ListView1.Items.Count; - if ClassicListMode then // AV: thumbs are useless + if ClassicListMode then // AV: thumbs are useless GeneratingThumbs := False - else begin - thread := TThumbnailThread.Create; - thread.Start; // AV: thread.Resume method is deprecated here - GeneratingThumbs := True; - end; + else + MainForm.RunThumbnailThread; // AV: wrap it into a separate method finally MainForm.ListView1.Items.EndUpdate; @@ -8025,8 +7531,63 @@ begin if MainForm.EnumerateFlames.Checked then // AV: displaying indices MainForm.EnumerateFlamesClick(MainForm.EnumerateFlames); + end; MainForm.ParseLoadingBatch := false; + + if AnimateForm.Visible then AnimateForm.UpdateControls; // AV +end; + +// AV: the fast way to refresh ListView +procedure TMainForm.AddFlameToList(const title: string = ''); +var + item: TListItem; + i: integer; + fname: string; +begin + if title = '' then fname := MainCp.name + else fname := title; + + ListView1.Items.BeginUpdate; + try + // first check for duplicates + item := ListView1.FindCaption(max(ListView1.ItemIndex, 0), fname, + false, true, true); + if item <> nil then + ListView1.Items.Delete(item.Index); + + // AV: temporary prevent all preview updates + ListView1.OnChange := nil; + ListView1.OnSelectItem := nil; + + item := ListView1.Items.Add; + item.Caption := fname; + ListView1.Selected := ListView1.Items[item.Index]; + UsedThumbnails.Add(ThumbnailPlaceholder, nil); // add dummy hourglass icon + item.ImageIndex := UsedThumbnails.Count - 1; + + item.OverlayIndex := ListView1.Items.Count; // remember the creation order + // if some flames were deleted from the list, max index is greater than the last one + for i := 0 to ListView1.Items.Count - 1 do + if ListView1.Items[i].OverlayIndex > item.OverlayIndex then + item.OverlayIndex := ListView1.Items[i].OverlayIndex + 1; + + ListView1.Selected := ListView1.Items[item.Index]; + ListView1.ItemFocused := ListView1.Selected; + if GeneratingThumbs then RefreshThumbnail; + finally + // AV: restore the default event handlers + ListView1.OnChange := ListViewChange; + if ConfirmResetUndo then + ListView1.OnSelectItem := ListViewSelectItem; + ListView1.Items.EndUpdate; + end; + // refreshing flame indices + if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames); + // scroll to the new item + if ListView1.Selected <> nil then ListView1.Selected.MakeVisible(true); + + if AnimateForm.Visible then AnimateForm.UpdateControls; end; procedure TMainForm.RefreshThumbnail; @@ -8037,28 +7598,18 @@ var i, w, h, w_old, h_old: integer; begin if not Assigned(ListView1.Selected) then exit; - i := ListView1.Selected.Index; - if (i > UsedThumbnails.Count) then exit; + i := ListView1.Selected.ImageIndex; + if (i >= UsedThumbnails.Count) then exit; - w := Maincp.Width; - h := Maincp.Height; - w_old := w; - h_old := h; + w_old := Maincp.Width; + h_old := Maincp.Height; - r := w / h; - if (w < h) then - begin - w := round(r * ThumbnailSize); - h := ThumbnailSize; - end else if (w > h) then - begin - h := round(ThumbnailSize / r); - w := ThumbnailSize; - end else - begin - w := ThumbnailSize; - h := ThumbnailSize; - end; + r := w_old / h_old; + w := ThumbnailSize; + h := w; + if (r < 1) then w := round(r * w) + else if (r > 1) then h := round(h / r); + sd := Maincp.sample_density; Maincp.AdjustScale(w, h); Maincp.spatial_oversample := defOversample; @@ -8073,15 +7624,15 @@ begin Thumbnail.PixelFormat := pf24bit; Thumbnail.HandleType := bmDIB; - Thumbnail.Width := ThumbnailSize; - Thumbnail.Height := ThumbnailSize; + Thumbnail.SetSize(ThumbnailSize, ThumbnailSize); Thumbnail.Canvas.Brush.Color := WinColor; // theme-aware system color Thumbnail.Canvas.FillRect(Rect(0, 0, ThumbnailSize, ThumbnailSize)); - Thumbnail.Canvas.Draw(round(ThumbnailSize / 2 - w / 2), - round(ThumbnailSize / 2 - h / 2), Renderer.GetImage); + Thumbnail.Canvas.Draw((ThumbnailSize - w) shr 1, + (ThumbnailSize - h) shr 1, Renderer.GetImage); try - UsedThumbnails.Replace(i + 1, Thumbnail, nil); + UsedThumbnails.Replace(i, Thumbnail, nil); + i := ListView1.Selected.Index; ListView1.Items.Item[i].Update; Trace2('Updating thumbnail for "' + ListView1.Items[i].Caption + '"'); except @@ -8100,7 +7651,6 @@ end; procedure TMainForm.UpdateThumbnails; // AV: refreshes images only var i: integer; - thumbs: TThumbnailThread; begin UsedThumbnails.Clear; UsedThumbnails.Add(ThumbnailPlaceholder, nil); @@ -8112,9 +7662,7 @@ begin EndUpdate; end; - thumbs := TThumbnailThread.Create; - thumbs.Start; - GeneratingThumbs := True; + RunThumbnailThread; // hightlight the item if possible ListView1.Selected := ListView1.ItemFocused; @@ -8150,9 +7698,9 @@ begin LoadForm.Output.Text := LoadForm.Output.Text + #13#10 + str + ' ' + TextByKey('main-report-noplugins') + #13#10; exit; end; - for i := 0 to MainCP.used_plugins.Count-1 do begin + for i := 0 to MainCP.used_plugins.Count-1 do str := str + #13#10 + ' - ' + MainCP.used_plugins[i]; - end; + // AV: added 3D and DC status str := str + #13#10 + TextByKey('main-report-directcoloring') + #32 + IfThen((pos('dc', str) > 0) or (pos('falloff', str) > 0) or (pos('affine3D', str) > 0), @@ -8161,13 +7709,17 @@ begin IfThen((MainCP.cameraPitch <> 0) or (MainCP.cameraRoll <> 0) or (pos('_rotate_', str) > 0), TextByKey('common-yes'), TextByKey('common-no')); + if MainCp.Comment <> '' then + str := str + #13#10 + TextByKey('common-comment') + ': '#13#10'"' + + MainCp.Comment + '"'; + LoadForm.Output.Text := LoadForm.Output.Text + #13#10 + str + #13#10; end; procedure TMainForm.mnuExportChaoticaClick(Sender: TObject); begin MainCP.FillUsedPlugins; - C_ExecuteChaotica(FlameToXml(MainCp, false, false), MainCp.used_plugins, UseX64IfPossible); + C_ExecuteChaotica(FlameToXml(MainCp), MainCp.used_plugins, UseX64IfPossible); end; procedure TMainForm.mnuManualClick(Sender: TObject); // AV: Apo7X link is dead... @@ -8282,19 +7834,20 @@ begin end; function TMainForm.ReadWithSubst(Attributes: TAttrList; attrname: string): string; -var i: integer; v: TStringType; +var i: integer; + v: string; //TStringType; begin - v := Attributes.Value(TStringType(attrname)); + v := string(Attributes.Value(Utf8String(attrname))); if (v <> '') then begin - Result := String(v); + Result := v; Exit; end; for i := 0 to SubstTarget.Count - 1 do begin if (SubstTarget[i] = attrname) then begin - v := Attributes.Value(TStringType(SubstSource[i])); + v := string(Attributes.Value(Utf8String(SubstSource[i]))); if (v <> '') then begin - Result := String(v); + Result := v; Exit; end; end; diff --git a/Forms/Mutate.dfm b/Forms/Mutate.dfm index 1f801f4..47b6b68 100644 --- a/Forms/Mutate.dfm +++ b/Forms/Mutate.dfm @@ -5,7 +5,7 @@ object MutateForm: TMutateForm BorderStyle = bsSingle Caption = 'Mutation' ClientHeight = 398 - ClientWidth = 422 + ClientWidth = 414 Color = clBtnFace Constraints.MinHeight = 400 Constraints.MinWidth = 400 @@ -21,51 +21,28 @@ object MutateForm: TMutateForm OnDestroy = FormDestroy OnShow = FormShow DesignSize = ( - 422 + 414 398) PixelsPerInch = 96 TextHeight = 13 - object GroupBox1: TGroupBox - Left = 8 + object gbDirections: TGroupBox + Left = 24 Top = 8 - Width = 409 + Width = 360 Height = 273 - Anchors = [akLeft, akTop, akRight, akBottom] Caption = 'Directions' TabOrder = 0 DesignSize = ( - 409 + 360 273) - object Panel10: TPanel + object pnlDirections: TPanel Left = 12 Top = 20 - Width = 384 + Width = 335 Height = 238 Anchors = [akLeft, akTop, akRight, akBottom] BevelOuter = bvNone TabOrder = 0 - object Panel6: TPanel - Left = 112 - Top = 168 - Width = 108 - Height = 80 - BevelOuter = bvLowered - Caption = 'PrevPnl3' - Color = clBlack - ShowCaption = False - TabOrder = 0 - object Image6: TImage - Tag = 6 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end - end object Panel7: TPanel Left = 0 Top = 168 @@ -75,18 +52,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 1 - object Image7: TImage - Tag = 7 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 0 end object Panel4: TPanel Left = 224 @@ -97,18 +63,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 2 - object Image4: TImage - Tag = 4 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 1 end object Panel0: TPanel Left = 112 @@ -120,7 +75,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 3 + TabOrder = 2 object Image0: TImage Left = 1 Top = 1 @@ -130,6 +85,8 @@ object MutateForm: TMutateForm PopupMenu = QualityPopup Stretch = True OnClick = Image0Click + ExplicitLeft = 2 + ExplicitTop = 0 end end object Panel8: TPanel @@ -141,18 +98,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 4 - object Image8: TImage - Tag = 8 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 3 end object Panel3: TPanel Left = 224 @@ -163,18 +109,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 5 - object Image3: TImage - Tag = 3 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 4 end object Panel2: TPanel Left = 112 @@ -185,18 +120,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 6 - object Image2: TImage - Tag = 2 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 5 end object Panel1: TPanel Left = 0 @@ -207,18 +131,7 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False - TabOrder = 7 - object Image1: TImage - Tag = 1 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end + TabOrder = 6 end object Panel5: TPanel Left = 224 @@ -229,37 +142,36 @@ object MutateForm: TMutateForm Caption = 'PrevPnl3' Color = clBlack ShowCaption = False + TabOrder = 7 + end + object Panel6: TPanel + Left = 112 + Top = 168 + Width = 108 + Height = 80 + BevelOuter = bvLowered + Caption = 'PrevPnl3' + Color = clBlack + ShowCaption = False TabOrder = 8 - object Image5: TImage - Tag = 5 - Left = 1 - Top = 1 - Width = 106 - Height = 78 - Align = alClient - PopupMenu = QualityPopup - Stretch = True - OnClick = MutantClick - end end end end object GroupBox2: TGroupBox Left = 8 Top = 288 - Width = 409 + Width = 393 Height = 105 - Anchors = [akLeft, akRight, akBottom] + Anchors = [akLeft, akBottom] TabOrder = 1 DesignSize = ( - 409 + 393 105) object scrollTime: TScrollBar - Left = 120 + Left = 114 Top = 20 Width = 202 Height = 20 - Anchors = [akLeft, akTop, akRight] LargeChange = 5 Max = 50 Min = 1 @@ -269,23 +181,23 @@ object MutateForm: TMutateForm OnChange = scrollTimeChange end object cmbTrend: TComboBox - Left = 119 + Left = 114 Top = 48 - Width = 282 + Width = 262 Height = 21 Style = csDropDownList - Anchors = [akLeft, akTop, akRight] DropDownCount = 16 + Sorted = True TabOrder = 1 OnChange = cmbTrendChange Items.Strings = ( - 'Random' - 'Linear') + 'Linear' + 'Random') end object chkSameNum: TCheckBox Left = 12 Top = 78 - Width = 389 + Width = 373 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Same no. of transforms' @@ -305,11 +217,10 @@ object MutateForm: TMutateForm TabOrder = 3 end object txtTime: TEdit - Left = 328 + Left = 318 Top = 20 - Width = 73 + Width = 60 Height = 21 - Anchors = [akTop, akRight] ReadOnly = True TabOrder = 4 Text = '0.25' @@ -331,8 +242,8 @@ object MutateForm: TMutateForm Enabled = False Interval = 100 OnTimer = TimerTimer - Left = 168 - Top = 80 + Left = 184 + Top = 136 end object QualityPopup: TPopupMenu Images = MainForm.Buttons diff --git a/Forms/Mutate.pas b/Forms/Mutate.pas index 69faaac..f0bca3a 100644 --- a/Forms/Mutate.pas +++ b/Forms/Mutate.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -28,11 +28,11 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ControlPoint, ComCtrls, Menus, Buttons, Cmap, - RenderingInterface, Translation, Curves; + RenderingInterface; type TMutateForm = class(TForm) - GroupBox1: TGroupBox; + gbDirections: TGroupBox; Timer: TTimer; GroupBox2: TGroupBox; scrollTime: TScrollBar; @@ -48,29 +48,20 @@ type N1: TMenuItem; mnuMaintainSym: TMenuItem; N2: TMenuItem; - Panel10: TPanel; - Panel6: TPanel; - Image6: TImage; + pnlDirections: TPanel; Panel7: TPanel; - Image7: TImage; Panel4: TPanel; - Image4: TImage; Panel0: TPanel; Image0: TImage; Panel8: TPanel; - Image8: TImage; Panel3: TPanel; - Image3: TImage; Panel2: TPanel; - Image2: TImage; Panel1: TPanel; - Image1: TImage; Panel5: TPanel; - Image5: TImage; pnlSpeed: TPanel; txtTime: TEdit; pnlTrend: TPanel; - //procedure Panel10Resize(Sender: TObject); + Panel6: TPanel; procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); @@ -80,7 +71,6 @@ type procedure TimerTimer(Sender: TObject); procedure scrollTimeChange(Sender: TObject); procedure cmbTrendChange(Sender: TObject); - procedure btnCancelClick(Sender: TObject); procedure mnuHighQualityClick(Sender: TObject); procedure mnuLowQualityClick(Sender: TObject); procedure mnuMediumQualityClick(Sender: TObject); @@ -91,11 +81,11 @@ type procedure mnuMaintainSymClick(Sender: TObject); private name: string; - bm: TBitmap; PreviewDensity: double; Updating: boolean; cps: array[0..8] of TControlPoint; Mutants: array[0..8] of TControlPoint; + MImages: array[1..8] of TImage; // AV Render: TRenderer; Time: double; bstop: boolean; @@ -106,6 +96,8 @@ type procedure ShowMain; procedure ShowMutants; procedure Interpolate; + procedure RandomCP(var cp: TControlPoint; const minT, maxT: integer); // AV: removed from ControlPoint + procedure SetVariation(var cp: TControlPoint); // AV: wrote a local method public Zoom: Double; Center: array[0..1] of double; @@ -120,7 +112,7 @@ var implementation uses - Main, Global, Registry, Editor, Adjust, XFormMan; + Main, Global, Registry, Editor, XFormMan, Adjust, Translation; {$R *.DFM} @@ -135,13 +127,12 @@ begin MainCp.AdjustScale(width, height); // AV: restore normal size if mnuResetLocation.checked then begin - //MainForm.Mainzoom := cps[0].zoom; MainForm.Center[0] := cps[0].Center[0]; MainForm.Center[1] := cps[0].Center[1]; end; MainForm.RedrawTimer.enabled := true; if EditForm.Visible then EditForm.UpdateDisplay; -// if AdjustForm.Visible then AdjustForm.UpdateDisplay; + if AdjustForm.Visible then AdjustForm.UpdateDisplay; end; procedure TMutateForm.UpdateDisplay; @@ -167,6 +158,26 @@ begin ShowMutants; end; +procedure TMutateForm.SetVariation(var cp: TControlPoint); +var + i, k, n: integer; +begin + if cmbTrend.ItemIndex = NRVAR then // AV: set random variations from selected + repeat + n := random(NrVar); + until Variations[n] + else // AV: sorted list is used from now + n := GetVariationIndex(cmbTrend.Items[cmbTrend.ItemIndex]); + + for i := 0 to cp.NumXforms-1 do + begin + for k := 0 to NrVar-1 do // AV: simplified the calculations + cp.xform[i].SetVariation(k, 0); + cp.xform[i].SetVariation(n, 1); + end; + +end; + procedure TMutateForm.ShowMain; begin cps[0].Width := Image0.Width; @@ -194,20 +205,21 @@ begin Render.SetCP(cps[0]); Render.Render; - BM.Assign(Render.GetImage); - Image0.Picture.Graphic := bm; + Image0.Picture.Graphic := Render.GetImage; end; procedure TMutateForm.ShowMutants; var - i: integer; + i: byte; + //t: cardinal; begin if Visible = false then exit; Updating := true; + //t := GetTickCount; for i := 1 to 8 do begin - mutants[i].Width := Image1.Width; - mutants[i].Height := Image1.Height; + mutants[i].Width := Image0.Width; + mutants[i].Height := Image0.Height; mutants[i].spatial_filter_radius := defFilterRadius; mutants[i].spatial_oversample := defOversample; mutants[i].sample_density := PreviewDensity; @@ -230,51 +242,22 @@ begin Render.SetCP(mutants[i]); Render.Render; - BM.Assign(Render.GetImage); - case i of - 1: begin - Image1.Picture.Graphic := bm; - Image1.Refresh; - end; - 2: begin - Image2.Picture.Graphic := bm; - Image2.Refresh; - end; - 3: begin - Image3.Picture.Graphic := bm; - Image3.Refresh; - end; - 4: begin - Image4.Picture.Graphic := bm; - Image4.Refresh; - end; - 5: begin - Image5.Picture.Graphic := bm; - Image5.Refresh; - end; - 6: begin - Image6.Picture.Graphic := bm; - Image6.Refresh; - end; - 7: begin - Image7.Picture.Graphic := bm; - Image7.Refresh; - end; - 8: begin - Image8.Picture.Graphic := bm; - Image8.Refresh; - end; - end; + // AV: replaced separate TImages by an array + MImages[i].Picture.Graphic := Render.GetImage; + MImages[i].Refresh; + Updating := false; end; + //ShowMessage((GetTickCount - t).ToString); end; procedure TMutateForm.Interpolate; -var i, j, k: Integer; +var i, j: Integer; begin if MainCp = nil then Exit; - + + //cps[0].Time := 0; for i := 1 to 8 do begin if bstop then exit; @@ -283,45 +266,53 @@ begin (* -X- something is not right here... Mutants[i] may be destroyed already Investigate? *) - Mutants[i].clear; + // AV: it's OK... Mutants are just placeholders for a new flame + Mutants[i].Clear; Mutants[i].InterpolateX(cps[0], cps[i], Time / 100); - Mutants[i].cmapindex := cps[0].cmapindex; - Mutants[i].cmap := cps[0].cmap; Mutants[i].background := MainCp.background; if mnuMaintainSym.Checked then // maintain symmetry for j := 0 to transforms - 1 do if cps[0].xform[j].Symmetry = 1 then mutants[i].xform[j].Assign(cps[0].xform[j]); end; + +end; + +procedure TMutateForm.RandomCP(var cp: TControlPoint; const minT, maxT: integer); // AV +var + nrXforms, i: integer; +begin + nrXforms := random(MaxT - MinT + 1) + MinT; + + for i := 0 to nrXforms - 1 do begin + cp.xform[i].density := 1.0 / nrXforms; + cp.xform[i].color := i / (nrXforms - 1); + cp.xform[i].RandomizeCoefs(cp.xform[i].c); + end; + + SetVariation(cp); //AV end; procedure TMutateForm.RandomSet; -var i, j, k: Integer; +var i: byte; begin RandSeed := seed; for i := 1 to 8 do begin cps[i].clear; + if chkSameNum.checked then - cps[i].RandomCP(transforms, transforms, false) + RandomCP(cps[i], transforms, transforms) else - cps[i].RandomCP(mutantMinTransforms, mutantMaxTransforms, false); - - if cmbTrend.ItemIndex = NRVAR then // AV - cps[i].SetVariation(vRandom) - else - for j := 0 to cps[i].NumXforms-1 do - begin - for k := 0 to NrVar-1 do // AV: simplified the calculations - cps[i].xform[j].SetVariation(k, 0); - cps[i].xform[j].SetVariation(cmbTrend.ItemIndex, 1); - end; + RandomCP(cps[i], mutantMinTransforms, mutantMaxTransforms); + { // AV: now it's done inside InterpolateX method if cps[0].HasFinalXForm = false then begin cps[i].xform[cps[i].NumXForms].Clear; cps[i].xform[cps[i].NumXForms].symmetry := 1; end; + } end; Interpolate; end; @@ -361,7 +352,7 @@ var i: integer; begin self.Caption := TextByKey('mutation-title'); - GroupBox1.Caption := TextByKey('mutation-directions'); + gbDirections.Caption := TextByKey('mutation-directions'); pnlSpeed.Caption := TextByKey('mutation-speed'); pnlTrend.Caption := TextByKey('mutation-trend'); chkSameNum.Caption := TextByKey('mutation-keepnumberoftransforms'); @@ -375,10 +366,9 @@ begin for i:= 0 to NRVAR -1 do // AV cmbTrend.Items.Add(varnames(i)); + cmbTrend.Sorted := False; // AV: 'random' item must be last cmbTrend.Items.Add(TextByKey('mutation-randomtrend')); - bm := TBitMap.Create; - case MutatePrevQual of 0: begin mnuLowQuality.Checked := true; @@ -401,7 +391,17 @@ begin Mutants[i] := TControlPoint.Create; end; - Time := 35; + for i := 1 to 8 do // AV: added array for speed + begin + MImages[i] := TImage.Create(self); + MImages[i].Parent := TPanel(self.FindComponent('Panel' + IntToStr(i))); + MImages[i].Align := alClient; + MImages[i].Tag := i; + MImages[i].OnClick := MutantClick; + MImages[i].PopupMenu := QualityPopup; + end; + + Time := 25; // 35; scrollTime.Position := 25; txtTime.Text := '0.25'; // AV cmbTrend.ItemIndex := NRVAR; // AV @@ -421,7 +421,6 @@ begin cps[i].Free; Mutants[i].Free; end; - bm.free; end; procedure TMutateForm.Image0Click(Sender: TObject); @@ -439,30 +438,32 @@ var cpt: TControlPoint; begin cpt := TControlPoint.Create; - cpt.Copy(cps[0], false, transforms); // AV bstop := true; - // AV: optimized fast version without checking indices + // AV: optimized faster version without checking indices i := TImage(Sender).Tag; cps[0].Time := 0; cps[i].Time := 1; - cps[0].InterpolateX(cps[0], cps[i], Time / 100); + cpt.InterpolateX(cps[0], cps[i], Time / 100); if mnuMaintainSym.Checked then // maintain symmetry begin for i := 0 to transforms - 1 do begin - if cpt.xform[i].Symmetry = 1 then - cps[0].xform[i].Assign(cpt.xform[i]); + if cps[0].xform[i].Symmetry = 1 then + cpt.xform[i].Assign(cps[0].xform[i]); end; end; + // AV: it's faster to make a copy by reference that use TControlPoint.Copy() + cps[0].Free; // AV + cps[0] := cpt; // AV + bstop := false; ShowMain; Interpolate; ShowMutants; UpdateFlame; - cpt.free; end; procedure TMutateForm.sbTimeChange(Sender: TObject); @@ -494,28 +495,15 @@ end; procedure TMutateForm.cmbTrendChange(Sender: TObject); var - i, j, k: integer; + i: byte; begin for i := 1 to 8 do - if cmbTrend.ItemIndex = NRVAR then - cps[i].SetVariation(VRandom) // AV - else - for j := 0 to cps[i].NumXforms-1 do - begin // AV - for k := 0 to NrVar-1 do - cps[i].xform[j].SetVariation(k, 0); - cps[i].xform[j].SetVariation(cmbTrend.ItemIndex, 1); - end; + SetVariation(cps[i]); //AV Interpolate; ShowMutants; end; -procedure TMutateForm.btnCancelClick(Sender: TObject); -begin - ModalResult := mrCancel; -end; - procedure TMutateForm.mnuHighQualityClick(Sender: TObject); begin mnuHighQuality.Checked := True; @@ -605,30 +593,6 @@ begin ShowMutants; end; -(* - procedure TMutateForm.Panel10Resize(Sender: TObject); - const gap:integer = 4 ; - var - w, h : integer; - begin - w := (Panel10.Width - 2*gap) div 3; - h := (Panel10.Height - 2*gap) div 3; - - Panel0.Width := w; Panel1.Width := w; Panel2.Width := w; - Panel3.Width := w; Panel4.Width := w; Panel5.Width := w; - Panel6.Width := w; Panel7.Width := w; Panel8.Width := w; - Panel0.Height := h; Panel1.Height := h; Panel2.Height := h; - Panel3.Height := h; Panel4.Height := h; Panel5.Height := h; - Panel6.Height := h; Panel7.Height := h; Panel8.Height := h; - - Panel2.Left := w + gap; Panel0.Left := w + gap; Panel6.Left := w + gap; - Panel3.Left := 2*(w + gap); Panel4.Left := 2*(w + gap); Panel5.Left := 2*(w + gap); - - Panel8.Top := h + gap; Panel0.Top := h + gap; Panel4.Top := h + gap; - Panel7.Top := 2*(h + gap); Panel6.Top := 2*(h + gap); Panel5.Top := 2*(h + gap); - end; - -*) end. diff --git a/Forms/Options.dfm b/Forms/Options.dfm index 00884a8..a3fc4da 100644 --- a/Forms/Options.dfm +++ b/Forms/Options.dfm @@ -1,11 +1,11 @@ object OptionsForm: TOptionsForm Left = 899 Top = 428 - BorderIcons = [biSystemMenu, biMinimize, biMaximize, biHelp] + BorderIcons = [biSystemMenu, biMinimize] BorderStyle = bsSingle Caption = 'Options' - ClientHeight = 498 - ClientWidth = 524 + ClientHeight = 505 + ClientWidth = 568 Color = clBtnFace Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -56,15 +56,36 @@ object OptionsForm: TOptionsForm OnCreate = FormCreate OnShow = FormShow DesignSize = ( - 524 - 498) + 568 + 505) PixelsPerInch = 96 TextHeight = 13 + object btnOK: TButton + Left = 374 + Top = 477 + Width = 86 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'OK' + Default = True + TabOrder = 0 + OnClick = btnOKClick + end + object btnCancel: TButton + Left = 466 + Top = 477 + Width = 86 + Height = 25 + Anchors = [akRight, akBottom] + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 1 + end object Tabs: TPageControl Left = 8 Top = 8 - Width = 512 - Height = 456 + Width = 556 + Height = 463 ActivePage = PathsPage Anchors = [akLeft, akTop, akRight, akBottom] MultiLine = True @@ -73,15 +94,11 @@ object OptionsForm: TOptionsForm object GeneralPage: TTabSheet HelpContext = 1 Caption = 'General' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) - object SpeedButton1: TSpeedButton - Left = 474 + 548 + 435) + object btnLanguage: TSpeedButton + Left = 518 Top = 7 Width = 24 Height = 24 @@ -123,7 +140,7 @@ object OptionsForm: TOptionsForm ParentFont = False ParentShowHint = False ShowHint = True - OnClick = SpeedButton1Click + OnClick = btnLanguageClick ExplicitLeft = 437 end object pnlJPEGQuality: TPanel @@ -136,77 +153,8 @@ object OptionsForm: TOptionsForm Caption = 'JPEG Quality' ParentShowHint = False ShowHint = True - TabOrder = 9 - end - object chkConfirmDel: TCheckBox - Left = 236 - Top = 115 - Width = 258 - Height = 17 - HelpContext = 1005 - Anchors = [akLeft, akTop, akRight] - Caption = 'Confirm delete' - TabOrder = 0 - end - object chkOldPaletteFormat: TCheckBox - Left = 236 - Top = 75 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Save gradient in old file format' - TabOrder = 1 - WordWrap = True - end - object chkConfirmExit: TCheckBox - Left = 236 - Top = 135 - Width = 258 - Height = 17 - HelpContext = 1005 - Anchors = [akLeft, akTop, akRight] - Caption = 'Confirm exit' - TabOrder = 18 - end - object chkConfirmStopRender: TCheckBox - Left = 236 - Top = 155 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Confirm stop render' TabOrder = 3 end - object cbUseTemplate: TCheckBox - Left = 236 - Top = 35 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Always create blank flame' - TabOrder = 4 - end - object cbMissingPlugin: TCheckBox - Left = 236 - Top = 55 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Warn when plugins are missing' - TabOrder = 5 - WordWrap = True - end - object cbEmbedThumbs: TCheckBox - Left = 236 - Top = 255 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable thumbnail embedding' - TabOrder = 6 - Visible = False - WordWrap = True - end object pnlMultithreading: TPanel Left = 8 Top = 92 @@ -217,7 +165,7 @@ object OptionsForm: TOptionsForm Caption = 'Multithreading' ParentShowHint = False ShowHint = True - TabOrder = 7 + TabOrder = 1 end object cbNrTheads: TComboBox Left = 112 @@ -226,7 +174,7 @@ object OptionsForm: TOptionsForm Height = 21 Style = csDropDownList ItemIndex = 0 - TabOrder = 8 + TabOrder = 2 Text = 'Off' Items.Strings = ( 'Off') @@ -241,7 +189,7 @@ object OptionsForm: TOptionsForm Caption = 'PNG Transparency' ParentShowHint = False ShowHint = True - TabOrder = 11 + TabOrder = 5 end object grpGuidelines: TGroupBox Left = 8 @@ -255,7 +203,7 @@ object OptionsForm: TOptionsForm Font.Name = 'Tahoma' Font.Style = [fsBold] ParentFont = False - TabOrder = 13 + TabOrder = 7 object cbGL: TCheckBox Left = 8 Top = 23 @@ -399,16 +347,16 @@ object OptionsForm: TOptionsForm Caption = 'Language file' ParentShowHint = False ShowHint = True - TabOrder = 14 + TabOrder = 8 end object txtLanguageFile: TComboBox Left = 112 Top = 8 - Width = 360 + Width = 404 Height = 21 Style = csDropDownList Anchors = [akLeft, akTop, akRight] - TabOrder = 15 + TabOrder = 9 end object cbPNGTransparency: TComboBox Left = 112 @@ -417,7 +365,7 @@ object OptionsForm: TOptionsForm Height = 21 Style = csDropDownList ItemIndex = 0 - TabOrder = 12 + TabOrder = 6 Text = 'Disabled' Items.Strings = ( 'Disabled' @@ -428,7 +376,7 @@ object OptionsForm: TOptionsForm Top = 36 Width = 113 Height = 21 - TabOrder = 10 + TabOrder = 4 Text = '100' OnKeyPress = NumFieldKeyPress Items.Strings = ( @@ -436,30 +384,11 @@ object OptionsForm: TOptionsForm '80' '100') end - object chkEngLayout: TCheckBox - Left = 236 - Top = 195 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Set English keyboard layout' - TabOrder = 16 - end - object chkConfirmClearScript: TCheckBox - Left = 236 - Top = 175 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Confirm clear script' - TabOrder = 17 - end object GroupBox15: TGroupBox - Left = 6 - Top = 290 - Width = 354 + Left = 240 + Top = 296 + Width = 297 Height = 120 - Anchors = [akLeft, akTop, akRight] Caption = 'On render complete' Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -467,17 +396,13 @@ object OptionsForm: TOptionsForm Font.Name = 'Tahoma' Font.Style = [fsBold] ParentFont = False - TabOrder = 2 - DesignSize = ( - 354 - 120) + TabOrder = 0 object btnBrowseSound: TSpeedButton - Left = 321 + Left = 265 Top = 41 Width = 24 Height = 24 Hint = 'Browse...' - Anchors = [akTop, akRight] Flat = True Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -515,15 +440,13 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnBrowseSoundClick - ExplicitLeft = 284 end object btnPlay: TSpeedButton - Left = 321 + Left = 265 Top = 14 Width = 24 Height = 24 Hint = 'Play' - Anchors = [akTop, akRight] Flat = True Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -561,7 +484,6 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnPlayClick - ExplicitLeft = 284 end object Label44: TLabel Left = 10 @@ -577,12 +499,17 @@ object OptionsForm: TOptionsForm ParentFont = False end object txtSoundFile: TEdit - Left = 84 + Left = 73 Top = 42 - Width = 230 + Width = 188 Height = 21 HelpContext = 1000 - Anchors = [akLeft, akTop, akRight] + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False ParentShowHint = False ShowHint = False TabOrder = 0 @@ -590,7 +517,7 @@ object OptionsForm: TOptionsForm object chkPlaysound: TCheckBox Left = 8 Top = 18 - Width = 270 + Width = 251 Height = 17 Caption = 'Play sound' Font.Charset = ANSI_CHARSET @@ -630,46 +557,341 @@ object OptionsForm: TOptionsForm TabOrder = 3 end end - object chkAutoSaveXML: TCheckBox - Left = 236 - Top = 215 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Automatically save pasted parameters' - TabOrder = 19 + object gbNotifications: TGroupBox + Left = 240 + Top = 35 + Width = 297 + Height = 145 + Caption = 'Notifications' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 10 + DesignSize = ( + 297 + 145) + object cbMissingPlugin: TCheckBox + Left = 4 + Top = 120 + Width = 282 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Warn when plugins are missing' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + WordWrap = True + end + object chkConfirmClearScript: TCheckBox + Left = 4 + Top = 80 + Width = 282 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Confirm clear script' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + end + object chkConfirmDel: TCheckBox + Left = 4 + Top = 20 + Width = 282 + Height = 17 + HelpContext = 1005 + Anchors = [akLeft, akTop, akRight] + Caption = 'Confirm delete' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + end + object chkConfirmExit: TCheckBox + Left = 4 + Top = 40 + Width = 282 + Height = 17 + HelpContext = 1005 + Anchors = [akLeft, akTop, akRight] + Caption = 'Confirm exit' + Color = clBtnFace + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentColor = False + ParentFont = False + TabOrder = 3 + end + object chkConfirmStopRender: TCheckBox + Left = 4 + Top = 60 + Width = 282 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Confirm stop render' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 4 + end + object chkConfirmResetUndo: TCheckBox + Left = 4 + Top = 100 + Width = 282 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Confirm reset editing history' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 5 + end end - object chkRandomTemplates: TCheckBox - Left = 236 - Top = 95 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Randomize gradient for templates' - TabOrder = 20 - WordWrap = True + object gbDefaults: TGroupBox + Left = 240 + Top = 185 + Width = 297 + Height = 105 + Caption = 'Defaults' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 11 + DesignSize = ( + 297 + 105) + object cbUseTemplate: TCheckBox + Left = 4 + Top = 20 + Width = 381 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Always create blank flame' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + end + object chkApplyFlatten: TCheckBox + Left = 4 + Top = 40 + Width = 381 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Apply flattening to old flames' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + WordWrap = True + end + object chkAutoSaveXML: TCheckBox + Left = 4 + Top = 60 + Width = 398 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Automatically save pasted parameters' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + end + object chkEngLayout: TCheckBox + Left = 4 + Top = 80 + Width = 398 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Set English keyboard layout' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 3 + end end - object chkApplyFlatten: TCheckBox - Left = 236 - Top = 235 - Width = 258 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Apply flattening to old flames' - TabOrder = 21 - WordWrap = True + object gbAnimation: TGroupBox + Left = 8 + Top = 272 + Width = 217 + Height = 125 + Caption = 'Animation' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False + TabOrder = 12 + DesignSize = ( + 217 + 125) + object pnlFPS: TPanel + Left = 8 + Top = 20 + Width = 105 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Frames per second' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 1 + end + object pnlAnimPrefix: TPanel + Left = 8 + Top = 72 + Width = 105 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Frame prefix' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 2 + end + object edAnimPrefix: TEdit + Left = 112 + Top = 72 + Width = 96 + Height = 21 + HelpContext = 1021 + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + Text = 'animate-' + end + object seFPS: TSpinEdit + Left = 112 + Top = 20 + Width = 96 + Height = 22 + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + MaxValue = 250 + MinValue = 5 + ParentFont = False + TabOrder = 3 + Value = 25 + OnKeyPress = NumFieldKeyPress + end + object pnlFrameExt: TPanel + Left = 8 + Top = 48 + Width = 105 + Height = 21 + BevelOuter = bvLowered + Caption = 'Graphic extension' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 4 + end + object cbFrameExt: TComboBox + Left = 112 + Top = 48 + Width = 96 + Height = 21 + Style = csDropDownList + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ItemIndex = 1 + ParentFont = False + TabOrder = 5 + Text = '.png' + Items.Strings = ( + '.bmp' + '.png' + '.jpg') + end + object chkCreateAnimFolder: TCheckBox + Left = 8 + Top = 100 + Width = 282 + Height = 17 + HelpContext = 1005 + Anchors = [akLeft, akTop, akRight] + Caption = 'Create a new folder for frames' + Color = clBtnFace + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentColor = False + ParentFont = False + TabOrder = 6 + end end end object EditorPage: TTabSheet Caption = 'Editor' ImageIndex = 8 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) + 548 + 435) object GroupBox1: TGroupBox Left = 8 Top = 4 @@ -738,8 +960,8 @@ object OptionsForm: TOptionsForm object GroupBox21: TGroupBox Left = 231 Top = 4 - Width = 268 - Height = 128 + Width = 312 + Height = 145 Anchors = [akLeft, akTop, akRight] Caption = 'Editor defaults' Font.Charset = ANSI_CHARSET @@ -750,12 +972,12 @@ object OptionsForm: TOptionsForm ParentFont = False TabOrder = 1 DesignSize = ( - 268 - 128) + 312 + 145) object chkAxisLock: TCheckBox Left = 8 Top = 38 - Width = 257 + Width = 301 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Lock transform axis' @@ -772,7 +994,7 @@ object OptionsForm: TOptionsForm object chkExtendedEdit: TCheckBox Left = 8 Top = 18 - Width = 257 + Width = 301 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Extended edit mode' @@ -789,7 +1011,7 @@ object OptionsForm: TOptionsForm object chkXaosRebuild: TCheckBox Left = 8 Top = 58 - Width = 257 + Width = 301 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Rebuild xaos links' @@ -806,7 +1028,7 @@ object OptionsForm: TOptionsForm object chkResetCoefs: TCheckBox Left = 8 Top = 78 - Width = 257 + Width = 301 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Reset coefs by double-click' @@ -821,7 +1043,7 @@ object OptionsForm: TOptionsForm object chkResetLinear: TCheckBox Left = 8 Top = 98 - Width = 257 + Width = 301 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Reset linear when other variation is set' @@ -833,6 +1055,21 @@ object OptionsForm: TOptionsForm ParentFont = False TabOrder = 4 end + object chkSyncTriangles: TCheckBox + Left = 8 + Top = 118 + Width = 301 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Synchronize triangles' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 5 + end end object grpEditorColors: TGroupBox Left = 8 @@ -1067,7 +1304,7 @@ object OptionsForm: TOptionsForm object chkEnableEditorPreview: TCheckBox Left = 8 Top = 256 - Width = 486 + Width = 530 Height = 17 Anchors = [akLeft, akTop, akRight] Caption = 'Enable editor preview' @@ -1095,7 +1332,7 @@ object OptionsForm: TOptionsForm object tbEPTransparency: TTrackBar Left = 128 Top = 276 - Width = 366 + Width = 410 Height = 25 Anchors = [akLeft, akTop, akRight] LineSize = 4 @@ -1107,16 +1344,12 @@ object OptionsForm: TOptionsForm end object DisplayPage: TTabSheet Caption = 'Display' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) + 548 + 435) object GroupBox2: TGroupBox - Left = 243 - Top = 78 + Left = 245 + Top = 4 Width = 226 Height = 100 Anchors = [akTop, akRight] @@ -1236,7 +1469,7 @@ object OptionsForm: TOptionsForm end object grpRendering: TGroupBox Left = 8 - Top = 78 + Top = 4 Width = 217 Height = 245 Caption = 'Rendering' @@ -1564,120 +1797,9 @@ object OptionsForm: TOptionsForm OnKeyPress = NumFloatKeyPress end end - object GroupBox20: TGroupBox - Left = 8 - Top = 2 - Width = 491 - Height = 73 - Anchors = [akLeft, akTop, akRight] - Caption = 'Main Window Preview' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [fsBold] - ParentFont = False - TabOrder = 2 - object Label48: TLabel - Left = 188 - Top = 46 - Width = 11 - Height = 13 - Caption = '%' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - end - object chkShowTransparency: TCheckBox - Left = 250 - Top = 20 - Width = 233 - Height = 17 - Caption = 'Show Transparency' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 2 - end - object chkExtendMainPreview: TCheckBox - Left = 8 - Top = 20 - Width = 225 - Height = 17 - Caption = 'Extend preview buffer' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 0 - end - object pnlExtension: TPanel - Left = 8 - Top = 42 - Width = 105 - Height = 21 - Cursor = crArrow - BevelOuter = bvLowered - Caption = 'Buffer extension' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 4 - end - object cbExtendPercent: TComboBox - Left = 112 - Top = 42 - Width = 73 - Height = 21 - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 1 - OnKeyPress = NumFieldKeyPress - Items.Strings = ( - '0' - '10' - '25' - '50' - '100' - '150' - '200') - end - object chkUseSmallThumbs: TCheckBox - Left = 250 - Top = 38 - Width = 209 - Height = 31 - Caption = 'Use small thumbnails' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 3 - WordWrap = True - end - end object GroupBox7: TGroupBox - Left = 243 - Top = 179 + Left = 245 + Top = 110 Width = 226 Height = 100 Anchors = [akTop, akRight] @@ -1688,7 +1810,7 @@ object OptionsForm: TOptionsForm Font.Name = 'Tahoma' Font.Style = [fsBold] ParentFont = False - TabOrder = 3 + TabOrder = 2 object pnSTile: TPanel Left = 8 Top = 24 @@ -1796,8 +1918,8 @@ object OptionsForm: TOptionsForm end object rgRotationMode: TRadioGroup Left = 8 - Top = 358 - Width = 220 + Top = 292 + Width = 226 Height = 66 Anchors = [akLeft, akBottom] Caption = 'Rotation Mode' @@ -1810,25 +1932,136 @@ object OptionsForm: TOptionsForm 'Rotate image' 'Rotate frame') ParentFont = False - TabOrder = 4 + TabOrder = 3 end object rgZoomingMode: TRadioGroup - Left = 243 - Top = 358 + Left = 8 + Top = 365 Width = 226 Height = 66 - Anchors = [akRight, akBottom] + Anchors = [akLeft, akBottom] Caption = 'Zooming mode' Items.Strings = ( 'Preserve quality' 'Preserve speed') + TabOrder = 4 + end + object GroupBox20: TGroupBox + Left = 245 + Top = 237 + Width = 226 + Height = 120 + Anchors = [akRight, akBottom] + Caption = 'Main Window Preview' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False TabOrder = 5 + object Label48: TLabel + Left = 188 + Top = 46 + Width = 11 + Height = 13 + Caption = '%' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + end + object chkShowTransparency: TCheckBox + Left = 8 + Top = 72 + Width = 233 + Height = 17 + Caption = 'Show Transparency' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + end + object chkExtendMainPreview: TCheckBox + Left = 8 + Top = 20 + Width = 225 + Height = 17 + Caption = 'Extend preview buffer' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 0 + end + object pnlExtension: TPanel + Left = 8 + Top = 42 + Width = 105 + Height = 21 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Buffer extension' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 4 + end + object cbExtendPercent: TComboBox + Left = 112 + Top = 42 + Width = 73 + Height = 21 + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + OnKeyPress = NumFieldKeyPress + Items.Strings = ( + '0' + '10' + '25' + '50' + '100' + '150' + '200') + end + object chkUseSmallThumbs: TCheckBox + Left = 8 + Top = 88 + Width = 209 + Height = 31 + Caption = 'Use small thumbnails' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 3 + WordWrap = True + end end object rgEnumMode: TRadioGroup - Left = 243 - Top = 298 + Left = 245 + Top = 365 Width = 226 - Height = 55 + Height = 66 Anchors = [akRight, akBottom] Caption = 'Enumerating mode ' Items.Strings = ( @@ -1839,13 +2072,9 @@ object OptionsForm: TOptionsForm end object RandomPage: TTabSheet Caption = 'Random' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) + 548 + 435) object gpNumberOfTransforms: TGroupBox Left = 8 Top = 6 @@ -1951,7 +2180,7 @@ object OptionsForm: TOptionsForm end end object gpFlameTitlePrefix: TGroupBox - Left = 269 + Left = 235 Top = 88 Width = 217 Height = 122 @@ -2102,7 +2331,7 @@ object OptionsForm: TOptionsForm end end object gpMutationTransforms: TGroupBox - Left = 269 + Left = 235 Top = 6 Width = 214 Height = 75 @@ -2430,15 +2659,11 @@ object OptionsForm: TOptionsForm object VariationsPage: TTabSheet Caption = 'Variations' ImageIndex = 4 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) + 548 + 435) object btnSetAll: TButton - Left = 410 + Left = 454 Top = 24 Width = 91 Height = 25 @@ -2449,7 +2674,7 @@ object OptionsForm: TOptionsForm OnClick = btnSetAllClick end object btnClearAll: TButton - Left = 410 + Left = 454 Top = 52 Width = 91 Height = 25 @@ -2460,7 +2685,7 @@ object OptionsForm: TOptionsForm OnClick = btnClearAllClick end object btnInvert: TButton - Left = 410 + Left = 454 Top = 80 Width = 91 Height = 25 @@ -2473,22 +2698,18 @@ object OptionsForm: TOptionsForm object VarsPages: TPageControl Left = 0 Top = 0 - Width = 403 - Height = 426 + Width = 447 + Height = 433 ActivePage = tabRandomVars Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 2 object tabRandomVars: TTabSheet Caption = 'Random choise' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object clbVarEnabled: TCheckListBox Left = 0 Top = 0 - Width = 395 - Height = 398 + Width = 439 + Height = 405 Align = alClient Columns = 2 ItemHeight = 13 @@ -2498,15 +2719,11 @@ object OptionsForm: TOptionsForm end object tabFavouriteVars: TTabSheet Caption = 'Favourites' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object clbVarFavourite: TCheckListBox Left = 0 Top = 0 - Width = 395 - Height = 398 + Width = 439 + Height = 405 Align = alClient Columns = 2 ItemHeight = 13 @@ -2519,16 +2736,9 @@ object OptionsForm: TOptionsForm object GradientPage: TTabSheet Caption = 'Gradient' ImageIndex = 5 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - DesignSize = ( - 504 - 428) object GroupBox13: TGroupBox - Left = 8 - Top = 186 + Left = 235 + Top = 13 Width = 209 Height = 79 Caption = 'Smooth palette' @@ -2721,11 +2931,10 @@ object OptionsForm: TOptionsForm end end object GroupBox18: TGroupBox - Left = 266 - Top = 8 + Left = 8 + Top = 188 Width = 209 Height = 81 - Anchors = [akTop, akRight] Caption = 'Saturation range' Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -2830,7 +3039,7 @@ object OptionsForm: TOptionsForm end object GroupBox22: TGroupBox Left = 8 - Top = 96 + Top = 98 Width = 209 Height = 81 Caption = 'Luminance range' @@ -2938,11 +3147,10 @@ object OptionsForm: TOptionsForm end end object GroupBox23: TGroupBox - Left = 266 - Top = 96 + Left = 8 + Top = 278 Width = 209 Height = 81 - Anchors = [akTop, akRight] Caption = 'Number of nodes' Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -3051,11 +3259,10 @@ object OptionsForm: TOptionsForm end end object rgColorBlend: TRadioGroup - Left = 266 - Top = 183 - Width = 209 + Left = 235 + Top = 189 + Width = 265 Height = 82 - Anchors = [akTop, akRight] Caption = 'Color blending ' ItemIndex = 0 Items.Strings = ( @@ -3064,31 +3271,82 @@ object OptionsForm: TOptionsForm 'No blend') TabOrder = 5 end - object chkEqualStripes: TCheckBox - Left = 13 - Top = 275 - Width = 491 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = ' Use equal color stripes' - Checked = True - State = cbChecked + object gbGradDefaults: TGroupBox + Left = 235 + Top = 98 + Width = 265 + Height = 85 + Caption = 'Defaults' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [fsBold] + ParentFont = False TabOrder = 6 - WordWrap = True + DesignSize = ( + 265 + 85) + object chkEqualStripes: TCheckBox + Left = 4 + Top = 60 + Width = 558 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = ' Use equal color stripes' + Checked = True + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + State = cbChecked + TabOrder = 0 + WordWrap = True + end + object chkRandomTemplates: TCheckBox + Left = 4 + Top = 40 + Width = 342 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Randomize gradient for templates' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 1 + WordWrap = True + end + object chkOldPaletteFormat: TCheckBox + Left = 5 + Top = 20 + Width = 342 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Save gradient in old file format' + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + ParentFont = False + TabOrder = 2 + WordWrap = True + end end end object UPRPage: TTabSheet Caption = 'UPR' ImageIndex = 5 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 DesignSize = ( - 504 - 428) + 548 + 435) object chkAdjustDensity: TCheckBox - Left = 274 + Left = 260 Top = 264 Width = 228 Height = 33 @@ -3098,7 +3356,7 @@ object OptionsForm: TOptionsForm WordWrap = True end object GroupBox11: TGroupBox - Left = 274 + Left = 260 Top = 184 Width = 228 Height = 81 @@ -3294,7 +3552,7 @@ object OptionsForm: TOptionsForm object GroupBox4: TGroupBox Left = 8 Top = 6 - Width = 494 + Width = 480 Height = 83 Anchors = [akLeft, akTop, akRight] Caption = 'Coloring algorithm' @@ -3373,7 +3631,7 @@ object OptionsForm: TOptionsForm object GroupBox5: TGroupBox Left = 8 Top = 95 - Width = 494 + Width = 480 Height = 82 Anchors = [akLeft, akTop, akRight] Caption = 'Fractal formula' @@ -3454,11 +3712,11 @@ object OptionsForm: TOptionsForm Caption = 'Environment' ImageIndex = 7 DesignSize = ( - 504 - 428) - object btnDefGradient: TSpeedButton - Left = 474 - Top = 7 + 548 + 435) + object btnDefParams: TSpeedButton + Left = 520 + Top = 5 Width = 24 Height = 24 Hint = 'Browse...' @@ -3499,11 +3757,10 @@ object OptionsForm: TOptionsForm ParentFont = False ParentShowHint = False ShowHint = True - OnClick = btnDefGradientClick - ExplicitLeft = 437 + OnClick = btnDefParamsClick end object btnSmooth: TSpeedButton - Left = 474 + Left = 520 Top = 31 Width = 24 Height = 24 @@ -3546,10 +3803,9 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnSmoothClick - ExplicitLeft = 437 end - object SpeedButton2: TSpeedButton - Left = 474 + object btnDefLibrary: TSpeedButton + Left = 520 Top = 55 Width = 24 Height = 24 @@ -3591,12 +3847,11 @@ object OptionsForm: TOptionsForm ParentFont = False ParentShowHint = False ShowHint = True - OnClick = SpeedButton2Click - ExplicitLeft = 437 + OnClick = btnDefLibraryClick end object btnRenderer: TSpeedButton - Left = 474 - Top = 79 + Left = 521 + Top = 83 Width = 24 Height = 24 Hint = 'Browse...' @@ -3638,11 +3893,10 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnRendererClick - ExplicitLeft = 437 end object btnHelp: TSpeedButton - Left = 474 - Top = 103 + Left = 520 + Top = 105 Width = 24 Height = 24 Hint = 'Browse...' @@ -3684,7 +3938,6 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnHelpClick - ExplicitLeft = 437 end object Label49: TLabel Left = 245 @@ -3693,52 +3946,8 @@ object OptionsForm: TOptionsForm Height = 13 Caption = 'minutes' end - object btnFindDefaultSaveFile: TSpeedButton - Left = 437 - Top = 272 - Width = 24 - Height = 24 - Hint = 'Browse...' - Flat = True - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Arial' - Font.Style = [fsBold] - Glyph.Data = { - 36030000424D3603000000000000360000002800000010000000100000000100 - 18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF - FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF75848F66808F - 607987576E7B4E626F4456613948522E3A43252E351B222914191E0E12160E13 - 18FF00FFFF00FFFF00FF77879289A1AB6AB2D4008FCD008FCD008FCD048CC708 - 88BE0F82B4157CA91B779F1F7296224B5C87A2ABFF00FFFF00FF7A8A957EBED3 - 8AA4AE7EDCFF5FCFFF55CBFF4CC4FA41BCF537B3F02EAAEB24A0E5138CD42367 - 805E696DFF00FFFF00FF7D8E9879D2EC8BA4AD89C2CE71D8FF65D3FF5CCEFF51 - C9FE49C1FA3FB9F534B0EE29A8E91085CD224B5B98B2BAFF00FF80919C81D7EF - 7DC5E08CA6B080DDFE68D3FF67D4FF62D1FF58CDFF4EC7FC46BEF73BB6F231AC - EC2569817A95A1FF00FF83959F89DCF18CE2FF8DA8B18CBAC774D8FF67D4FF67 - D4FF67D4FF5FD0FF54CDFF4BC5FC41BBF72EA2DB51677498B2BA869AA392E1F2 - 98E8FD80C4DE8EA7B081DEFD84E0FF84E0FF84E0FF84E0FF81DFFF7BDDFF74D8 - FF6BD6FF56A9D18F9BA4889CA59AE6F39FEBFB98E8FE8BACB98BACB98AAAB788 - A6B386A3AF839FAA819AA67F95A17C919D7A8E99798B957788938BA0A8A0EAF6 - A6EEF99FEBFB98E8FE7ADAFF67D4FF67D4FF67D4FF67D4FF67D4FF67D4FF7788 - 93FF00FFFF00FFFF00FF8EA2ABA7EEF6ABF0F7A6EEF99FEBFB98E8FD71D4FB89 - 9EA78699A382949F7E909A7A8C97778893FF00FFFF00FFFF00FF8FA4ACA0D2DA - ABF0F7ABF0F7A6EEF99FEBFB8DA1AAB5CBD0FF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFBDCED48FA4AC8FA4AC8FA4AC8FA4AC8FA4ACB5CBD0FF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF - FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 - FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF - 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} - ParentFont = False - ParentShowHint = False - ShowHint = True - OnClick = btnFindDefaultSaveFileClick - end object btnPluginPath: TSpeedButton - Left = 474 + Left = 520 Top = 128 Width = 24 Height = 24 @@ -3781,10 +3990,9 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnPluginPathClick - ExplicitLeft = 437 end object btnSShotPath: TSpeedButton - Left = 474 + Left = 520 Top = 155 Width = 24 Height = 24 @@ -3827,10 +4035,9 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnSShotPathClick - ExplicitLeft = 437 end object btnDefScript: TSpeedButton - Left = 474 + Left = 520 Top = 181 Width = 24 Height = 24 @@ -3873,7 +4080,50 @@ object OptionsForm: TOptionsForm ParentShowHint = False ShowHint = True OnClick = btnDefScriptClick - ExplicitLeft = 437 + end + object btnFindDefaultSaveFile: TSpeedButton + Left = 440 + Top = 272 + Width = 24 + Height = 24 + Hint = 'Browse...' + Flat = True + Font.Charset = ANSI_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Arial' + Font.Style = [fsBold] + Glyph.Data = { + 36030000424D3603000000000000360000002800000010000000100000000100 + 18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF75848F66808F + 607987576E7B4E626F4456613948522E3A43252E351B222914191E0E12160E13 + 18FF00FFFF00FFFF00FF77879289A1AB6AB2D4008FCD008FCD008FCD048CC708 + 88BE0F82B4157CA91B779F1F7296224B5C87A2ABFF00FFFF00FF7A8A957EBED3 + 8AA4AE7EDCFF5FCFFF55CBFF4CC4FA41BCF537B3F02EAAEB24A0E5138CD42367 + 805E696DFF00FFFF00FF7D8E9879D2EC8BA4AD89C2CE71D8FF65D3FF5CCEFF51 + C9FE49C1FA3FB9F534B0EE29A8E91085CD224B5B98B2BAFF00FF80919C81D7EF + 7DC5E08CA6B080DDFE68D3FF67D4FF62D1FF58CDFF4EC7FC46BEF73BB6F231AC + EC2569817A95A1FF00FF83959F89DCF18CE2FF8DA8B18CBAC774D8FF67D4FF67 + D4FF67D4FF5FD0FF54CDFF4BC5FC41BBF72EA2DB51677498B2BA869AA392E1F2 + 98E8FD80C4DE8EA7B081DEFD84E0FF84E0FF84E0FF84E0FF81DFFF7BDDFF74D8 + FF6BD6FF56A9D18F9BA4889CA59AE6F39FEBFB98E8FE8BACB98BACB98AAAB788 + A6B386A3AF839FAA819AA67F95A17C919D7A8E99798B957788938BA0A8A0EAF6 + A6EEF99FEBFB98E8FE7ADAFF67D4FF67D4FF67D4FF67D4FF67D4FF67D4FF7788 + 93FF00FFFF00FFFF00FF8EA2ABA7EEF6ABF0F7A6EEF99FEBFB98E8FD71D4FB89 + 9EA78699A382949F7E909A7A8C97778893FF00FFFF00FFFF00FF8FA4ACA0D2DA + ABF0F7ABF0F7A6EEF99FEBFB8DA1AAB5CBD0FF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFBDCED48FA4AC8FA4AC8FA4AC8FA4AC8FA4ACB5CBD0FF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF + FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00 + FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF + 00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF} + ParentFont = False + ParentShowHint = False + ShowHint = True + OnClick = btnFindDefaultSaveFileClick end object chkRememberLastOpen: TCheckBox Left = 8 @@ -3900,7 +4150,7 @@ object OptionsForm: TOptionsForm object txtDefParameterFile: TEdit Left = 146 Top = 8 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -3926,7 +4176,7 @@ object OptionsForm: TOptionsForm object txtDefSmoothFile: TEdit Left = 146 Top = 32 - Width = 329 + Width = 373 Height = 21 HelpContext = 1001 Anchors = [akLeft, akTop, akRight] @@ -3978,7 +4228,7 @@ object OptionsForm: TOptionsForm object txtLibrary: TEdit Left = 146 Top = 56 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -3990,7 +4240,7 @@ object OptionsForm: TOptionsForm object txtRenderer: TEdit Left = 146 Top = 80 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -4002,7 +4252,7 @@ object OptionsForm: TOptionsForm object txtHelp: TEdit Left = 146 Top = 104 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -4081,7 +4331,7 @@ object OptionsForm: TOptionsForm Left = 8 Top = 329 Width = 457 - Height = 73 + Height = 56 Caption = 'Chaotica 0.45+' Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -4092,9 +4342,9 @@ object OptionsForm: TOptionsForm TabOrder = 16 DesignSize = ( 457 - 73) + 56) object btnChaotica: TSpeedButton - Left = 425 + Left = 429 Top = 18 Width = 24 Height = 24 @@ -4156,21 +4406,6 @@ object OptionsForm: TOptionsForm ShowHint = True TabOrder = 1 end - object cbC64: TCheckBox - Left = 8 - Top = 48 - Width = 441 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use x64-version if possible' - Font.Charset = ANSI_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - ParentFont = False - TabOrder = 2 - end object txtChaotica: TEdit Left = 136 Top = 20 @@ -4198,7 +4433,7 @@ object OptionsForm: TOptionsForm Caption = 'File name (x64)' ParentShowHint = False ShowHint = True - TabOrder = 3 + TabOrder = 2 Visible = False end end @@ -4219,7 +4454,7 @@ object OptionsForm: TOptionsForm object txtPluginFolder: TEdit Left = 146 Top = 130 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -4245,7 +4480,7 @@ object OptionsForm: TOptionsForm object txtSShotFolder: TEdit Left = 146 Top = 156 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -4270,7 +4505,7 @@ object OptionsForm: TOptionsForm object txtDefScript: TEdit Left = 146 Top = 182 - Width = 329 + Width = 373 Height = 21 HelpContext = 1000 Anchors = [akLeft, akTop, akRight] @@ -4280,29 +4515,8 @@ object OptionsForm: TOptionsForm end end end - object btnOK: TButton - Left = 327 - Top = 469 - Width = 86 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - TabOrder = 0 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 422 - Top = 469 - Width = 86 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Cancel' - TabOrder = 1 - OnClick = btnCancelClick - end object OpenDialog: TOpenDialog - Left = 424 - Top = 392 + Left = 24 + Top = 448 end end diff --git a/Forms/Options.pas b/Forms/Options.pas index b997b46..36fe4d1 100644 --- a/Forms/Options.pas +++ b/Forms/Options.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -22,38 +22,30 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } //{$D-,L-,O+,Q-,R-,Y-,S-} + unit Options; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, ComCtrls, ExtCtrls, Buttons, Registry, Mask, CheckLst, - MMSystem, Translation, RegexHelper, FileCtrl, StrUtils, ShellAPI, ShlObj, - Vcl.Samples.Spin; + StdCtrls, ComCtrls, ExtCtrls, Buttons, Registry, CheckLst, + MMSystem, FileCtrl, StrUtils, ShellAPI, ShlObj, Vcl.Samples.Spin; type TOptionsForm = class(TForm) btnOK: TButton; btnCancel: TButton; OpenDialog: TOpenDialog; - GroupBox15: TGroupBox; - btnBrowseSound: TSpeedButton; - btnPlay: TSpeedButton; - Label44: TLabel; - txtSoundFile: TEdit; - chkPlaysound: TCheckBox; Tabs: TPageControl; GeneralPage: TTabSheet; - SpeedButton1: TSpeedButton; + btnLanguage: TSpeedButton; pnlJPEGQuality: TPanel; chkConfirmDel: TCheckBox; - chkOldPaletteFormat: TCheckBox; chkConfirmExit: TCheckBox; chkConfirmStopRender: TCheckBox; cbUseTemplate: TCheckBox; cbMissingPlugin: TCheckBox; - cbEmbedThumbs: TCheckBox; pnlMultithreading: TPanel; cbNrTheads: TComboBox; pnlPNGTransparency: TPanel; @@ -72,14 +64,29 @@ type txtLanguageFile: TComboBox; cbPNGTransparency: TComboBox; txtJPEGquality: TComboBox; + chkEngLayout: TCheckBox; + chkConfirmClearScript: TCheckBox; + GroupBox15: TGroupBox; + btnBrowseSound: TSpeedButton; + btnPlay: TSpeedButton; + Label44: TLabel; + txtSoundFile: TEdit; + chkPlaysound: TCheckBox; + chkShowRenderStats: TCheckBox; + chkShowRenderImage: TCheckBox; + chkAutoSaveXML: TCheckBox; + chkApplyFlatten: TCheckBox; EditorPage: TTabSheet; GroupBox1: TGroupBox; chkUseXFormColor: TCheckBox; chkHelpers: TCheckBox; + chkShowAllXforms: TCheckBox; GroupBox21: TGroupBox; chkAxisLock: TCheckBox; chkExtendedEdit: TCheckBox; chkXaosRebuild: TCheckBox; + chkResetCoefs: TCheckBox; + chkResetLinear: TCheckBox; grpEditorColors: TGroupBox; pnlBackground: TPanel; pnlReferenceC: TPanel; @@ -95,6 +102,9 @@ type shGC1: TShape; pnlGridColor2: TPanel; shGC2: TShape; + pnlReflection: TPanel; + pnlReflectionC: TPanel; + shReflection: TShape; chkEnableEditorPreview: TCheckBox; Panel48: TPanel; tbEPTransparency: TTrackBar; @@ -121,6 +131,19 @@ type txtBrightness: TEdit; txtGamma: TEdit; txtSampleDensity: TEdit; + pnlFuse: TPanel; + txtFuse: TSpinEdit; + pnlContrast: TPanel; + txtContrast: TEdit; + GroupBox7: TGroupBox; + pnSTile: TPanel; + pnRTile: TPanel; + pnHexTile: TPanel; + txtHexTile: TEdit; + txtRTile: TEdit; + txtSTile: TEdit; + rgRotationMode: TRadioGroup; + rgZoomingMode: TRadioGroup; GroupBox20: TGroupBox; Label48: TLabel; chkShowTransparency: TCheckBox; @@ -128,6 +151,7 @@ type pnlExtension: TPanel; cbExtendPercent: TComboBox; chkUseSmallThumbs: TCheckBox; + rgEnumMode: TRadioGroup; RandomPage: TTabSheet; gpNumberOfTransforms: TGroupBox; udMinXforms: TUpDown; @@ -143,6 +167,9 @@ type Panel12: TPanel; txtBatchSize: TEdit; txtRandomPrefix: TEdit; + pnlRandBackground: TPanel; + pnlRandBackColor: TPanel; + shRandBackColor: TShape; gpMutationTransforms: TGroupBox; udMinMutate: TUpDown; udMaxMutate: TUpDown; @@ -166,7 +193,12 @@ type VariationsPage: TTabSheet; btnSetAll: TButton; btnClearAll: TButton; + btnInvert: TButton; + VarsPages: TPageControl; + tabRandomVars: TTabSheet; clbVarEnabled: TCheckListBox; + tabFavouriteVars: TTabSheet; + clbVarFavourite: TCheckListBox; GradientPage: TTabSheet; GroupBox13: TGroupBox; Panel28: TPanel; @@ -201,6 +233,8 @@ type txtMinNodes: TEdit; udMaxNodes: TUpDown; txtMaxNodes: TEdit; + rgColorBlend: TRadioGroup; + chkEqualStripes: TCheckBox; UPRPage: TTabSheet; chkAdjustDensity: TCheckBox; GroupBox11: TGroupBox; @@ -226,13 +260,16 @@ type txtFFFile: TEdit; txtFFIdent: TEdit; PathsPage: TTabSheet; - btnDefGradient: TSpeedButton; + btnDefParams: TSpeedButton; btnSmooth: TSpeedButton; - SpeedButton2: TSpeedButton; + btnDefLibrary: TSpeedButton; btnRenderer: TSpeedButton; btnHelp: TSpeedButton; Label49: TLabel; btnFindDefaultSaveFile: TSpeedButton; + btnPluginPath: TSpeedButton; + btnSShotPath: TSpeedButton; + btnDefScript: TSpeedButton; chkRememberLastOpen: TCheckBox; Panel39: TPanel; txtDefParameterFile: TEdit; @@ -252,62 +289,35 @@ type GroupBox3: TGroupBox; btnChaotica: TSpeedButton; Panel47: TPanel; - cbC64: TCheckBox; txtChaotica: TEdit; Panel49: TPanel; - btnPluginPath: TSpeedButton; Panel50: TPanel; txtPluginFolder: TEdit; - pnlReflection: TPanel; - pnlReflectionC: TPanel; - shReflection: TShape; - GroupBox7: TGroupBox; - pnSTile: TPanel; - pnRTile: TPanel; - pnHexTile: TPanel; - txtHexTile: TEdit; - txtRTile: TEdit; - txtSTile: TEdit; - pnlFuse: TPanel; - txtFuse: TSpinEdit; - chkEngLayout: TCheckBox; - chkConfirmClearScript: TCheckBox; pnlScreenShot: TPanel; - btnSShotPath: TSpeedButton; txtSShotFolder: TEdit; - rgRotationMode: TRadioGroup; - rgZoomingMode: TRadioGroup; - chkShowRenderStats: TCheckBox; - btnDefScript: TSpeedButton; pnlScriptFile: TPanel; txtDefScript: TEdit; - chkAutoSaveXML: TCheckBox; - rgColorBlend: TRadioGroup; - chkEqualStripes: TCheckBox; - pnlContrast: TPanel; - txtContrast: TEdit; + chkSyncTriangles: TCheckBox; + gbNotifications: TGroupBox; + gbDefaults: TGroupBox; + chkOldPaletteFormat: TCheckBox; chkRandomTemplates: TCheckBox; - chkResetCoefs: TCheckBox; - chkApplyFlatten: TCheckBox; - pnlRandBackground: TPanel; - pnlRandBackColor: TPanel; - shRandBackColor: TShape; - chkResetLinear: TCheckBox; - btnInvert: TButton; - chkShowAllXforms: TCheckBox; - VarsPages: TPageControl; - tabRandomVars: TTabSheet; - tabFavouriteVars: TTabSheet; - clbVarFavourite: TCheckListBox; - rgEnumMode: TRadioGroup; - chkShowRenderImage: TCheckBox; + gbGradDefaults: TGroupBox; + chkConfirmResetUndo: TCheckBox; + gbAnimation: TGroupBox; + pnlFPS: TPanel; + pnlAnimPrefix: TPanel; + edAnimPrefix: TEdit; + seFPS: TSpinEdit; + pnlFrameExt: TPanel; + cbFrameExt: TComboBox; + chkCreateAnimFolder: TCheckBox; procedure chkEnableEditorPreviewClick(Sender: TObject); procedure btnChaoticaClick(Sender: TObject); - procedure SpeedButton1Click(Sender: TObject); - procedure btnCancelClick(Sender: TObject); + procedure btnLanguageClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure btnOKClick(Sender: TObject); - procedure btnDefGradientClick(Sender: TObject); + procedure btnDefParamsClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure btnSmoothClick(Sender: TObject); procedure cmbSymTypeChange(Sender: TObject); @@ -326,7 +336,7 @@ type procedure txtMinMutateChange(Sender: TObject); procedure txtMaxMutateChange(Sender: TObject); procedure btnRendererClick(Sender: TObject); - procedure SpeedButton2Click(Sender: TObject); + procedure btnDefLibraryClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure pnlBackColorClick(Sender: TObject); procedure pnlReferenceClick(Sender: TObject); @@ -390,12 +400,7 @@ implementation {$R *.DFM} uses - Main, Global, Editor, ControlPoint, XFormMan, Adjust, FormRender; - -procedure TOptionsForm.btnCancelClick(Sender: TObject); -begin - Close; -end; + Main, Global, Editor, ControlPoint, XFormMan, Adjust, FormRender, Translation; procedure TOptionsForm.UpdateShapeColors; begin @@ -439,7 +444,6 @@ begin txtNumtries.text := IntToStr(Numtries); txtTryLength.text := IntToStr(Trylength); udBatchSize.Position := BatchSize; -// chkResize.checked := ResizeOnLoad; if NrTreads <= 1 then cbNrTheads.ItemIndex := 0 // AV: MT off @@ -471,17 +475,17 @@ begin chkConfirmExit.Checked := ConfirmExit; chkConfirmStopRender.Checked := ConfirmStopRender; chkConfirmClearScript.Checked := ConfirmClearScript; // AV + chkConfirmResetUndo.Checked := ConfirmResetUndo; // AV chkRememberLastOpen.Checked := RememberLastOpenFile; chkUseSmallThumbs.Checked := UseSmallThumbnails; cbUseTemplate.Checked := AlwaysCreateBlankFlame; cbMissingPlugin.Checked := WarnOnMissingPlugin; - cbEmbedThumbs.Checked := EmbedThumbnails; + // cbEmbedThumbs.Checked := EmbedThumbnails; chkEngLayout.Checked := SetEngLayout; // AV chkAutoSaveXML.Checked := AutoSaveXML; // AV chkEqualStripes.Checked := EqualStripes; chkRandomTemplates.Checked := RandomizeTemplates; chkApplyFlatten.Checked := ApplyFlatten; - //cbSinglePrecision.Checked := SingleBuffer; rgRotationMode.ItemIndex := MainForm_RotationMode; if PreserveQuality then @@ -495,7 +499,11 @@ begin chkPlaySound.Checked := PlaySoundOnRenderComplete; txtSoundFile.Text := RenderCompleteSoundFile; - //cbInternalBitsPerSample.ItemIndex := InternalBitsPerSample; + { Animation } + seFPS.Value := AnimFPS; + edAnimPrefix.Text := defAnimPrefix; + cbFrameExt.ItemIndex := defFrameExt; + chkCreateAnimFolder.Checked := CreateAnimFolder; { Editor } chkUseXFormColor.checked := UseTransformColors; @@ -509,6 +517,7 @@ begin chkEnableEditorPreviewClick(self); chkResetCoefs.Checked := AllowResetCoefs; chkResetLinear.Checked := AllowResetLinear; + chkSyncTriangles.Checked := UseTriangleSync; { Display tab } txtSampleDensity.Text := FloatToStr(defSampleDensity); @@ -529,12 +538,12 @@ begin txtSTile.Text := FloatToStr(Round6(SquareTR)); // AV txtRTile.Text := FloatToStr(RhombTR); // AV - pnlBackColor.Color := TColor(EditorBkgColor); + pnlBackColor.Color := EditorBkgColor; pnlGridColor1.Color := GridColor1; pnlGridColor2.Color := GridColor2; - pnlReference.color := TColor(ReferenceTriangleColor); - pnlReflectionC.Color := TColor(FlipColor); // AV - pnlHelpersColor.Color := TColor(HelpersColor); // AV + pnlReference.color := ReferenceTriangleColor; + pnlReflectionC.Color := FlipColor; // AV + pnlHelpersColor.Color := HelpersColor; // AV cbPNGTransparency.ItemIndex := PNGTransparency; chkShowTransparency.Checked := ShowTransparency; @@ -560,7 +569,7 @@ begin udSymOrder.Position := SymmetryOrder; udSymNVars.Position := SymmetryNVars; - pnlRandBackColor.Color := TColor(RandBackColor); // AV + pnlRandBackColor.Color := RandBackColor; // AV chkKeepBackgroundClick(nil); // AV { Variations tab } @@ -607,19 +616,13 @@ begin cbEnableAutosaveClick(nil); - pnlCenterLine.Color := TColor(LineCenterColor); - pnlThirdsLine.Color := TColor(LineThirdsColor); - pnlGRLine.Color := TColor(LineGRColor); + pnlCenterLine.Color := LineCenterColor; + pnlThirdsLine.Color := LineThirdsColor; + pnlGRLine.Color := LineGRColor; cbGL.Checked := EnableGuides; cbGLClick(nil); txtChaotica.Text := ChaoticaPath; - {$ifdef Apo7X64} - cbc64.Checked := true; - {$else} - cbC64.Checked := UseX64IfPossible; - {$endif} - txtPluginFolder.Text := PluginPath; txtSShotFolder.Text := ScreenShotPath; @@ -627,7 +630,8 @@ begin j := -1; txtLanguageFile.Items.Clear; - for i := 0 to AvailableLanguages.Count-1 do begin + for i := 0 to AvailableLanguages.Count-1 do + begin if AvailableLanguages.Strings[i] = '' then begin txtLanguageFile.Items.Add('Default (English)'); end else begin @@ -637,7 +641,6 @@ begin end; if (lowercase(AvailableLanguages.Strings[i]) = lowercase(languagefile)) then j := i; - end; txtLanguageFile.ItemIndex := j; end; @@ -666,8 +669,8 @@ end; procedure TOptionsForm.NumFloatKeyPress(Sender: TObject; var Key: Char); begin - if (Key = ',') then Key := FormatSettings.DecimalSeparator; - if not CharinSet(Key,['0'..'9', #8, #13, FormatSettings.DecimalSeparator]) + if (Key = ',') then Key := '.'; + if not CharinSet(Key,['0'..'9', #8, #13, '.']) then Key:= #0; end; @@ -689,17 +692,23 @@ begin if vars = false then Variations[0] := true; - warn := (LanguageFile <> AvailableLanguages[txtLanguageFile.ItemIndex]) - { or (UseSmallThumbnails <> chkUseSmallThumbs.Checked)}; // AV: fixed + warn := (SetEngLayout <> chkEngLayout.Checked); + { AV: eliminate "List index out of bounds" error and memory leak + if 32- and 64-bit Apophysis paths are different } + i := txtLanguageFile.ItemIndex; + if (i >= 0) then + warn := warn or (LanguageFile <> AvailableLanguages[i]); // AV - { General tab } - JPEGQuality := StrToInt(txtJPEGQuality.text); - Numtries := StrToInt(txtNumtries.text); - if NumTries < 1 then Numtries := 1; - Trylength := StrToInt(txtTrylength.text); - if Trylength < 100 then trylength := 100; + { General tab } + JPEGQuality := StrToIntDef(txtJPEGQuality.text, 100); if JPEGQuality > 100 then JPEGQuality := 100; if JPEGQuality < 1 then JPEGQuality := 100; + + Numtries := StrToIntDef(txtNumtries.text, 1); + if NumTries < 1 then Numtries := 1; + Trylength := StrToIntDef(txtTrylength.text, 100); + if Trylength < 100 then trylength := 100; + BatchSize := udBatchSize.Position; if BatchSize < 1 then BatchSize := 1; if BatchSize > 300 then BatchSize := 300; @@ -717,28 +726,35 @@ begin RememberLastOpenFile := chkRememberLastOpen.Checked; UseSmallThumbnails := chkUseSmallThumbs.Checked; AlwaysCreateBlankFlame := cbUseTemplate.Checked; - EmbedThumbnails := cbEmbedThumbs.Checked; + // EmbedThumbnails := cbEmbedThumbs.Checked; WarnOnMissingPlugin := cbMissingPlugin.Checked; SetEngLayout := chkEngLayout.Checked; // AV ConfirmClearScript := chkConfirmClearScript.Checked; // AV + ConfirmResetUndo := chkConfirmResetUndo.Checked; // AV AutoSaveXML := chkAutoSaveXML.Checked; // AV EqualStripes := chkEqualStripes.Checked; // AV RandomizeTemplates := chkRandomTemplates.Checked; ApplyFlatten := chkApplyFlatten.Checked; - LanguageFile := AvailableLanguages.Strings[txtLanguageFile.ItemIndex]; - //SingleBuffer := cbSinglePrecision.Checked; + { AV: eliminate "List index out of bounds" error and memory leak + if 32- and 64-bit Apophysis paths are different } + if (i >= 0) then LanguageFile := AvailableLanguages.Strings[i]; MainForm_RotationMode := rgRotationMode.ItemIndex; PreserveQuality := (rgZoomingMode.ItemIndex = 0); FlameEnumMode := rgEnumMode.ItemIndex; // AV - //InternalBitsPerSample := cbInternalBitsPerSample.ItemIndex; LineCenterColor := pnlCenterLine.Color; LineThirdsColor := pnlThirdsLine.Color; LineGRColor := pnlGRLine.Color; EnableGuides := cbGL.Checked; - // Editor + { Animation } + AnimFPS := seFPS.Value; + defAnimPrefix := edAnimPrefix.Text; + defFrameExt := cbFrameExt.ItemIndex; + CreateAnimFolder := chkCreateAnimFolder.Checked; + + { Editor } UseTransformColors := chkUseXFormColor.checked; HelpersEnabled := chkHelpers.Checked; ShowAllXforms := chkShowAllXforms.Checked; @@ -750,101 +766,84 @@ begin EditorPreviewTransparency := tbEPTransparency.Position; AllowResetCoefs := chkResetCoefs.Checked; AllowResetLinear := chkResetLinear.Checked; + UseTriangleSync := chkSyncTriangles.Checked; { Display tab } - try - defSampleDensity := StrToFloat(txtSampleDensity.Text); - if defSampleDensity > 100 then defSampleDensity := 100; - if defSampleDensity <= 0 then defSampleDensity := 0.1; - except - defSampleDensity := 5; - end; - try - defGamma := StrToFloat(txtGamma.Text); - if defGamma < 0.1 then defGamma := 0.1; - except - defGamma := 4; - end; - try - defBrightness := StrToFloat(txtBrightness.Text); - if defBrightness < 0.1 then defBrightness := 0.1; - except - defBrightness := 4; - end; - try // AV - defContrast := StrToFloat(txtContrast.Text); - if defContrast < 0.1 then defContrast := 0.1; - if defContrast > 10 then defContrast := 10; - except - defContrast := 1; - end; - try - defVibrancy := StrToFloat(txtVibrancy.Text); - if defVibrancy < 0 then defVibrancy := 0.1; - except - defVibrancy := 1; - end; - try - defFilterRadius := StrToFloat(txtFilterRadius.Text); + // AV: replaced all try-except blocks by a more convenient StrToFloatDef + + defSampleDensity := StrToFloatDef(txtSampleDensity.Text, 5); + if defSampleDensity > 100 then + defSampleDensity := 100 + else if defSampleDensity <= 0 then + defSampleDensity := 0.1; + + defGamma := StrToFloatDef(txtGamma.Text, 4); + if defGamma < 0.1 then + defGamma := 0.1 + else if defGamma > 10 then + defGamma := 10; + + defBrightness := StrToFloatDef(txtBrightness.Text, 4); + if defBrightness < 0.1 then + defBrightness := 0.1 + else if defBrightness > 100 then + defBrightness := 100; + + defContrast := StrToFloatDef(txtContrast.Text, 1); + if defContrast < 0.1 then + defContrast := 0.1 + else if defContrast > 10 then + defContrast := 10; + + defVibrancy := StrToFloatDef(txtVibrancy.Text, 1); + if defVibrancy < 0.1 then defVibrancy := 0.1; + + defFilterRadius := StrToFloatDef(txtFilterRadius.Text, 0.2); if defFilterRadius <= 0 then defFilterRadius := 0.1; - except - defFilterRadius := 0.2; - end; - try - defGammaThreshold := StrToFloat(txtGammaThreshold.Text); - if defGammaThreshold < 0 then - except - defGammaThreshold := 0.01; - end; - defOversample := StrToInt(txtOversample.Text); - if defOversample > 4 then defOversample := 4; - if defOversample < 1 then defOversample := 1; - try - prevLowQuality := StrToFloat(txtLowQuality.Text); - if prevLowQuality > 100 then prevLowQuality := 100; - if prevLowQuality < 0.01 then - except - prevLowQuality := 0.1; - end; - try - prevMediumQuality := StrToFloat(txtMediumQuality.Text); - if prevMediumQuality > 1000 then prevMediumQuality := 1000; - if prevMediumQuality < 0.01 then prevMediumQuality := 0.01; - except - prevMediumQuality := 1; - end; - try - prevHighQuality := StrToFloat(txtHighQuality.Text); - if prevHighQuality > 10000 then prevHighQuality := 10000; - if prevHighQuality < 0.01 then prevHighQuality := 0.01; - except - prevHighQuality := 5; - end; + + defGammaThreshold := StrToFloatDef(txtGammaThreshold.Text, 0); + if defGammaThreshold < 0 then defGammaThreshold := 0; + + defOversample := StrToIntDef(txtOversample.Text, 1); + if defOversample > 4 then + defOversample := 4 + else if defOversample < 1 then + defOversample := 1; + + prevLowQuality := StrToFloatDef(txtLowQuality.Text, 0.1); + if prevLowQuality > 100 then + prevLowQuality := 100 + else if prevLowQuality < 0.01 then + prevLowQuality := 0.1; + + prevMediumQuality := StrToFloatDef(txtMediumQuality.Text, 1); + if prevMediumQuality > 500 then + prevMediumQuality := 500 + else if prevMediumQuality < 0.01 then + prevMediumQuality := 0.01; + + prevHighQuality := StrToFloatDef(txtHighQuality.Text, 5); + if prevHighQuality > 1000 then + prevHighQuality := 1000 + else if prevHighQuality < 0.01 then + prevHighQuality := 0.01; Fuse := txtFuse.Value; // AV - try - HexTR := StrToFloat(txtHexTile.Text); // AV + HexTR := StrToFloatDef(txtHexTile.Text, 1); // AV if HexTR < 0.1 then HexTR := 0.1; - except - HexTR := 1; - end; - try - SquareTR := StrToFloat(txtSTile.Text); // AV - if SquareTR < 0.1 then SquareTR := 0.1; - except - SquareTR := 1; - end; - try - RhombTR := StrToFloat(txtRTile.Text); // AV - if RhombTR < 0.1 then RhombTR := 0.1; - except - RhombTR := 1; - end; + + SquareTR := StrToFloatDef(txtSTile.Text, 1); // AV + if SquareTR < 0.1 then SquareTR := 0.1; + + RhombTR := StrToFloatDef(txtRTile.Text, 1); // AV + if RhombTR < 0.1 then RhombTR := 0.1; MainPreviewScale := 1 + 0.02 * StrToFloatDef(cbExtendPercent.Text, 0); - if MainPreviewScale < 1 then MainPreviewScale := 1 - else if MainPreviewScale > 5 then MainPreviewScale := 5; + if MainPreviewScale < 1 then + MainPreviewScale := 1 + else if MainPreviewScale > 5 then + MainPreviewScale := 5; ExtendMainPreview := chkExtendMainPreview.Checked; ShowRenderStats := chkShowRenderStats.Checked; @@ -902,8 +901,6 @@ begin ScreenShotPath := ScreenShotPath + '\'; defScriptFile := txtDefScript.Text; // AV - UseX64IfPossible := cbC64.Checked; - PluginPath := txtPluginFolder.Text; if (PluginPath = '') or (not DirectoryExists(PluginPath)) then PluginPath := ExtractFilePath(Application.ExeName); // AV @@ -918,36 +915,34 @@ begin MainForm.mnuExportChaotica.Enabled := FileExists(chaoticaPath + '\chaotica.exe'); if (warn) then - Application.MessageBox(PChar(TextByKey('options-restartnotice')), PChar('Apophysis'), MB_ICONWARNING); + Application.MessageBox(PChar(TextByKey('options-restartnotice')), + ApophysisSVN, MB_ICONWARNING); - Close; + ModalResult := mrOK; // AV: was Close; end; -procedure TOptionsForm.btnDefGradientClick(Sender: TObject); -var - fn:string; +procedure TOptionsForm.btnDefParamsClick(Sender: TObject); begin - OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame|' + TextBykey('common-filter-allfiles') + '|*.*'; + OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame|' + + TextBykey('common-filter-allfiles') + '|*.*'; + OpenDialog.InitialDir := ParamFolder; // AV OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.flame', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtDefParameterFile.text := fn; - end; + if OpenDialog.Execute then + txtDefParameterFile.text := OpenDialog.FileName; end; procedure TOptionsForm.btnDefScriptClick(Sender: TObject); -var - fn:string; begin - OpenDialog.Filter := TextByKey('common-filter-scriptfiles') + '|*.aposcript;*.asc|' + TextBykey('common-filter-allfiles') + '|*.*';; + OpenDialog.Filter := TextByKey('common-filter-scriptfiles') + '|*.aposcript;*.asc|' + + TextBykey('common-filter-allfiles') + '|*.*';; if DirectoryExists(ScriptPath) then OpenDialog.InitialDir := ScriptPath + '\' else OpenDialog.InitialDir := ExtractFilePath(Application.ExeName); OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.asc', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - txtDefScript.Text := fn; + OpenDialog.DefaultExt := 'asc'; + if OpenDialog.Execute then + txtDefScript.Text := OpenDialog.FileName; end; procedure TOptionsForm.FormClose(Sender: TObject; var Action: TCloseAction); @@ -966,31 +961,26 @@ begin finally Registry.Free; end; - end; procedure TOptionsForm.btnSmoothClick(Sender: TObject); -var - fn:string; begin - OpenDialog.Filter := TextByKey('common-filter-gradientfiles') + '|*.gradient;*.ugr|' + TextBykey('common-filter-allfiles') + '|*.*'; + OpenDialog.Filter := TextByKey('common-filter-gradientfiles') +'|*.gradient;*.ugr|' + + TextBykey('common-filter-allfiles') + '|*.*'; OpenDialog.InitialDir := ExtractFilePath(defSmoothPaletteFile); OpenDialog.FileName := ''; OpenDialog.DefaultExt := 'ugr'; - if OpenSaveFileDialog(OptionsForm, OpenDialog.DefaultExt, OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtDefSmoothFile.text := fn; - end; + if OpenDialog.Execute then + txtDefSmoothFile.text := OpenDialog.FileName;; end; -procedure TOptionsForm.btnSShotPathClick(Sender: TObject); +procedure TOptionsForm.btnSShotPathClick(Sender: TObject); // AV var sspath: string; begin sspath := ScreenShotPath; if SelectDirectory(TextByKey('options-tab-environment-screenshotshint'), '', sspath, [sdNewFolder, sdShowEdit, sdNewUI, sdValidateDir], Self) then - txtSShotFolder.Text := sspath + '\'; + txtSShotFolder.Text := IfThen(RightStr(sspath, 1)='\', sspath, sspath + '\'); end; procedure TOptionsForm.cmbSymTypeChange(Sender: TObject); @@ -1122,32 +1112,27 @@ begin end; procedure TOptionsForm.btnRendererClick(Sender: TObject); -var - fn:string; begin - OpenDialog.Filter := TextBykey('common-filter-allfiles') + '|*.*'; - OpenDialog.InitialDir := ExtractFilePath(flam3Path); - OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtRenderer.text := fn; - end; - + OpenDialog.Filter := TextBykey('common-filter-allfiles') + '|*.exe'; + if FileExists(flam3Path) then + OpenDialog.InitialDir := ExtractFilePath(flam3Path) + else + OpenDialog.InitialDir := GetEnvironmentVariable('PROGRAMFILES'); + OpenDialog.FileName := 'flam3-render.exe'; // AV + OpenDialog.DefaultExt := 'exe'; // AV + if OpenDialog.Execute then + txtRenderer.Text := OpenDialog.FileName; end; -procedure TOptionsForm.SpeedButton2Click(Sender: TObject); -var - fn:string; +procedure TOptionsForm.btnDefLibraryClick(Sender: TObject); begin - OpenDialog.Filter := TextByKey('common-filter-scriptfiles') + '|*.aposcript;*.asc|' + TextBykey('common-filter-allfiles') + '|*.*';; + OpenDialog.Filter := TextByKey('common-filter-scriptfiles') + '|*.aposcript;*.asc|' + + TextBykey('common-filter-allfiles') + '|*.*'; OpenDialog.InitialDir := ExtractFilePath(defLibrary); OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.asc', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtLibrary.text := fn; - end; + OpenDialog.DefaultExt := '.asc'; + if OpenDialog.Execute then + txtLibrary.Text := OpenDialog.FileName; end; procedure TOptionsForm.TilePanelDblClick(Sender: TObject); @@ -1169,27 +1154,28 @@ begin cbNrTheads.Items.Add(IntToStr(i)); except cbNrTheads.Items.Clear; - for i := 1 to 12 do + for i := 1 to 12 do cbNrTheads.Items.Add(IntToStr(i)); end; - UseNrThreads := cbNrTheads.Items.Count; + UseNrThreads := cbNrTheads.Items.Count; // save nr processor cores btnOK.Caption := TextByKey('common-ok'); btnCancel.Caption := TextByKey('common-cancel'); pnlLowQ.Caption := TextByKey('common-lowquality'); pnlMediumQ.Caption := TextByKey('common-mediumquality'); pnlHighQ.Caption := TextByKey('common-highquality'); - btnDefGradient.Hint := TextByKey('common-browse'); - btnSmooth.Hint := btnDefGradient.Hint; - SpeedButton2.Hint := btnDefGradient.Hint; - btnRenderer.Hint := btnDefGradient.Hint; - btnHelp.Hint := btnDefGradient.Hint; - btnPluginPath.Hint := btnDefGradient.Hint; - btnSShotPath.Hint := btnDefGradient.Hint; - btnChaotica.Hint := btnDefGradient.Hint; - btnFindDefaultSaveFile.Hint := btnDefGradient.Hint; - btnBrowseSound.Hint := btnDefGradient.Hint; - btnDefScript.Hint := btnDefGradient.Hint; + btnDefParams.Hint := TextByKey('common-browse'); + btnSmooth.Hint := btnDefParams.Hint; + btnDefLibrary.Hint := btnDefParams.Hint; + btnRenderer.Hint := btnDefParams.Hint; + btnHelp.Hint := btnDefParams.Hint; + btnPluginPath.Hint := btnDefParams.Hint; + btnSShotPath.Hint := btnDefParams.Hint; + btnChaotica.Hint := btnDefParams.Hint; + btnFindDefaultSaveFile.Hint := btnDefParams.Hint; + btnBrowseSound.Hint := btnDefParams.Hint; + btnDefScript.Hint := btnDefParams.Hint; + btnLanguage.Hint := btnDefParams.Hint; Panel37.Caption := TextByKey('common-width'); Panel38.Caption := TextByKey('common-height'); Panel31.Caption := TextByKey('common-filename'); @@ -1223,11 +1209,12 @@ begin Label49.Caption := TextByKey('common-minutes'); Panel47.Caption := TextByKey('common-filename'); Panel50.Caption := TextByKey('options-tab-general-pluginpath'); - //Panel49.Caption := TextByKey('common-filename') + ' (x64)'; Panel48.Caption := TextByKey('options-tab-editor-previewtransparency'); + gbDefaults.Caption := TextByKey('options-tab-general-defaults'); + gbGradDefaults.Caption := TextByKey('options-tab-general-defaults'); + gbNotifications.Caption := TextByKey('options-tab-general-notifications'); pnlScreenShot.Caption := TextByKey('options-tab-environment-screenshots'); pnlScriptFile.Caption := TextByKey('options-tab-environment-defaultscript'); - cbC64.Caption := TextByKey('options-tab-environment-usex64chaotica'); chkEnableEditorPreview.Caption := TextByKey('options-tab-editor-enablepreview'); chkAutoSaveXML.Caption := TextByKey('options-tab-general-autosavepasted'); self.Caption := TextByKey('options-title'); @@ -1235,7 +1222,6 @@ begin Panel46.Caption := TextByKey('options-tab-general-language'); pnlMultithreading.Caption := TextByKey('options-tab-general-multithreading'); cbNrTheads.Items[0] := TextByKey('options-tab-general-multithreading-off'); - //pnlBufferDepth.Caption := TextByKey('options-tab-general-bufferdepth'); pnlJPEGQuality.Caption := TextByKey('options-tab-general-jpegquality'); pnlPNGTransparency.Caption := TextByKey('options-tab-general-pngtransparency'); chkShowRenderStats.Caption := TextByKey('options-tab-general-showextendedstatistics'); @@ -1244,11 +1230,12 @@ begin chkConfirmExit.Caption := TextByKey('options-tab-general-confirmexit'); chkconfirmStopRender.Caption := TextByKey('options-tab-general-confirmrenderstop'); chkConfirmClearScript.Caption := TextByKey('options-tab-general-confirmclearscript'); + chkConfirmResetUndo.Caption := TextByKey('options-tab-general-confirmresetundo'); chkOldPaletteFormat.Caption := TextByKey('options-tab-general-oldgradientformat'); cbUseTemplate.Caption := TextByKey('options-tab-general-alwaysblankflame'); chkEqualStripes.Caption := TextByKey('options-tab-gradient-equalstripes'); cbMissingplugin.Caption := TextByKey('options-tab-general-enablemissingpluginswarning'); - cbEmbedThumbs.Caption := TextByKey('options-tab-general-enablethumbnailembedding'); + // cbEmbedThumbs.Caption := TextByKey('options-tab-general-enablethumbnailembedding'); chkEngLayout.Caption := TextByKey('options-tab-general-setenglayout'); chkRandomTemplates.Caption := TextByKey('options-tab-general-templaterandcolor'); chkApplyFlatten.Caption := TextByKey('options-tab-general-autoflatten'); @@ -1347,7 +1334,6 @@ begin chkRememberLastOpen.Caption := TextByKey('options-tab-environment-rememberlastopen'); cbEnableAutosave.Caption := TextByKey('options-tab-environment-autosave'); panel45.Caption := TextByKey('options-tab-environment-savefrequency'); - //cbSinglePrecision.Caption := TextByKey('options-tab-general-singleprecision'); grpEditorColors.Caption := TextByKey('editor-tab-color-title'); GroupBox15.Caption := TextByKey('options-tab-general-onrendercomplete'); chkPlaySound.Caption := TextByKey('options-tab-general-playsound'); @@ -1359,18 +1345,19 @@ begin pnSTile.Caption := TextByKey('main-menu-flame-squaretile'); GroupBox7.Caption := TextByKey('options-tab-display-tileradius'); pnlRandBackground.Caption := TextByKey('options-tab-editor-backgroundcolor'); + chkSyncTriangles.Caption := TextByKey('options-tab-editor-synctriangles'); + + gbAnimation.Caption := TextByKey('animate-animation'); + pnlFPS.Caption := TextByKey('animate-fps'); + pnlAnimPrefix.Caption := TextByKey('animate-prefix'); + pnlFrameExt.Caption := TextByKey('animate-graphicext'); + chkCreateAnimFolder.Caption := TextByKey('options-tab-general-createanimdir') ; for i:= 0 to NRVAR - 1 do begin clbVarEnabled.Items.Add(varnames(i)); clbVarFavourite.Items.Add(varnames(i)); // AV end; - if not CheckX64 then // AV - begin - cbc64.Enabled := false; - UseX64IfPossible := false; - end; - Tabs.ActivePageIndex := 0; // AV VarsPages.ActivePageIndex := 0; // AV end; @@ -1516,11 +1503,11 @@ begin OpenDialog.InitialDir := ExtractFilePath(RenderCompleteSoundFile); OpenDialog.Filter := 'Waveform files (*.wav)|*.wav'; OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.wav', OpenDialog.Filter, OpenDialog.InitialDir, - TextByKey('common-openwav'), fn, true, false, false, true) then - begin - txtSoundFile.text := fn; - end; + OpenDialog.DefaultExt := 'wav'; + OpenDialog.Title := TextByKey('common-openwav'); + if OpenDialog.Execute then + txtSoundFile.text := OpenDialog.FileName; + OpenDialog.Title := ''; // AV: reset caption to default "Open..." end; procedure TOptionsForm.btnPlayClick(Sender: TObject); @@ -1554,17 +1541,14 @@ begin end; procedure TOptionsForm.btnGradientsFileClick(Sender: TObject); -var - fn:string; begin - OpenDialog.Filter := TextByKey('common-filter-gradientfiles') + '|*.gradient;*.ugr|' + TextBykey('common-filter-allfiles') + '|*.*'; + OpenDialog.Filter := TextByKey('common-filter-gradientfiles') + '|*.gradient;*.ugr|' + + TextBykey('common-filter-allfiles') + '|*.*'; OpenDialog.InitialDir := ExtractFilePath(randGradientFile); OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.ugr', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtGradientsFile.text := fn; - end; + OpenDialog.DefaultExt := 'ugr'; + if OpenDialog.Execute then + txtGradientsFile.text := OpenDialog.FileName; end; procedure TOptionsForm.shBackgroundMouseUp(Sender: TObject; @@ -1632,10 +1616,10 @@ begin if chkRememberLastOpen.Checked then begin txtDefParameterFile.Enabled := false; txtDefParameterFile.Text := ''; //LastOpenFile; - btnDefGradient.Enabled := false; + btnDefParams.Enabled := false; end else begin txtDefParameterFile.Enabled := true; - btnDefGradient.Enabled := true; + btnDefParams.Enabled := true; end; Panel39.Enabled := txtDefParameterFile.Enabled; @@ -1645,15 +1629,12 @@ begin end; procedure TOptionsForm.btnFindDefaultSaveFileClick(Sender: TObject); -var fn:string; begin - OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame|' + TextBykey('common-filter-allfiles') + '|*.*'; + OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame|' + + TextBykey('common-filter-allfiles') + '|*.*'; OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '.flame', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, false, false, false, false) then - //if OpenDialog.Execute then - begin - txtDefaultSaveFile.text := fn; - end; + if OpenDialog.Execute then + txtDefaultSaveFile.Text := OpenDialog.FileName; end; procedure TOptionsForm.cbEnableAutosaveClick(Sender: TObject); @@ -1671,17 +1652,13 @@ begin end; procedure TOptionsForm.btnHelpClick(Sender: TObject); -var - fn:string; begin OpenDialog.Filter := TextBykey('common-filter-allfiles') + '|*.*'; OpenDialog.InitialDir := ExtractFilePath(helpPath); OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - txtHelp.text := fn; - end; + OpenDialog.DefaultExt := ''; + if OpenDialog.Execute then + txtHelp.text := OpenDialog.FileName; end; procedure TOptionsForm.btnInvertClick(Sender: TObject); @@ -1712,21 +1689,22 @@ begin else pnlGoldenRatio.Font.Color := clGrayText; end; -procedure TOptionsForm.SpeedButton1Click(Sender: TObject); +procedure TOptionsForm.btnLanguageClick(Sender: TObject); var fn, fn2, s1, s2:string; i : integer; begin OpenDialog.Filter := 'Extensible Markup Language Files (*.xml)|*.xml'; OpenDialog.InitialDir := ExtractFilePath(helpPath); OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then + OpenDialog.DefaultExt := ''; + if OpenDialog.Execute then begin - fn2 := ExtractFilePath(Application.ExeName) + 'Languages\' + ExtractFileName(fn); + fn := OpenDialog.FileName; // AV + fn2 := AppPath + 'Languages\' + ExtractFileName(fn); LanguageInfo(fn, s1, s2); if s1 <> '' then begin - if not DirectoryExists(ExtractFilePath(Application.ExeName) + 'Languages\') then - CreateDirectory(PChar(ExtractFilePath(Application.ExeName) + 'Languages\'), nil); - if (lowercase(ExtractFilePath(fn)) <> lowercase(ExtractFilePath(Application.ExeName) + 'Languages\')) then + if not DirectoryExists(AppPath + 'Languages\') then + CreateDir(AppPath + 'Languages\'); + if (lowercase(ExtractFilePath(fn)) <> lowercase(AppPath + 'Languages\')) then CopyFile(PChar(fn), PChar(fn2), False); AvailableLanguages.Add(fn2); i := AvailableLanguages.Count - 1; @@ -1734,42 +1712,26 @@ begin s1 := s2 + ' (' + s1 + ')'; txtLanguageFile.Items.Add(s1); txtLanguageFile.ItemIndex := txtLanguageFile.Items.Count - 1; - end else begin - Application.MessageBox(PChar(TextByKey('common-invalidformat')), PChar('Apophysis'), MB_ICONERROR); - end; + end else + raise Exception.Create(TextByKey('common-invalidformat')); // AV end; end; procedure TOptionsForm.btnChaoticaClick(Sender: TObject); var fn: string; begin - - // new b. 1550 fn := ChaoticaPath; if SelectDirectory(fn, [sdAllowCreate, sdPerformCreate, sdPrompt], 0) then begin txtChaotica.Text := fn; if not FileExists(fn + '\chaotica.exe') then begin - MessageBox(0, - PCHAR('Could not find "' + fn + '\chaotica.exe" - invalid Chaotica 0.45+ path'), - PCHAR('Apophysis AV'), MB_ICONHAND or MB_OK); + MessageBox(0, PCHAR(TextByKey('main-status-nochaotica')), + ApophysisSVN, MB_ICONHAND or MB_OK); txtChaotica.Text := ChaoticaPath; fn := ChaoticaPath; end; end; - {OpenDialog.Filter := TextBykey('common-filter-allfiles') + '|*.*'; - if sender = TSpeedButton(btnChaotica) then - OpenDialog.InitialDir := ExtractFilePath(ChaoticaPath) - else - OpenDialog.InitialDir := ExtractFilePath(ChaoticaPath64); - OpenDialog.FileName := ''; - if OpenSaveFileDialog(OptionsForm, '', OpenDialog.Filter, OpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then - //if OpenDialog.Execute then - begin - if sender = TSpeedButton(btnChaotica) then txtChaotica.text := fn - else txtChaotica64.text := fn; - end; } end; procedure TOptionsForm.chkEnableEditorPreviewClick(Sender: TObject); diff --git a/Forms/Preview.pas b/Forms/Preview.pas index 2f1b3d1..a8dedcf 100644 --- a/Forms/Preview.pas +++ b/Forms/Preview.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,8 +27,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - ExtCtrls, ControlPoint, RenderingInterface, Translation, Vcl.Menus, - Vcl.Imaging.PNGimage; + ExtCtrls, ControlPoint, RenderingInterface, Vcl.Menus, Vcl.Imaging.PNGimage; type TPreviewForm = class(TForm) @@ -57,7 +56,7 @@ var implementation -uses Main, Global, ScriptForm; +uses Main, Global, ScriptForm, Translation; {$R *.DFM} @@ -100,26 +99,27 @@ end; procedure TPreviewForm.MakeScreenShotClick(Sender: TObject); var - s: string; - pic: TPNGObject; + s, t: string; + pic: TPNGImage; begin if not DirectoryExists(ScreenShotPath) then begin CreateDir(AppPath + 'ScreenShots\'); ScreenShotPath := AppPath + 'ScreenShots\'; end; - s := ScreenShotPath + 'Apophysis Animation Preview' + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now) + '.bmp'; + t := FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now); + s := ScreenShotPath + 'Apophysis Animation Preview' + t + '.bmp'; try if KeepFrame.Checked then GetFormScreenShot(s) else begin try - pic := TPNGObject.Create; + pic := TPNGImage.Create; try pic.Assign(Image.Picture.Bitmap); - if cp.name = '' then cp.name := RemoveExt(s); - pic.AddtEXt('ApoFlame', AnsiString(Trim(MainForm.RetrieveXML(cp)))); + if cp.name = '' then cp.name := RemoveExt(s) + t; + pic.AddtEXt('ApoFlame', AnsiString(Trim(FlameToXML(cp)))); s := ChangeFileExt(s, '.png'); pic.SaveToFile(s); finally @@ -130,9 +130,9 @@ begin end; end; Application.MessageBox(PChar(Format(TextByKey('common-screenshot-saved'), - [ExtractFileName(s), ExtractFilePath(s)])), PChar('Apophysis AV'), MB_ICONINFORMATION); + [ExtractFileName(s), ExtractFilePath(s)])), ApophysisSVN, MB_ICONINFORMATION); except - Application.MessageBox(PChar(TextByKey('common-screenshot-error')), PChar('Apophysis AV'), MB_ICONERROR); + Application.MessageBox(PChar(TextByKey('common-screenshot-error')), ApophysisSVN, MB_ICONERROR); end; end; diff --git a/Forms/Save.dfm b/Forms/Save.dfm index 93f012d..7d75575 100644 --- a/Forms/Save.dfm +++ b/Forms/Save.dfm @@ -3,8 +3,8 @@ object SaveForm: TSaveForm Top = 432 BorderStyle = bsDialog Caption = 'Save Parameters' - ClientHeight = 153 - ClientWidth = 517 + ClientHeight = 197 + ClientWidth = 528 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText @@ -16,17 +16,16 @@ object SaveForm: TSaveForm OnCreate = FormCreate OnShow = FormShow DesignSize = ( - 517 - 153) + 528 + 197) PixelsPerInch = 120 TextHeight = 16 object btnDefGradient: TSpeedButton - Left = 480 - Top = 9 + Left = 485 + Top = 8 Width = 30 Height = 29 Hint = 'Browse...' - Anchors = [akTop, akRight] Flat = True Font.Charset = ANSI_CHARSET Font.Color = clWindowText @@ -65,31 +64,10 @@ object SaveForm: TSaveForm ShowHint = True OnClick = btnDefGradientClick end - object btnSave: TButton - Left = 310 - Top = 116 - Width = 93 - Height = 30 - Anchors = [akRight, akBottom] - Caption = '&Save' - Default = True - TabOrder = 2 - OnClick = btnSaveClick - end - object btnCancel: TButton - Left = 410 - Top = 116 - Width = 92 - Height = 30 - Anchors = [akRight, akBottom] - Caption = 'Cancel' - TabOrder = 3 - OnClick = btnCancelClick - end object pnlTarget: TPanel Left = 10 Top = 10 - Width = 124 + Width = 120 Height = 26 Cursor = crArrow BevelOuter = bvLowered @@ -102,7 +80,7 @@ object SaveForm: TSaveForm object pnlName: TPanel Left = 10 Top = 39 - Width = 124 + Width = 120 Height = 26 Cursor = crArrow BevelOuter = bvLowered @@ -112,42 +90,62 @@ object SaveForm: TSaveForm TabOrder = 5 end object txtFilename: TEdit - Left = 128 + Left = 130 Top = 10 Width = 353 Height = 24 - Anchors = [akLeft, akTop, akRight] TabOrder = 0 Text = 'txtFilename' end object txtTitle: TEdit - Left = 128 + Left = 130 Top = 39 - Width = 383 + Width = 381 Height = 24 - Anchors = [akLeft, akTop, akRight] TabOrder = 1 Text = 'txtTitle' end - object optUseOldFormat: TRadioButton + object pnlComment: TPanel Left = 10 - Top = 79 - Width = 304 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use classic flame format' - Checked = True + Top = 68 + Width = 120 + Height = 26 + Cursor = crArrow + BevelOuter = bvLowered + Caption = 'Comment' + ParentShowHint = False + ShowHint = True TabOrder = 6 - TabStop = True end - object optUseNewFormat: TRadioButton - Left = 10 - Top = 101 - Width = 304 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use new flame format' - Enabled = False + object txtComment: TMemo + Left = 130 + Top = 68 + Width = 381 + Height = 77 + Lines.Strings = ( + '') + ScrollBars = ssBoth TabOrder = 7 end + object btnCancel: TButton + Left = 413 + Top = 159 + Width = 92 + Height = 30 + Anchors = [akRight, akBottom] + Caption = 'Cancel' + TabOrder = 3 + OnClick = btnCancelClick + end + object btnSave: TButton + Left = 305 + Top = 159 + Width = 93 + Height = 30 + Anchors = [akRight, akBottom] + Caption = '&Save' + Default = True + TabOrder = 2 + OnClick = btnSaveClick + end end diff --git a/Forms/Save.pas b/Forms/Save.pas index 4d5fcdb..eb6265f 100644 --- a/Forms/Save.pas +++ b/Forms/Save.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -39,8 +39,8 @@ type btnDefGradient: TSpeedButton; pnlTarget: TPanel; pnlName: TPanel; - optUseOldFormat: TRadioButton; - optUseNewFormat: TRadioButton; + pnlComment: TPanel; + txtComment: TMemo; procedure FormCreate(Sender: TObject); procedure btnSaveClick(Sender: TObject); procedure btnCancelClick(Sender: TObject); @@ -51,6 +51,7 @@ type public Title: string; Filename: string; + Comment: string; SaveType : ESaveType; end; @@ -135,17 +136,17 @@ begin if ((t = '') and txtTitle.Enabled) then begin - Application.MessageBox(PChar(TextByKey('save-status-notitle')), 'Apophysis', 48); + Application.MessageBox(PChar(TextByKey('save-status-notitle')), PChar(ApophysisSVN), 48); Exit; end; if f = '' then begin - Application.MessageBox(PChar(TextByKey('save-status-invalidfilename')), 'Apophysis', 48); + Application.MessageBox(PChar(TextByKey('save-status-invalidfilename')), PChar(ApophysisSVN), 48); Exit; end; if ExtractFileExt(f) = '' then begin - Application.MessageBox(PChar(TextByKey('save-status-invalidfilename')), 'Apophysis', 48); + Application.MessageBox(PChar(TextByKey('save-status-invalidfilename')), PChar(ApophysisSVN), 48); Exit; end; @@ -166,17 +167,22 @@ begin check := EntryExists(t, f); end; - if check then begin if onestr then begin - if Application.MessageBox(PChar(Format(TextByKey('save-status-alreadyexists2'), [f])), - 'Apophysis', 52) = ID_NO then exit; - end else begin - if Application.MessageBox(PChar(Format(TextByKey('save-status-alreadyexists'), [t, f])), - 'Apophysis', 52) = ID_NO then exit; - end end; + if check then begin + if onestr then + begin + if Application.MessageBox(PChar(Format(TextByKey('save-status-alreadyexists2'), [f])), + PChar(ApophysisSVN), 52) = ID_NO then exit; + end + else begin + if Application.MessageBox(PChar(Format(TextByKey('save-status-alreadyexists'), [t, f])), + PChar(ApophysisSVN), 52) = ID_NO then exit; + end + end; if (t = '*') then t := ''; Title := t; Filename := f; + Comment := Trim(txtComment.Lines.Text); ModalResult := mrOK; end; @@ -189,11 +195,9 @@ procedure TSaveForm.FormShow(Sender: TObject); begin txtFilename.Text := Filename; txtTitle.Text := Title; - //btnSave.SetFocus; + txtComment.Lines.Text := Comment; // AV self.Caption := TextByKey(SaveTypeTextKey(SaveType)); - {if (SaveType = stSaveParameters) or (SaveType = stSaveAllParameters) then - self.Height := 160 - else self.Height := 120; } + if (SaveType = stSaveGradient) then // AV pnlName.Caption := TextByKey('save-namepal') else pnlName.Caption := TextByKey('save-name'); @@ -203,8 +207,11 @@ begin if (not txtTitle.Enabled) then pnlName.Font.Color := clGrayText else pnlName.Font.Color := clWindowText; - optUseOldFormat.Visible := (SaveType = stSaveParameters) or (SaveType = stSaveAllParameters); - optUseNewFormat.Visible := (SaveType = stSaveParameters) or (SaveType = stSaveAllParameters); + pnlComment.Visible := (SaveType = stSaveParameters) or (SaveType = stSaveTemplate); + txtComment.Visible := pnlComment.Visible; + if txtComment.Visible then + self.Height := 225 + else self.Height := 160; txtFileName.ReadOnly := (SaveType = stSaveTemplate); // AV end; @@ -234,9 +241,8 @@ begin btnSave.Caption := TextByKey('common-ok'); btnDefGradient.Hint := TextByKey('common-browse'); pnlTarget.Caption := TextByKey('common-destination'); + pnlComment.Caption := TextByKey('common-comment'); //pnlName.Caption := TextByKey('save-name'); - optUseOldFormat.Caption := TextByKey('save-oldformat'); - optUseNewFormat.Caption := TextByKey('save-newformat'); end; end. diff --git a/Forms/SavePreset.dfm b/Forms/SavePreset.dfm index 5f28a48..09d2b27 100644 --- a/Forms/SavePreset.dfm +++ b/Forms/SavePreset.dfm @@ -12,14 +12,15 @@ object SavePresetForm: TSavePresetForm Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False + Position = poDesktopCenter OnCreate = FormCreate DesignSize = ( 349 66) PixelsPerInch = 96 TextHeight = 13 - object Button1: TButton - Left = 190 + object btOK: TButton + Left = 180 Top = 37 Width = 75 Height = 25 @@ -28,10 +29,10 @@ object SavePresetForm: TSavePresetForm Default = True ModalResult = 1 TabOrder = 1 - OnClick = Button1Click + OnClick = btOKClick end - object Button2: TButton - Left = 270 + object btCancel: TButton + Left = 260 Top = 37 Width = 75 Height = 25 diff --git a/Forms/SavePreset.pas b/Forms/SavePreset.pas index 85a3095..9d3be5e 100644 --- a/Forms/SavePreset.pas +++ b/Forms/SavePreset.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -32,11 +32,11 @@ uses type TSavePresetForm = class(TForm) txtPresetName: TEdit; - Button1: TButton; - Button2: TButton; + btOK: TButton; + btCancel: TButton; pnlName: TPanel; procedure FormCreate(Sender: TObject); - procedure Button1Click(Sender: TObject); + procedure btOKClick(Sender: TObject); private { Private declarations } public @@ -50,11 +50,11 @@ implementation {$R *.DFM} -procedure TSavePresetForm.Button1Click(Sender: TObject); +procedure TSavePresetForm.btOKClick(Sender: TObject); begin if txtPresetName.Text = '' then begin - Application.MessageBox(PChar(TextByKey('savepreset-notitle')), 'Apophysis', 48); + Application.MessageBox(PChar(TextByKey('savepreset-notitle')), 'Apophysis AV', 48); Exit; end; end; @@ -62,8 +62,8 @@ end; procedure TSavePresetForm.FormCreate(Sender: TObject); begin self.Caption := TextBykey('savepreset-title'); - button1.Caption := TextByKey('common-ok'); - button2.Caption := TextByKey('common-cancel'); + btOK.Caption := TextByKey('common-ok'); + btCancel.Caption := TextByKey('common-cancel'); pnlName.Caption := TextByKey('savepreset-name'); end; diff --git a/Forms/ScriptForm.dfm b/Forms/ScriptForm.dfm index 9a7c5c9..68180c9 100644 --- a/Forms/ScriptForm.dfm +++ b/Forms/ScriptForm.dfm @@ -766,7 +766,7 @@ object ScriptEditor: TScriptEditor CallExecHookEvent = False Left = 480 Top = 200 - end + end object OpenDialog: TOpenDialog DefaultExt = 'flame' Filter = @@ -994,6 +994,9 @@ object ScriptEditor: TScriptEditor 'procedure Print(data: variant)' 'procedure AddSymmetry(symmetry_type: integer)' + 'procedure PrepareToMorph(Flame1_Num: integer, Flame2_Num: intege' + + 'r)' + 'procedure Morph(Flame1_Num: integer, Flame2_Num: integer, Speed:' + ' double, interp_type: integer = 3)' 'procedure SetRenderBounds' @@ -1076,6 +1079,7 @@ object ScriptEditor: TScriptEditor 'property Name: string' 'property Batches: integer' 'property FinalXformEnabled: boolean' + 'property Comment: string' 'var LimitVibrancy: boolean' 'var DateCode: readonly' 'procedure DecodeDate(date, year, month, day)' @@ -1228,7 +1232,7 @@ object ScriptEditor: TScriptEditor 'procedure Inc(num: integer)' 'function Odd(num: integer): boolean' 'function StringOfChar(symbol: char, count: integer): string' - 'function GetEnvironmentVariable(sys_const: string): string;' + 'function GetEnvironmentVariable(sys_const: string): string' 'const PI' 'const NVARS' 'const NumVariables' diff --git a/Forms/ScriptForm.pas b/Forms/ScriptForm.pas index becf428..9d0ce13 100644 --- a/Forms/ScriptForm.pas +++ b/Forms/ScriptForm.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,9 +27,9 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - ExtCtrls, StdCtrls, ControlPoint, Buttons, ComCtrls, ToolWin, Menus, - XFormMan, XForm, GradientHlpr, cmap,LibXmlParser, LibXmlComps, Math, Translation, - atScript, atPascal, ScripterInit, ScrMemo, Scrmps, ScrCodeList; + ExtCtrls, StdCtrls, ControlPoint, Buttons, ComCtrls, ToolWin, Menus, Math, + XFormMan, XForm, GradientHlpr, cmap, LibXmlParser, LibXmlComps, Translation, + atScript, atPascal, Vcl.ScripterInit, ScrMemo, Scrmps, ScrCodeList; const NCPS = 10; // AV: max number of flames for animation @@ -38,9 +38,17 @@ const type TOptions = class public + { TOptions class is used only as an interface to user's preferencies } end; TFlame = class public + { The TFlame class is used only as an interface. The control point parameters + are read and set directly. Parameter ranges aren't limited but values not + in the correct range are ignored. } + end; + TTransform = class + public + { TTransform class only serves as an interface to active transform } end; TScriptRender = class public @@ -50,6 +58,7 @@ type end; TPivot = class public + { TPivot class only serves as an interface to active transform's pivot point } end; TScriptEditor = class(TForm) MainOpenDialog: TOpenDialog; @@ -68,7 +77,7 @@ type N1: TMenuItem; BackPanel: TPanel; Editor: TScrMemo; - Scripter: TatPascalScripter; + Scripter: TatPascalScripter; Splitter1: TSplitter; Console: TMemo; btnStop: TToolButton; @@ -104,7 +113,6 @@ type ExpandBlocks: TMenuItem; procedure F2SXMLStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); - procedure F2SXMLEndTag(Sender: TObject; TagName: string); procedure F2SXMLEmptyTag(Sender: TObject; TagName: string; Attributes: TAttrList); procedure F2SXMLContent(Sender: TObject; Content: string); @@ -154,25 +162,13 @@ type procedure Editcaption1Click(Sender: TObject); procedure CollapseBlocksClick(Sender: TObject); procedure ExpandBlocksClick(Sender: TObject); - public - cp: TControlPoint; - Stopped: boolean; - cmap: TColorMap; + private + //cmap: TColorMap; Flame: TFlame; + Transform: TTransform; Options: TOptions; Pivot: TPivot; - Renderer: TScriptRender; Another: TScriptRender; - AddedXForms : integer; - chaosLines : TStringList; - procedure LoadRunAndClear(scriptFile:string); - procedure LoadScriptFile(filename:string); - procedure ScriptFromFlame(flameXML:string); - procedure UpdateFlame; - procedure PrepareScripter; - procedure OpenScript; - procedure RunScript; - procedure AdjustScripterColors; { Flame interface } procedure SetFlameNameProc(AMachine: TatVirtualMachine); @@ -213,6 +209,8 @@ type procedure SetFlamePaletteProc(AMachine: TatVirtualMachine); procedure GetFlameBackgroundProc(AMachine: TatVirtualMachine); procedure SetFlameBackgroundProc(AMachine: TatVirtualMachine); + procedure GetFlameCommentProc(AMachine: TatVirtualMachine); + procedure SetFlameCommentProc(AMachine: TatVirtualMachine); // procedure SetFlameNickProc(AMachine: TatVirtualMachine); // procedure GetFlameNickProc(AMachine: TatVirtualMachine); // procedure SetFlameURLProc(AMachine: TatVirtualMachine); @@ -243,7 +241,6 @@ type procedure GetPreviewWidthProc(AMachine: TatVirtualMachine); procedure SetPreviewWidthProc(AMachine: TatVirtualMachine); - { Transform interface } procedure GetTransformAProc(AMachine: TatVirtualMachine); procedure SetTransformAProc(AMachine: TatVirtualMachine); @@ -306,7 +303,7 @@ type procedure TransformRotateProc(AMachine: TatVirtualMachine); procedure TransformScaleProc(AMachine: TatVirtualMachine); procedure TransformRotateOriginProc(AMachine: TatVirtualMachine); - + // AV: added reflections procedure TransformFlipHorizProc(AMachine: TatVirtualMachine); procedure TransformFlipVertProc(AMachine: TatVirtualMachine); @@ -453,39 +450,47 @@ type // AV: moved here from TOperationLibrary procedure CopyFileProc(AMachine: TatVirtualMachine); - end; - TTransform = class public - { Transform class only serves as an - interface to active transform } + cp: TControlPoint; + Stopped: boolean; + Renderer: TScriptRender; + + procedure LoadRunAndClear(scriptFile:string); + procedure LoadScriptFile(filename:string); + procedure ScriptFromFlame(flameXML:string); + procedure UpdateFlame; + procedure PrepareScripter; + procedure OpenScript; + procedure RunScript; + procedure AdjustScripterColors; end; // TMatrix = array[0..2, 0..2] of double; // AV: we already have such a type + EFormatInvalid = class(Exception); var ScriptEditor: TScriptEditor; - LastParseError: string; - NumTransforms: integer; // Keeps track of number of xforms in flame. - ActiveTransform: integer; // Operations affect this transform. + ScFileList: TStringList; // AV: renamed due to sporadic name-space conflicts LastError: string; - color: double; - cps: array[0..NCPS - 1] of TControlPoint; - Transform: TTransform; - Stopped, ResetLocation, UpdateIt: Boolean; - ParamFile: string; - FileList: TStringList; - ErrorOutOfRange, RTError, DTError: string; // AV implementation -uses Main, Editor, Adjust, Global, Mutate, Registry, Preview, LoadTracker, - ScriptRender, ap_math, ap_classes, ap_sysutils, ap_Dialogs, - SavePreset, ap_windows, ap_FileCtrl, ap_Forms(*, bmdll32*); +uses + Main, Editor, Adjust, Global, Mutate, Registry, Preview, LoadTracker, + ScriptRender, ap_math, ap_classes, ap_sysutils, ap_Dialogs, ap_windows, + ap_FileCtrl, ap_Forms; {$R *.DFM} -//const -// ErrorOutOfRange = 'Transform out of range!'; +var + ErrorOutOfRange, RTError, DTError: string; // AV + chaosLines : TStringList; + cps: array[0..NCPS - 1] of TControlPoint; + ResetLocation, UpdateIt: Boolean; + NumTransforms: integer; // Keeps track of number of xforms in flame. + ActiveTransform: integer; // Operations affect this transform. + ParamFile: string; + AddedXForms : integer; type TOperationLibrary = class(TatScripterLibrary) @@ -512,6 +517,7 @@ type procedure ClearProc(AMachine: TatVirtualMachine); procedure PreviewProc(AMachine: TatVirtualMachine); procedure Print(AMachine: TatVirtualMachine); + procedure PrepareToMorphProc(AMachine: TatVirtualMachine); // AV procedure MorphProc(AMachine: TatVirtualMachine); procedure RenderProc(AMachine: TatVirtualMachine); procedure AddSymmetryProc(AMachine: TatVirtualMachine); @@ -569,9 +575,9 @@ begin xml.Normalize := True; xml.OnContent := F2SXMLContent; // AV: temporary unused xml.OnEmptyTag := F2SXMLEmptyTag; - xml.OnEndTag := F2SXMLEndTag; + // xml.OnEndTag := F2SXMLEndTag; xml.OnStartTag := F2SXMLStartTag; - xml.LoadFromBuffer(TCharType(TStringType(flameXML))); // AV: changed from ANSI + xml.LoadFromBuffer(PAnsiChar(Utf8String(flameXML))); xml.Execute; xml.Destroy; @@ -774,7 +780,7 @@ begin with AMachine do begin v := GetInputArgAsFloat(0); - if (v >= 0.1) and (v <= 100) then defGamma := v; + if (v >= 0.1) and (v <= 10) then defGamma := v; end; end; @@ -1486,6 +1492,7 @@ begin Scripter.DefineMethod('Render', 0, tkNone, nil, RenderProc); Scripter.DefineMethod('Print', 1, tkNone, nil, Print); Scripter.DefineMethod('AddSymmetry', 1, tkNone, nil, AddSymmetryProc); + Scripter.DefineMethod('PrepareToMorph', 2, tkNone, nil, PrepareToMorphProc); // AV Scripter.DefineMethod('Morph', 4, tkNone, nil, MorphProc, false, 1); Scripter.DefineMethod('SetRenderBounds', 0, tkNone, nil, SetRenderBounds); Scripter.DefineMethod('SetFlameFile', 1, tkNone, nil, SetParamFileProc); @@ -1497,7 +1504,7 @@ begin Scripter.DefineMethod('RandomGradient', 0, tkNone, nil, RandomGradientProc); Scripter.DefineMethod('PresetGradient', 1, tkNone, nil, PresetGradientProc); // AV Scripter.DefineMethod('SaveGradient', 2, tkNone, nil, SaveGradientProc); - Scripter.DefineMethod('Variation', 0, tkInteger, nil, GetVariation); // AV: ? + Scripter.DefineMethod('Variation', 0, tkInteger, nil, GetVariation); // AV: fixed Scripter.DefineMethod('SetVariation', 1, tkInteger, nil, SetVariation); // AV: fixed Scripter.AddConstant('ProgramVersionString', AppVersionString); @@ -1537,7 +1544,7 @@ begin for i := 0 to NXFORMS - 1 do if ScriptEditor.cp.xform[i].density = 0 then break; NumTransforms := i; - except on E: EMathError do + except on EMathError do end; end; @@ -1571,10 +1578,13 @@ begin end; procedure TOperationLibrary.CalculateColors(AMachine: TatVirtualMachine); -var i: integer; +var i: smallint; begin + if NumTransforms > 1 then // fixed divide-by-zero bug for i := 0 to NumTransforms-1 do - ScriptEditor.cp.xform[i].color := i / (NumTransforms-1); + ScriptEditor.cp.xform[i].color := i / (NumTransforms-1) + else + ScriptEditor.cp.xform[0].color := 0; end; procedure TOperationLibrary.CalculateWeights(AMachine: TatVirtualMachine); @@ -1583,14 +1593,14 @@ begin end; procedure TOperationLibrary.RandomizeColors(AMachine: TatVirtualMachine); -var i: integer; +var i: smallint; begin for i := 0 to NumTransforms-1 do ScriptEditor.cp.xform[i].color := random; end; procedure TOperationLibrary.RandomizeColorSpeed(AMachine: TatVirtualMachine); -var i: integer; +var i: smallint; begin for i := 0 to NumTransforms-1 do ScriptEditor.cp.xform[i].symmetry := 2 * random - 1; @@ -1601,9 +1611,18 @@ begin ScriptEditor.cp.CalculateColorSpeed; end; -procedure TOperationLibrary.RandomizeWeights(AMachine: TatVirtualMachine); +procedure TOperationLibrary.EqualizeWeights(AMachine: TatVirtualMachine); +var i: smallint; begin - ScriptEditor.cp.RandomizeWeights; + for i := 0 to NumTransforms-1 do + ScriptEditor.cp.xform[i].density := 0.5; +end; + +procedure TOperationLibrary.RandomizeWeights(AMachine: TatVirtualMachine); +var i: smallint; +begin + for i := 0 to NumTransforms-1 do + ScriptEditor.cp.xform[i].density := random; end; procedure TOperationLibrary.NormalizeWeights(AMachine: TatVirtualMachine); @@ -1611,13 +1630,9 @@ begin ScriptEditor.cp.NormalizeProbabilities; end; -procedure TOperationLibrary.EqualizeWeights(AMachine: TatVirtualMachine); -begin - ScriptEditor.cp.EqualizeWeights; -end; - procedure TOperationLibrary.SetRenderBounds(AMachine: TatVirtualMachine); begin + // AV: it actually does nothing special... just waste of time ScriptRenderForm.SetRenderBounds; end; @@ -1726,16 +1741,17 @@ begin LastError := 'SetFlameFile: ' + TextByKey('common-noparamfile'); AMachine.RuntimeError(LastError); // AV AMachine.Halt; - if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV + if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV end; end; procedure TOperationLibrary.RotateProc(AMachine: TatVirtualMachine); begin try - if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then raise EFormatInvalid.Create(ErrorOutOfRange); - with AMachine do - ScriptEditor.cp.xform[ActiveTransform].Rotate(GetInputArgAsFloat(0)); + if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then + raise EFormatInvalid.Create(ErrorOutOfRange); + with ScriptEditor.cp.xform[ActiveTransform] do + Rotate(c, AMachine.GetInputArgAsFloat(0)); except on E: EFormatInvalid do begin // ScriptEditor.Console.Lines.Add('Rotate: ' + E.message); @@ -1747,27 +1763,20 @@ end; procedure TOperationLibrary.MulPXProc(AMachine: TatVirtualMachine); -var k, m, l, n, pa, pb, pc, pd: double; +var k, m, l, n: double; begin try - if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then raise EFormatInvalid.Create(ErrorOutOfRange); - with AMachine do - begin - k := GetInputArgAsFloat(0); - m := GetInputArgAsFloat(1); - l := GetInputArgAsFloat(2); - n := GetInputArgAsFloat(3); - end; - with ScriptEditor.cp.xform[ActiveTransform] do begin - pa := p[0,0]; - pb := -p[1,0]; - pc := -p[0,1]; - pd := p[1,1]; - p[0,0] := pa * k + pc * l; - p[0,1] := -(pa * m + pc * n); - p[1,0] := -(pb * k + pd * l); - p[1,1] := pb * m + pd * n; + if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then + raise EFormatInvalid.Create(ErrorOutOfRange); + with AMachine do + begin + k := GetInputArgAsFloat(0); + m := GetInputArgAsFloat(1); + l := GetInputArgAsFloat(2); + n := GetInputArgAsFloat(3); end; + with ScriptEditor.cp.xform[ActiveTransform] do + Multiply(p, k, l, m, n); // AV: my common method for both matrices except on E: EFormatInvalid do begin // ScriptEditor.Console.Lines.Add('MultiplyPX: ' + E.message); @@ -1778,33 +1787,23 @@ begin end; procedure TOperationLibrary.MulProc(AMachine: TatVirtualMachine); -var k, m, l, n, ca, cb, cc, cd: double; +var k, m, l, n: double; begin - if ScriptEditor.cp.xform[ActiveTransform].postXswap then - begin - MulPXProc(AMachine); - Exit; - end; try if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then raise EFormatInvalid.Create(ErrorOutOfRange); with AMachine do // ScriptEditor.cp.xform[ActiveTransform].Multiply(GetInputArgAsFloat(0), GetInputArgAsFloat(1), GetInputArgAsFloat(2), GetInputArgAsFloat(3)); begin - k := GetInputArgAsFloat(0); - m := GetInputArgAsFloat(1); - l := GetInputArgAsFloat(2); - n := GetInputArgAsFloat(3); - end; - with ScriptEditor.cp.xform[ActiveTransform] do begin - ca := c[0,0]; - cb := -c[1,0]; - cc := -c[0,1]; - cd := c[1,1]; - c[0,0] := ca * k + cc * l; - c[0,1] := -(ca * m + cc * n); - c[1,0] := -(cb * k + cd * l); - c[1,1] := cb * m + cd * n; + k := GetInputArgAsFloat(0); + m := GetInputArgAsFloat(1); + l := GetInputArgAsFloat(2); + n := GetInputArgAsFloat(3); end; + with ScriptEditor.cp.xform[ActiveTransform] do + if postXswap then + Multiply(p, k, l, m, n) // AV: my common method for both matrices + else + Multiply(c, k, l, m, n); except on E: EFormatInvalid do begin // ScriptEditor.Console.Lines.Add('Multiply: ' + E.message); @@ -1829,15 +1828,15 @@ end; procedure TOperationLibrary.SaveFlameProc(AMachine: TatVirtualMachine); var - filename: string; + filename, ext: string; begin with AMachine do begin filename := GetInputArgAsString(0); - (*if (LowerCase(ExtractFileExt(filename)) = '.apo') or - (LowerCase(ExtractFileExt(filename)) = '.fla') then + ext := LowerCase(ExtractFileExt(filename)); + if (ext = '.apo') or (ext = '.fla') then // AV MainForm.SaveFlame(ScriptEditor.cp, ScriptEditor.cp.name, filename) - else *) + else MainForm.SaveXMLFlame(ScriptEditor.cp, ScriptEditor.cp.name, filename) end; end; @@ -1845,21 +1844,23 @@ end; procedure TOperationLibrary.SaveGradientProc(AMachine: TatVirtualMachine); var gradstr: TStringList; + gradname: string; begin gradstr := TStringList.Create; try - gradstr.add(CleanIdentifier(AMachine.GetInputArgAsString(1)) + ' {'); - gradstr.add(MainForm.GradientFromPalette(ScriptEditor.cp.cmap, AMachine.GetInputArgAsString(1))); + gradname := AMachine.GetInputArgAsString(1); // AV + gradstr.add(CleanIdentifier(gradname) + ' {'); + gradstr.add(MainForm.GradientFromPalette(ScriptEditor.cp.cmap, gradname)); gradstr.add('}'); - MainForm.SaveGradient(gradstr.text, AMachine.GetInputArgAsString(1), AMachine.GetInputArgAsString(0)) + MainForm.SaveGradient(gradstr.text, gradname, AMachine.GetInputArgAsString(0)); finally - gradstr.free + gradstr.free; end; end; procedure TOperationLibrary.ListFileProc(AMachine: TatVirtualMachine); var - flafile: string; + flafile, ext: string; i: integer; begin flafile := AMachine.GetInputArgAsString(0); @@ -1867,17 +1868,15 @@ begin begin OpenFile := flafile; MainForm.Caption := AppVersionString + ' - ' + OpenFile; - (*if (LowerCase(ExtractFileExt(flafile)) = '.apo') or - (LowerCase(ExtractFileExt(flafile)) = '.undo') then - begin - ListIFS(OpenFile, 1); - OpenFileType := ftFla + ext := LowerCase(ExtractFileExt(flafile)); + if (ext = '.apo') or (ext = '.undo') then begin + OpenFileType := ftApo; + ListIFS(OpenFile, 1); end - else - begin*) - ListXML(OpenFile, 1); + else begin OpenFileType := ftXML; - //end; + ListXML(OpenFile, 1); + end; MainForm.SetFocus; end else @@ -1901,7 +1900,7 @@ begin v := AMachine.GetInputArgAsInteger(0); if (v >= 0) and (v < NCPS) then begin - cps[v].copy(ScriptEditor.cp); + cps[v].copy(ScriptEditor.cp); // <-- AV: optimized for speed cps[v].cmap := ScriptEditor.cp.cmap; end else begin @@ -1915,22 +1914,25 @@ end; procedure TOperationLibrary.GetFlameProc(AMachine: TatVirtualMachine); var - i, v: integer; + i, j: integer; begin - v := AMachine.GetInputArgAsInteger(0); - if (v >= 0) and (v < NCPS) then + j := AMachine.GetInputArgAsInteger(0); + if (j >= 0) and (j < NCPS) then begin - ScriptEditor.cp.copy(cps[v]); - ScriptEditor.cp.cmap := cps[v].cmap; - - for i := 0 to NXFORMS - 1 do - if ScriptEditor.cp.xform[i].density = 0 then break; - NumTransforms := i; + ScriptEditor.cp.copy(cps[j]); // <-- AV: optimized for speed + ScriptEditor.cp.cmap := cps[j].cmap; + + for i := 0 to NXFORMS - 1 do + if ScriptEditor.cp.xform[i].density = 0 then break; + NumTransforms := i; + + // AV: added a special method for easy gradient animation + RotateCMapHue(ScriptEditor.cp); end else begin - LastError := 'GetFlame(' + IntToStr(v) + '): ' + TextByKey('script-status-varoutofrange'); - ScriptEditor.Editor.ActiveLine := - LineNumberFromInstruction(AMachine.CurrentInstruction); // AV + LastError := 'GetFlame(' + IntToStr(j) + '): ' + TextByKey('script-status-varoutofrange'); + ScriptEditor.Editor.ActiveLine := + LineNumberFromInstruction(AMachine.CurrentInstruction); // AV ScriptEditor.Editor.ActiveLineSettings.ShowActiveLine := true; // AV AMachine.Halt; end; @@ -1940,13 +1942,10 @@ procedure LoadXMLFlame(index: integer); var FStrings: TStringList; IFSStrings: TStringList; - EntryStrings, Tokens: TStringList; i: integer; begin FStrings := TStringList.Create; IFSStrings := TStringList.Create; - Tokens := TStringList.Create; - EntryStrings := TStringList.Create; try FStrings.LoadFromFile(ParamFile); @@ -1954,9 +1953,9 @@ begin begin if Pos(' 0; ScriptEditor.cp.Clear; // initialize control point for new flame; ScriptEditor.cp.background[0] := 0; ScriptEditor.cp.background[1] := 0; @@ -2011,57 +1986,27 @@ begin ScriptEditor.cp.sample_density := defSampleDensity; ScriptEditor.cp.spatial_oversample := defOversample; ScriptEditor.cp.spatial_filter_radius := defFilterRadius; - for i := 0 to FStrings.count - 1 do - begin - if Pos(Lowercase(FileList[index]) + ' ', Trim(Lowercase(FStrings[i]))) = 1 then - break; - end; - inc(i); - while (Pos('}', FStrings[i]) = 0) and (Pos('palette:', FStrings[i]) = 0) do - begin - EntryStrings.Add(FStrings[i]); - inc(i); - end; - if Pos('palette:', FStrings[i]) = 1 then - begin - SavedPal := True; - inc(i); - for j := 0 to 255 do begin - s := FStrings[i]; - GetTokens(s, Tokens); - Palette[j][0] := StrToInt(Tokens[0]); - Palette[j][1] := StrToInt(Tokens[1]); - Palette[j][2] := StrToInt(Tokens[2]); - inc(i); - end; - end; - FlameString := EntryStrings.Text; - ScriptEditor.cp.ParseString(FlameString); + + FlameFromUndo(ScriptEditor.cp, ScFileList[index], ParamFile); // AV + for i := 0 to NXFORMS - 1 do if ScriptEditor.cp.xform[i].density = 0 then break; NumTransforms := i; - if SavedPal then ScriptEditor.cp.cmap := Palette; - ScriptEditor.cp.name := FileList[index]; - finally - IFSStrings.Free; - FStrings.Free; - Tokens.free; - EntryStrings.free; - end; end; procedure TOperationLibrary.LoadFlameProc(AMachine: TatVirtualMachine); var i: integer; + ext: string; begin i := AMachine.GetInputArgAsInteger(0); - if (i >= 0) and (i < FileList.count) then + if (i >= 0) and (i < ScFileList.count) then begin - (*if (LowerCase(ExtractFileExt(ParamFile)) = '.undo') or - (LowerCase(ExtractFileExt(ParamFile)) = '.apo') then - LoadFlame(i) - else*) - LoadXMLFlame(i); ; + ext := LowerCase(ExtractFileExt(ParamFile)); + if (ext = '.apo') or (ext = '.undo') then + LoadFlame(i) // AV: added support for Undo files + else + LoadXMLFlame(i); end; end; @@ -2121,14 +2066,15 @@ end; procedure TOperationLibrary.ScaleProc(AMachine: TatVirtualMachine); begin try - if (ActiveTransform < 0) or (ActiveTransform >= ScriptEditor.cp.NumXForms) then raise EFormatInvalid.Create(ErrorOutOfRange); - with AMachine do - ScriptEditor.cp.xform[ActiveTransform].Scale(GetInputArgAsFloat(0)); + if (ActiveTransform < 0) or (ActiveTransform >= ScriptEditor.cp.NumXForms) then + raise EFormatInvalid.Create(ErrorOutOfRange); + with ScriptEditor.cp.xform[ActiveTransform] do + Scale(c, AMachine.GetInputArgAsFloat(0)); except on E: EFormatInvalid do begin - //ScriptEditor.Console.Lines.Add('Scale: ' + E.message); - Application.ProcessMessages; + //ScriptEditor.Console.Lines.Add('Scale: ' + E.message); LastError := 'Scale: ' + E.Message; + Application.ProcessMessages; end; end; end; @@ -2152,26 +2098,9 @@ begin end; procedure TOperationLibrary.GetVariation(AMachine: TatVirtualMachine); -var - i, n: integer; begin - with AMachine do - begin - // AV: something was wrong here, I rewrote it... - { i := integer(Variation); - if (i >= NRVAR) or (i < 0) then - i := -1; } - i := 0; - if MainForm.mnuVRandom.Checked then i := -1 - else - for n := 0 to NRVAR - 1 do - if MainForm.VarMenus[n].Checked then - begin - i := n; - break; - end; - ReturnOutputArg(i); - end + // AV: changed Variation to integer - no more ugly type-casting here! + AMachine.ReturnOutputArg(Variation); end; procedure TOperationLibrary.SetVariation(AMachine: TatVirtualMachine); @@ -2182,32 +2111,32 @@ begin begin i := GetInputArgAsInteger(0); if (i < 0) or (i >= NRVAR) then - i := NRVAR; - if i = NRVAR then begin MainForm.mnuVRandom.Checked := True; - // AV: outdated type... - Variation := vRandom; // AV: only one variation type can be active - for i := 0 to NRVAR - 1 do - MainForm.VarMenus[i].Checked := False; - MainForm.mnuBuiltinVars.Checked := False; - MainForm.mnuPluginVars.Checked := False; + if Variation > vRandom then begin + MainForm.VarMenus[Variation].Checked := False; + MainForm.mnuBuiltinVars.Checked := False; + MainForm.mnuPluginVars.Checked := False; + end; + Variation := vRandom; // AV: outdated type, I changed it to integer end else begin MainForm.VarMenus[i].Checked := True; MainForm.mnuVRandom.Checked := False; - Variation := TVariation(i); - if (i >= NumBuiltinVars) then + if Variation > vRandom then + MainForm.VarMenus[Variation].Checked := False + else + MainForm.mnuVRandom.Checked := False; + + // AV: changed Variation to integer - no more ugly type-casting here! + Variation := i; + if (i >= NumBuiltinVars) then // AV: fixme begin - for i := 0 to NumBuiltinVars-1 do - MainForm.VarMenus[i].Checked := False; // AV: fixme MainForm.mnuBuiltinVars.Checked := False; MainForm.mnuPluginVars.Checked := True; end else begin - for i := NumBuiltinVars to NrVar - 1 do - MainForm.VarMenus[i].Checked := False; // AV: fixme MainForm.mnuBuiltinVars.Checked := True; MainForm.mnuPluginVars.Checked := False; end; @@ -2221,9 +2150,13 @@ var str: string; begin with AMachine do begin + { str := LowerCase(GetInputArgAsString(0)); i := NRVAR-1; while (i >= 0) and (LowerCase(varnames(i)) <> str) do Dec(i); + } + str := GetInputArgAsString(0); // AV + i := GetVariationIndex(str); // AV ReturnOutputArg(i); end; end; @@ -2248,9 +2181,9 @@ var str: string; begin with AMachine do begin - str := LowerCase(GetInputArgAsString(0)); + str := GetInputArgAsString(0); i := GetNrVariableNames-1; - while (i >= 0) and (LowerCase(GetVariableNameAt(i)) <> str) do Dec(i); + while (i >= 0) and (GetVariableNameAt(i) <> str) do Dec(i); ReturnOutputArg(i); end; end; @@ -2258,7 +2191,6 @@ end; procedure TOperationLibrary.VariableNameProc(AMachine: TatVirtualMachine); var i: integer; - str: string; begin with AMachine do begin i := GetInputArgAsInteger(0); @@ -2272,7 +2204,7 @@ end; procedure TOperationLibrary.FileCountProc(AMachine: TatVirtualMachine); begin with AMachine do - ReturnOutputArg(FileList.Count); + ReturnOutputArg(ScFileList.Count); end; procedure TOperationLibrary.ClearProc(AMachine: TatVirtualMachine); @@ -2281,12 +2213,9 @@ var begin NumTransforms := 0; ActiveTransform := -1; -{ - for i := 0 to NXFORMS - 1 do - ScriptEditor.cp.xform[i].density := 0; -} + ScriptEditor.cp.Clear; - ScriptEditor.cp.xform[0].symmetry := 1; + ScriptEditor.cp.xform[0].symmetry := 1; // AV: why? with ScriptEditor.cp do begin // AV: added 3D-camera resetting for new flames @@ -2299,6 +2228,28 @@ begin end; end; +procedure TOperationLibrary.PrepareToMorphProc(AMachine: TatVirtualMachine); +var + a, b: integer; +begin + with AMachine do + begin + a := GetInputArgAsInteger(0); + b := GetInputArgAsInteger(1); + if (a >= 0) and (a < NCPS) and (b >= 0) and (b < NCPS) then + begin + PrepareToInterpolation(cps[a], cps[b]); // adjust flame parameters + end + else begin + LastError := Format('PrepareToMorph(%d, %d): ', [a, b]) + + TextByKey('script-status-varoutofrange'); + RuntimeError(LastError); + Scripter.Halt; + if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV: show errors + end; + end; +end; + procedure TOperationLibrary.MorphProc(AMachine: TatVirtualMachine); var a, b, i: integer; @@ -2325,7 +2276,7 @@ begin TextByKey('script-status-varoutofrange'); RuntimeError(LastError); Scripter.Halt; - if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV: show errors + if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV: show errors end; end; end; @@ -2335,7 +2286,7 @@ begin if NumTransforms > 0 then begin //AMachine.Paused := True; // AV: it doesn't let to pause the animation - PreviewForm.cp.Copy(ScriptEditor.cp); + PreviewForm.cp.Copy(ScriptEditor.cp); // <-- AV: optimized for speed PreviewForm.cp.AdjustScale(PreviewForm.Image.Width, PreviewForm.Image.Height); PreviewForm.Show; PreviewForm.DrawFlame; @@ -2443,9 +2394,9 @@ begin except Application.ProcessMessages; LastError := 'DeleteTransform: Oops!'; - i := LineNumberFromInstruction(AMachine.CurrentInstruction); // AV - ScriptEditor.Editor.ActiveLine := i; - ScriptEditor.Editor.ActiveLineSettings.ShowActiveLine := true; // AV + i := LineNumberFromInstruction(AMachine.CurrentInstruction); // AV + ScriptEditor.Editor.ActiveLine := i; + ScriptEditor.Editor.ActiveLineSettings.ShowActiveLine := true; // AV Scripter.Halt; end; end; @@ -2482,25 +2433,18 @@ end; procedure TOperationLibrary.TranslateProc(AMachine: TatVirtualMachine); var x, y: double; begin - if ScriptEditor.cp.xform[ActiveTransform].postXswap then - begin - TranslatePXProc(AMachine); - Exit; - end; try if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then // was: NXFORMS-1 raise EFormatInvalid.Create(ErrorOutOfRange); - with AMachine do - // AV: matrix multiplication must not affect the translation - // ScriptEditor.cp.xform[ActiveTransform].Translate(GetInputArgAsFloat(0), GetInputArgAsFloat(1)); - begin - x := GetInputArgAsFloat(0); - y := -1 * GetInputArgAsFloat(1); - end; - with ScriptEditor.cp.xform[ActiveTransform] do begin - c[2,0] := c[2,0] + x; - c[2,1] := c[2,1] + y; - end; + // AV: matrix multiplication must not affect the translation + // ScriptEditor.cp.xform[ActiveTransform].Translate(GetInputArgAsFloat(0), GetInputArgAsFloat(1)); + x := AMachine.GetInputArgAsFloat(0); + y := AMachine.GetInputArgAsFloat(1); + with ScriptEditor.cp.xform[ActiveTransform] do + if postXswap then + Translate(p, x, y) + else + Translate(c, x, y); except on E: EFormatInvalid do begin Application.ProcessMessages; @@ -2516,15 +2460,11 @@ begin try if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then raise EFormatInvalid.Create(ErrorOutOfRange); - with AMachine do - begin - x := GetInputArgAsFloat(0); - y := -1 * GetInputArgAsFloat(1); - end; - with ScriptEditor.cp.xform[ActiveTransform] do begin - p[2,0] := p[2,0] + x; - p[2,1] := p[2,1] + y; - end; + + x := AMachine.GetInputArgAsFloat(0); + y := AMachine.GetInputArgAsFloat(1); + with ScriptEditor.cp.xform[ActiveTransform] do + Translate(p, x, y); except on E: EFormatInvalid do begin Application.ProcessMessages; @@ -2534,6 +2474,33 @@ begin end; end; +procedure NormalizeVariations(var cp1: TControlPoint); // AV: moved from Main +var + totvar, v: double; + i, j: integer; +begin + for i := 0 to cp1.NumXForms do + begin + totvar := 0; + for j := 0 to NRVAR - 1 do + begin + v := cp1.xform[i].GetVariation(j); // AV + if v < 0 then + cp1.xform[i].SetVariation(j, -v); + totvar := totvar + v; + end; + if totVar = 0 then + cp1.xform[i].SetVariation(0, 1) + else + for j := 0 to NRVAR - 1 do begin + v := cp1.xform[i].GetVariation(j); // AV + //if totVar <> 0 then // <-- AV: we've already check it! + if v <> 0 then // AV: because 0/totvar = 0 + cp1.xform[i].SetVariation(j, v / totvar); + end; + end; +end; + procedure TOperationLibrary.NormalizeVars(AMachine: TatVirtualMachine); begin NormalizeVariations(ScriptEditor.cp); @@ -2552,7 +2519,7 @@ begin btnSave.Hint := TextByKey('script-save'); btnRun.Hint := TextByKey('script-run'); btnStop.Hint := TextByKey('script-stop'); - btnFavorite.Hint := TextByKey('script-faves'); + btnFavorite.Hint := TextByKey('script-faves'); CodeButton.Hint := TextByKey('script-codeblocks'); btnPause.Hint := TextByKey('script-pause'); ShowCodeHints.Caption := TextByKey('script-codeblockhints'); @@ -2581,15 +2548,23 @@ begin DTError := #13#10 + TextByKey('script-compileerror') + #13#10 + StringOfChar('=', length(TextByKey('script-compileerror'))) + #13#10; + // AV: moved this into OnCreate handler since filters never change + MainOpenDialog.Filter := Format('%s|*.aposcript;*.asc|%s|*.*', + [TextByKey('common-filter-scriptfiles'), + TextByKey('common-filter-allfiles')]); + MainSaveDialog.Filter := MainOpenDialog.Filter; // AV + // AV: added language translation here: SaveDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*rand;*.template|' - + TextByKey('common-filter-allfiles') + '|*.*'; - OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*rand;*.template|' + - TextByKey('common-filter-scriptfiles') + '|*.asc;*aposcript|' + - TextByKey('common-filter-allfiles') + '|*.*'; + + TextByKey('common-filter-undofiles') + '|*.undo;*.apo|' + + TextByKey('common-filter-allfiles') + '|*.*'; + OpenDialog.Filter := TextByKey('common-filter-flamefiles') +'|*.flame;*rand;*.template|' + + TextByKey('common-filter-scriptfiles') + '|*.asc;*aposcript|' + + TextByKey('common-filter-undofiles') + '|*.undo;*.apo|' + + TextByKey('common-filter-allfiles') + '|*.*'; Transform := TTransform.create; - FileList := TStringList.Create; + ScFileList := TStringList.Create; Flame := TFlame.Create; Options := TOptions.Create; Pivot := TPivot.Create; @@ -2609,15 +2584,15 @@ begin except Editor.Lines.Clear; end; - - AdjustScripterColors; // AV: change scripter font ang background for dark themes + // AV: change scripter font ang background for dark themes + AdjustScripterColors; end; procedure TScriptEditor.FormDestroy(Sender: TObject); var i: integer; begin - FileList.Free; + ScFileList.Free; Renderer.Free; Another.Free; for i := 0 to 9 do @@ -2720,7 +2695,7 @@ begin with AMachine do begin v := GetInputArgAsFloat(0); - if (v > 0) and (v <= 5) then cp.Gamma := v; // AV: added max check + if (v > 0) and (v <= 10) then cp.Gamma := v; // AV: added max check end; end; @@ -3059,6 +3034,16 @@ begin AMachine.ReturnOutPutArg(cp.name); end; +procedure TScriptEditor.SetFlameCommentProc(AMachine: TatVirtualMachine); +begin + cp.comment := AMachine.GetInputArgAsString(0); +end; + +procedure TScriptEditor.GetFlameCommentProc(AMachine: TatVirtualMachine); +begin + AMachine.ReturnOutPutArg(cp.comment); +end; + (* procedure TScriptEditor.SetFlameNickProc(AMachine: TatVirtualMachine); begin @@ -3961,7 +3946,7 @@ begin k := SelStartY; m := SelEndY; end; - BlockIndent(k, m, 4); + BlockIndent(k, m, 4); if Sender = BeginEnd1 then begin InsertTextAtXY('begin'#13#10, 0, k); InsertTextAtXY('end;'#13#10, 0, m + 2); @@ -4050,8 +4035,8 @@ begin with cp.xform[ActiveTransform] do begin - c[0,0] := -c[0,0]; - c[1,0] := -c[1,0]; + c[0,0] := -c[0,0]; + c[1,0] := -c[1,0]; with EditForm do if (PivotMode = PivotWorld) then c[2,0] := 2 * WorldPivot.x - c[2,0]; @@ -4068,8 +4053,8 @@ begin with cp.xform[ActiveTransform] do begin - p[0,0] := -p[0,0]; - p[1,0] := -p[1,0]; + p[0,0] := -p[0,0]; + p[1,0] := -p[1,0]; with EditForm do if (PivotMode = PivotWorld) then p[2,0] := 2 * WorldPivot.x - p[2,0]; @@ -4092,8 +4077,8 @@ begin with cp.xform[ActiveTransform] do begin - c[0,1] := -c[0,1]; - c[1,1] := -c[1,1]; + c[0,1] := -c[0,1]; + c[1,1] := -c[1,1]; with EditForm do if (PivotMode = PivotWorld) then c[2,1] := -2 * WorldPivot.y - c[2,1]; @@ -4110,8 +4095,8 @@ begin with cp.xform[ActiveTransform] do begin - p[0,1] := -p[0,1]; - p[1,1] := -p[1,1]; + p[0,1] := -p[0,1]; + p[1,1] := -p[1,1]; with EditForm do if (PivotMode = PivotWorld) then p[2,1] := -2 * WorldPivot.y - p[2,1]; @@ -4187,7 +4172,6 @@ end; procedure TScriptEditor.TransformScalePXProc(AMachine: TatVirtualMachine); var - i, j: integer; s: double; begin if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then begin @@ -4199,9 +4183,7 @@ begin s := AMachine.GetInputArgAsFloat(0); with cp.xform[ActiveTransform] do begin - for i := 0 to 1 do - for j:= 0 to 1 do - p[i,j] := p[i,j] * s; + Scale(p, s); with EditForm do if (PivotMode = PivotWorld) then begin @@ -4213,33 +4195,26 @@ end; procedure TScriptEditor.TransformRotatePXProc(AMachine: TatVirtualMachine); var - v, tx, ty, tx0, tx1, ty0, ty1, sv, cv: double; + v, tx, ty, sv, cv: double; begin try if (ActiveTransform < 0) or (ActiveTransform > NXFORMS) then raise EFormatInvalid.Create('Transform.RotatePX: ' + ErrorOutOfRange); - with AMachine do - v := GetInputArgAsFloat(0) * PI / 180; - SinCos(v, sv, cv); - with cp.xform[ActiveTransform] do - begin - tx0 := p[0,0] * cv - (-p[0,1] * sv); - tx1 := p[0,0] * sv + (-p[0,1] * cv); - ty0 := -p[1,0] * cv - p[1,1] * sv; - ty1 := -p[1,0] * sv + p[1,1] * cv; - p[0,0] := tx0; - p[0,1] := -tx1; - p[1,0] := -ty0; - p[1,1] := ty1; - with EditForm do - if (PivotMode = PivotWorld) then - begin - tx := WorldPivot.x + (p[2,0] - WorldPivot.x) * cv - (-p[2,1] - WorldPivot.y) * sv; - ty := WorldPivot.y + (p[2,0] - WorldPivot.x) * sv + (-p[2,1] - WorldPivot.y) * cv; - p[2,0] := tx; - p[2,1] := -ty; - end; - end; + with AMachine do + v := GetInputArgAsFloat(0) * PI / 180; + SinCos(v, sv, cv); + with cp.xform[ActiveTransform] do + begin + Multiply(p, cv, -sv, sv, cv); // AV: my common method for both matrices + with EditForm do + if (PivotMode = PivotWorld) then + begin + tx := WorldPivot.x + (p[2,0] - WorldPivot.x) * cv - (-p[2,1] - WorldPivot.y) * sv; + ty := WorldPivot.y + (p[2,0] - WorldPivot.x) * sv + (-p[2,1] - WorldPivot.y) * cv; + p[2,0] := tx; + p[2,1] := -ty; + end; + end; except on E: EFormatInvalid do begin Application.ProcessMessages; @@ -4411,6 +4386,8 @@ end; procedure TScriptEditor.PrepareScripter; var i: integer; + lib : TStringList; + s: string; begin Scripter.AddLibrary(TatSysUtilsLibrary); with Scripter.defineClass(TScriptRender) do @@ -4445,6 +4422,7 @@ begin DefineProp('Gradient', tkInteger, GetFlamePaletteProc, SetFlamePaletteProc, nil, false, 2); DefineProp('Background', tkInteger, GetFlameBackgroundProc, SetFlameBackgroundProc, nil, false, 1); DefineProp('Name', tkString, GetFlameNameProc, SetFlameNameProc); + DefineProp('Comment', tkString, GetFlameCommentProc, SetFlameCommentProc); // DefineProp('Nick', tkString, GetFlameNickProc, SetFlameNickProc); // DefineProp('URL', tkString, GetFlameURLProc, SetFlameURLProc); DefineProp('Hue', tkFloat, GetFlameHueProc, SetFlameHueProc); @@ -4490,23 +4468,23 @@ begin DefineMethod('Scale', 1, tkNone, nil, TransformScaleProc); DefineMethod('RotateOrigin', 1, tkNone, nil, TransformRotateOriginProc); - DefineMethod('RotatePXOrigin', 1, tkNone, nil, TransformRotatePXOriginProc); - DefineMethod('RotatePX', 1, tkNone, nil, TransformRotatePXProc); - DefineMethod('ScalePX', 1, tkNone, nil, TransformScalePXProc); - DefineMethod('FlipPXHoriz', 0, tkNone, nil, TransformFlipPXHorizProc); - DefineMethod('FlipHoriz', 0, tkNone, nil, TransformFlipHorizProc); - DefineMethod('FlipPXVert', 0, tkNone, nil, TransformFlipPXVertProc); - DefineMethod('FlipVert', 0, tkNone, nil, TransformFlipVertProc); - DefineMethod('SwapCoefs', 0, tkNone, nil, TransformSwapCoefsProc); - DefineMethod('ResetVariables', 0, tkNone, nil, TransformResetVariables); + DefineMethod('RotatePXOrigin', 1, tkNone, nil, TransformRotatePXOriginProc); + DefineMethod('RotatePX', 1, tkNone, nil, TransformRotatePXProc); + DefineMethod('ScalePX', 1, tkNone, nil, TransformScalePXProc); + DefineMethod('FlipPXHoriz', 0, tkNone, nil, TransformFlipPXHorizProc); + DefineMethod('FlipHoriz', 0, tkNone, nil, TransformFlipHorizProc); + DefineMethod('FlipPXVert', 0, tkNone, nil, TransformFlipPXVertProc); + DefineMethod('FlipVert', 0, tkNone, nil, TransformFlipVertProc); + DefineMethod('SwapCoefs', 0, tkNone, nil, TransformSwapCoefsProc); + DefineMethod('ResetVariables', 0, tkNone, nil, TransformResetVariables); - DefineMethod('SetVariationOrder', 2, tkNone, nil, TransformMoveVarProc); - DefineMethod('SwapVariations', 2, tkNone, nil, TransformExchangeVarsProc); - DefineMethod('SortVariationsByName', 0, tkNone, nil, TransformSortVarsProc); - DefineMethod('SortVariationsByIndex', 0, tkNone, nil, TransformDefaultVarOrderProc); - DefineMethod('GetVariationOrder', 1, tkInteger, nil, TransformGetVarOrderProc); - DefineMethod('CopyVariationsOrder', 1, tkInteger, nil, TransformCopyVarOrderProc); - DefineMethod('PrintVariationsOrder', 0, tkNone, nil, TransformDisplayVarsProc); + DefineMethod('SetVariationOrder', 2, tkNone, nil, TransformMoveVarProc); + DefineMethod('SwapVariations', 2, tkNone, nil, TransformExchangeVarsProc); + DefineMethod('SortVariationsByName', 0, tkNone, nil, TransformSortVarsProc); + DefineMethod('SortVariationsByIndex', 0, tkNone, nil, TransformDefaultVarOrderProc); + DefineMethod('GetVariationOrder', 1, tkInteger, nil, TransformGetVarOrderProc); + DefineMethod('CopyVariationsOrder', 1, tkInteger, nil, TransformCopyVarOrderProc); + DefineMethod('PrintVariationsOrder', 0, tkNone, nil, TransformDisplayVarsProc); DefineProp('a', tkFloat, GetTransformAProc, SetTransformAProc); DefineProp('b', tkFloat, GetTransformBProc, SetTransformBProc); @@ -4520,8 +4498,8 @@ begin DefineProp('PlotMode', tkInteger, GetTransformPlotModeProc, SetTransformPlotModeProc); DefineProp('Opacity', tkFloat, GetTransformOpacityProc, SetTransformOpacityProc); - DefineProp('PostXformEnabled', tkInteger, GetTransformPostxformEnabledProc, SetTransformPostxformEnabledProc); - DefineProp('Name', tkString, GetTransformNameProc, SetTransformNameProc); + DefineProp('PostXformEnabled', tkInteger, GetTransformPostxformEnabledProc, SetTransformPostxformEnabledProc); + DefineProp('Name', tkString, GetTransformNameProc, SetTransformNameProc); end; Scripter.AddObject('Transform', Transform); @@ -4637,7 +4615,7 @@ begin { Variations } Scripter.AddConstant('V_LINEAR', 0); - Scripter.AddConstant('V_RANDOM', -1); + Scripter.AddConstant('V_RANDOM', vRandom); // Scripter.AddLibrary(TatWindowsLibrary); // Scripter.AddLibrary(TatFormsLibrary); @@ -4646,8 +4624,7 @@ begin Scripter.AddLibrary(TatSysUtilsLibrary); Scripter.AddLibrary(TatFileCtrlLibrary); Scripter.AddLibrary(TatClassesLibrary); - { Nonsense - it's the only way to get the last real - library to work! } + { Nonsense - it's the only way to get the last real library to work! } Scripter.AddObject('Not_Any_Thing_Useful', Another); Scripter.AddObject('IglooFunkyRubber', Another); Scripter.AddObject('Scrumptious', Another); @@ -4660,7 +4637,21 @@ begin // AV: moved into main library to let user choose which CopyFile must be called Scripter.SystemLibrary.DefineMethod('CopyFile', 3, tkVariant, nil, CopyFileProc, false, 1); - RegisterClasses([TButton, TLabel, TEdit, TComboBox]); // AV: to load external Delphi forms + if FileExists(defLibrary) then // AV: add user's defined methods + begin + lib := TStringList.Create; + try + lib.LoadFromFile(defLibrary); + for s in lib do + if (pos('procedure', LowerCase(s)) > 0) or (pos('function', LowerCase(s)) > 0) then + Editor.SyntaxStyles.AutoCompletion.Add(Trim(s)); + finally + lib.Free; + end; + end; + + // AV: to load external Delphi forms + RegisterClasses([TButton, TLabel, TEdit, TComboBox]); end; { ************************* Buttons ***************************************** } @@ -4672,7 +4663,7 @@ begin if ConfirmClearScript then begin if Editor.LinesModified then // AV: if script changes not saved yet - c := (Application.MessageBox(PChar(TextByKey('script-confirmclear')), 'Apophysis', 52) = IDYES) + c := (Application.MessageBox(PChar(TextByKey('script-confirmclear')), ApophysisSVN, 52) = IDYES) else c := True; end @@ -4689,7 +4680,7 @@ end; procedure TScriptEditor.LoadScriptFile(filename:string); var s: string; - fn:string; + fn: string; begin Editor.Lines.LoadFromFile(filename); s := ExtractFileName(filename); @@ -4701,22 +4692,20 @@ end; procedure TScriptEditor.OpenScript; var s: string; - fn:string; + fn: string; begin MainOpenDialog.InitialDir := ScriptPath; MainOpenDialog.Filename := ''; - MainOpenDialog.Filter := Format('%s|*.aposcript;*.asc|%s|*.*', [TextByKey('common-filter-scriptfiles'), TextByKey('common-filter-allfiles')]); - if OpenSaveFileDialog(ScriptEditor, '.aposcript', MainOpenDialog.Filter, MainOpenDialog.InitialDir, TextByKey('common-browse'), fn, true, false, false, true) then -// if MainOpenDialog.execute then + if MainOpenDialog.execute then begin - MainOpenDialog.FileName := fn; - Script := MainOpenDialog.Filename; - Editor.Lines.LoadFromFile(MainOpenDialog.Filename); - s := ExtractFileName(MainOpenDialog.Filename); + fn := MainOpenDialog.FileName; // AV + Script := fn; + Editor.Lines.LoadFromFile(fn); + s := ExtractFileName(fn); s := Copy(s, 0, length(s) - Length(ExtractFileExt(s))); MainForm.mnuRun.Caption := Format(TextByKey('main-menu-script-run2'), [s]); Caption := s; - ScriptPath := ExtractFileDir(MainOpenDialog.Filename); + ScriptPath := ExtractFileDir(fn); end; end; @@ -4746,17 +4735,14 @@ end; procedure TScriptEditor.btnSaveClick(Sender: TObject); var fn : string; begin - if Script = '' then fn := '' - else fn := ChangeFileExt(ExtractFileName(Script), '.aposcript'); - if OpenSaveFileDialog(ScriptEditor, '.aposcript', - Format('%s|*.aposcript;*.asc|%s|*.*', - [TextByKey('common-filter-scriptfiles'), - TextByKey('common-filter-allfiles')]), - ScriptPath, TextByKey('common-browse'), fn, - false, true, false, false) then - //if MainSaveDialog.Execute then + if Script = '' then + MainSaveDialog.Filename := '' + else + MainSaveDialog.Filename := ChangeFileExt(ExtractFileName(Script), '.aposcript'); + MainSaveDialog.InitialDir := ScriptPath; + if MainSaveDialog.Execute then begin - MainOpenDialog.FileName := fn; + fn := MainSaveDialog.FileName; // AV Script := fn; Editor.Lines.SaveToFile(fn); Caption := ExtractFileName(fn); @@ -4775,13 +4761,11 @@ begin FStrings := TStringList.Create; FStrings.LoadFromFile(ParamFile); try - FileList.Clear; + ScFileList.Clear; ext := LowerCase(ExtractFileExt(ParamFile)); - (*if (ext = '.fla') or (ext = '.apo') then - begin - - // Get names from .fla or .apo file + if (ext = '.fla') or (ext = '.apo') then // AV + begin // Get names from .undo or .apo file if (Pos('{', FStrings.Text) <> 0) then for i := 0 to FStrings.Count - 1 do begin @@ -4791,15 +4775,13 @@ begin Title := Trim(Copy(FStrings[i], 1, p - 1)); if Title <> '' then begin { Otherwise bad format } - FileList.Add(Trim(Copy(FStrings[i], 1, p - 1))); + ScFileList.Add(Trim(Copy(FStrings[i], 1, p - 1))); end; end; end; - end else - - begin *) + begin // Get names from .flame file if (Pos(' 0) then begin @@ -4809,17 +4791,16 @@ begin if (p <> 0) then begin pname := ''; - MainForm.ListXMLScanner.LoadFromBuffer(PANSICHAR(AnsiString(FSTrings[i]))); + MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FStrings[i]))); MainForm.ListXMLScanner.Execute; if Trim(pname) = '' then Title := '*untitled ' + ptime else - FileList.Add(pname); + ScFileList.Add(pname); end; end; - end; - //end; + end; finally FStrings.Free; end; @@ -4852,7 +4833,7 @@ begin LastError := 'CopyFile: ' + TextByKey('common-genericcopyfailure'); RuntimeError(LastError); // AV Halt; - if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV + if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV end else begin if not FileExists(src) then @@ -4861,7 +4842,7 @@ begin LastError := 'CopyFile: ' + TextByKey('render-status-pathdoesnotexist'); RuntimeError(LastError); // AV Halt; - if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV + if LoadForm.CheckBox1.Checked then LoadForm.Show; // AV end; end; end; @@ -4902,7 +4883,7 @@ begin ActiveTransform := EditForm.SelectedTriangle; NumTransforms := Transforms; cp.copy(MainCp); - cmap := MainCp.cmap; + //cmap := MainCp.cmap; // <-- is used nowhere Application.ProcessMessages; Randomize; StatusBar.SimpleText := TextByKey('script-status-executing'); @@ -4914,6 +4895,7 @@ begin MainForm.mnuStop.Enabled := True; MainForm.btnStopScript.Enabled := True; end; + with Scripter do begin SourceCode.Assign(Editor.Lines); @@ -4934,10 +4916,20 @@ begin //Compile; Execute; end; + if (NumTransforms < 1) and UpdateIt then + Console.Lines.Add(TextByKey('script-status-notransforms')) + else if (LastError = '') and UpdateIt then begin - Console.Lines.Add(TextByKey('script-status-notransforms')); - ScriptRenderForm.Close; + MainForm.UpdateUndo; + MainCp.Copy(cp); + UpdateFlame; + if ResetLocation then MainForm.ResetLocation; + end + else + Console.Lines.Add(LastError); + + if ScriptRenderForm.Visible then ScriptRenderForm.Close; btnRun.Enabled := True; btnStop.Enabled := False; MainForm.btnRunScript.Enabled := True; @@ -4945,38 +4937,11 @@ begin MainForm.mnuRun.Enabled := True; MainForm.mnuStop.Enabled := False; btnBreak.Enabled := False; - btnPause.Enabled := False; - StatusBar.SimpleText := StatusBar.Hint; - // AV: to continue work with these scripts + btnPause.Enabled := False; + // AV: restore the status of submenus to continue work with these scripts MainForm.FavouriteScripts1.Enabled := favs; MainForm.Directory1.Enabled := defs; - Exit; - end - else - if (LastError = '') and UpdateIt then - begin - MainForm.UpdateUndo; - MainCp.Copy(cp); - UpdateFlame; - if ResetLocation then MainForm.ResetLocation; - end - else - begin - Console.Lines.Add(LastError); - end; - ScriptRenderForm.Close; - btnRun.Enabled := True; - btnStop.Enabled := False; - MainForm.btnRunScript.Enabled := True; - MainForm.btnStopScript.Enabled := False; - MainForm.mnuRun.Enabled := True; - MainForm.mnuStop.Enabled := False; - btnBreak.Enabled := False; - btnPause.Enabled := False; - // restore the status of submenus - MainForm.FavouriteScripts1.Enabled := favs; - MainForm.Directory1.Enabled := defs; - StatusBar.SimpleText := StatusBar.Hint; + StatusBar.SimpleText := StatusBar.Hint; end; procedure TScriptEditor.btnRunClick(Sender: TObject); @@ -5148,8 +5113,8 @@ begin for i:= 0 to GetNrVariableNames - 1 do begin ALIst.AddObject('property ' + GetVariableNameAt(i) + ': double', TObject(ttProp)); end; - end; - if (LowerCase(AToken) = 'flame.') then + end + else if (LowerCase(AToken) = 'flame.') then begin ALIst.AddObject('property Gamma: double', TObject(ttProp)); ALIst.AddObject('property GammaThreshold: double', TObject(ttProp)); @@ -5172,6 +5137,7 @@ begin ALIst.AddObject('property Y: double', TObject(ttProp)); ALIst.AddObject('property DOF: double', TObject(ttProp)); ALIst.AddObject('property Name: string', TObject(ttProp)); + ALIst.AddObject('property Comment: string', TObject(ttProp)); ALIst.AddObject('property SampleDensity: double', TObject(ttProp)); ALIst.AddObject('property Quality: double', TObject(ttProp)); ALIst.AddObject('property Time: double', TObject(ttProp)); @@ -5181,24 +5147,24 @@ begin ALIst.AddObject('property FinalXformEnabled: boolean', TObject(ttProp)); ALIst.AddObject('property Background[]: array of integer', TObject(ttProp)); ALIst.AddObject('property Gradient[][]: array of integer', TObject(ttProp)); - end; - if (LowerCase(AToken) = 'pivot.') then + end + else if (LowerCase(AToken) = 'pivot.') then begin ALIst.AddObject('property X: double', TObject(ttProp)); ALIst.AddObject('property Y: double', TObject(ttProp)); ALIst.AddObject('property Mode: integer', TObject(ttProp)); ALIst.AddObject('procedure Set( X: double, Y: double)', TObject(ttMethod)); ALIst.AddObject('procedure Reset', TObject(ttMethod)); - end; - if (LowerCase(AToken) = 'renderer.') then + end + else if (LowerCase(AToken) = 'renderer.') then begin ALIst.AddObject('property Filename: string', TObject(ttProp)); ALIst.AddObject('property Width: integer', TObject(ttProp)); ALIst.AddObject('property Height: integer', TObject(ttProp)); ALIst.AddObject('property MaxMemory: integer', TObject(ttProp)); ALIst.AddObject('property EmbedParameters: boolean', TObject(ttProp)); - end; - if (LowerCase(AToken) = 'options.') then + end + else if (LowerCase(AToken) = 'options.') then begin ALIst.AddObject('property JPEGQuality: integer', TObject(ttProp)); ALIst.AddObject('property BatchSize: integer', TObject(ttProp)); @@ -5237,14 +5203,15 @@ begin ALIst.AddObject('property ColorBlending: integer', TObject(ttProp)); ALIst.AddObject('property EvenGradientStripes: boolean', TObject(ttProp)); ALIst.AddObject('property ExportRenderer: string', TObject(ttProp)); - end; - if pos('tstringlist', LowerCase(AToken))> 0 then - ALIst.AddObject('constructor Create', TObject(ttMethod)); + end + else if pos('tstringlist', LowerCase(AToken))> 0 then + ALIst.AddObject('constructor Create', TObject(ttMethod)) // AV: easter eggs ;-) - if ((pos('apo', LowerCase(AToken))> 0) or (pos('ifs', LowerCase(AToken))> 0)) then + else if (((pos('apo', LowerCase(AToken))> 0) and (LowerCase(AToken) <> 'apophysis.')) + or (pos('ifs', LowerCase(AToken))> 0)) then begin - AList.Clear; + //AList.Clear; ALIst.AddObject('procedure LoadFromFile(full_filename: string)', TObject(ttProc)); ALIst.AddObject('procedure SaveToFile(full_filename: string)', TObject(ttProc)); ALIst.AddObject('function Add(text: string): integer', TObject(ttFunc)); @@ -5269,25 +5236,24 @@ begin ALIst.AddObject('property Sorted: boolean', TObject(ttProp)); ALIst.AddObject('procedure Assign(sourse: TStrings)', TObject(ttProc)); ALIst.AddObject('procedure AddStrings(strings: TStrings)', TObject(ttProc)); - end; - + end + else if (LowerCase(AToken) = 'apophysis.') or (LowerCase(AToken) = 'application.') then begin - AList.Clear; ALIst.AddObject('function MessageBox(Promt, Caption: string, DlgStyle: integer = 0): integer;', TObject(ttFunc)); ALIst.AddObject('property Icon', TObject(ttProp)); ALIst.AddObject('property Title', TObject(ttProp)); ALIst.AddObject('property ExeName', TObject(ttProp)); ALIst.AddObject('procedure ProcessMessages', TObject(ttMethod)); - end; - - if pos('ttaskdialog', LowerCase(AToken))> 0 then - ALIst.AddObject('constructor Create(nil)', TObject(ttMethod)); - + end + else + if (LowerCase(AToken) = 'ttaskdialog.') then + ALIst.AddObject('constructor Create(nil)', TObject(ttMethod)) + else if (pos('tdlg', LowerCase(AToken))> 0) then begin - AList.Clear; + //AList.Clear; ALIst.AddObject('destructor Destroy', TObject(ttMethod)); ALIst.AddObject('property Title: string', TObject(ttProp)); ALIst.AddObject('property Caption: string', TObject(ttProp)); @@ -5389,7 +5355,7 @@ end; procedure TScriptEditor.ScripterCompileError(Sender: TObject; var msg: string; row, col: Integer; var ShowException: Boolean); -var ps: integer; +var ps, n: integer; begin btnRun.Enabled := True; btnStop.Enabled := False; @@ -5409,7 +5375,8 @@ begin StatusBar.SimpleText := TextByKey('script-status-compileerror'); // AV - Editor.ActiveLine := row - 1; + n := min(row, Editor.Lines.Count) - 1; // AV + Editor.ActiveLine := n; Editor.ActiveLineSettings.ShowActiveLine := True; if LanguageFile <> '' then // AV: if we need to translate from/to English begin @@ -5478,9 +5445,9 @@ begin end; end; end; - Console.Lines.Add(TextByKey('script-line') + #32 + IntToStr(row) + ' : '+ msg); + Console.Lines.Add(TextByKey('script-line') + #32 + IntToStr(n+1) + ' : '+ msg); LoadForm.Output.Text := LoadForm.Output.Text + DTError + TextByKey('script-line') + ': '#39 + - Editor.Lines[row-1] + #39', '+ TextByKey('script-position') + + Editor.Lines[n] + #39', '+ TextByKey('script-position') + ': '+ IntToStr(col) + #13#10 + msg + #13#10; // AV ScriptRenderForm.Close; ShowException := true; @@ -5508,7 +5475,7 @@ begin if (MainForm.Directory1.Count > 0) then MainForm.Directory1.Enabled := True; // AV - Editor.ActiveLine := row - 1; + Editor.ActiveLine := min(row, Editor.Lines.Count) - 1; // AV Editor.ActiveLineSettings.ShowActiveLine := True; if LanguageFile <> '' then { AV: We don't need to translate from-to English } @@ -5521,7 +5488,7 @@ begin TextByKey('script-status-noformfile'), []); end; LoadForm.Output.Text := LoadForm.Output.Text + RTError + TextByKey('script-line') + ': '#39 + - Editor.Lines[row-1] + #39', '+ TextByKey('script-position') + + Editor.Lines[Editor.ActiveLine] + #39', '+ TextByKey('script-position') + ': '+ IntToStr(col) + #13#10 + msg + #13#10; ScriptRenderForm.Close; ShowException := true; @@ -5559,7 +5526,6 @@ begin Editor.BlockColor := MidColor; Editor.Gutter.GutterColor := BrightColor; Editor.Gutter.GutterColorTo := MidColor; - Editor.Gutter.GutterColorTo := MidColor; Editor.Gutter.Font.Color := TextColor; ScrCodeList1.Font.Color := Editor.Font.Color; @@ -5629,7 +5595,7 @@ begin end; if there then begin Application.MessageBox(PChar(Format(TextByKey('common-favscriptexists'), - [ExtractFileName(Script)])), PChar('Apophysis AV'), MB_ICONWARNING); + [ExtractFileName(Script)])), PChar(ApophysisSVN), MB_ICONWARNING); exit; end; @@ -5639,7 +5605,7 @@ begin Favorites.SaveToFile(AppPath + scriptFavsFilename); MainForm.GetScripts; Application.MessageBox(PChar(Format(TextByKey('common-favscriptadded'), - [ExtractFileName(Script)])), PChar('Apophysis AV'), MB_ICONINFORMATION); + [ExtractFileName(Script)])), ApophysisSVN, MB_ICONINFORMATION); end; end; @@ -5674,8 +5640,8 @@ end; procedure TScriptEditor.F2SXMLEmptyTag(Sender: TObject; TagName: string; Attributes: TAttrList); var - i,n: integer; - v,w: TStringType; + i, n: integer; + v, w: string; //TStringType; d, floatcolor: double; Tokens: TStringList; begin @@ -5689,19 +5655,19 @@ begin Editor.Lines.Add('Flame.FinalXformEnabled := True;'); Editor.Lines.Add('SetActiveTransform(transforms);'); end else begin - w := TStringType('{ Transform ' + IntToStr(AddedXForms + 1)); - v := Attributes.Value('name'); + w := '{ Transform ' + IntToStr(AddedXForms + 1); + v := string(Attributes.Value('name')); if (v <> '') then w := w + ' (' + v + ')'; w := w + ' }'; - Editor.Lines.Add(String(w)); + Editor.Lines.Add(w); Editor.Lines.Add('AddTransform;'); end; Editor.Lines.Add('with Transform do begin'); //Editor.Lines.Add(' for i := 0 to NXFORMS do Chaos[i] := 1;'); - v := Attributes.Value('var_order'); + v := string(Attributes.Value('var_order')); if v <> '' then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); n := -1; for i := 0 to Tokens.Count-1 do if (GetVariationIndex(Tokens[i]) >= 0) then begin @@ -5710,42 +5676,44 @@ begin end; end; - v := Attributes.Value(TStringType(varnames(0))); - if v = '' then - Editor.Lines.Add(' Variation[0] := 0; // linear'); + v := string(Attributes.Value('linear')); // varnames(0) + if v = '' then + Editor.Lines.Add(' Variation[0] := 0; // linear'); for i := 0 to NRVAR - 1 do begin - v := Attributes.Value(TStringType(varnames(i))); + w := varnames(i); + v := string(Attributes.Value(Utf8String(w))); if v <> '' then - //Editor.Lines.Add(' ' + varnames(i) + ' := ' + String(v) + ';'); - Editor.Lines.Add(Format(' %s := %.6g;', [varnames(i), StrToFloat(String(v))])); + Editor.Lines.Add(Format(' %s := %.6g;', [w, StrToFloat(v)])); end; for i := 0 to GetNrVariableNames - 1 do begin - v := Attributes.Value(TStringType(GetVariableNameAt(i))); + w := GetVariableNameAt(i); + v := string(Attributes.Value(Utf8String(w))); if v <> '' then begin - Editor.Lines.Add(' ' + GetVariableNameAt(i) + ' := ' + String(v) + ';'); + Editor.Lines.Add(' ' + w + ' := ' + v + ';'); end; end; - v := Attributes.Value('weight'); + v := string(Attributes.Value('weight')); if (v <> '') and (TagName = 'xform') then - Editor.Lines.Add(Format(' Weight := %.6g;', [StrToFloat(String(v))])); - v := Attributes.Value('color'); - if (v <> '') then Editor.Lines.Add(' Color := ' + String(v) + ';'); - v := Attributes.Value('var_color'); - if (v <> '') then Editor.Lines.Add(' VarColor := ' + String(v) + ';'); - v := Attributes.Value('symmetry'); - if (v <> '') and (TagName = 'xform') then Editor.Lines.Add(' Symmetry := ' + String(v) + ';'); - v := Attributes.Value('opacity'); + Editor.Lines.Add(Format(' Weight := %.6g;', [StrToFloat(v)])); + v := string(Attributes.Value('color')); + if (v <> '') then Editor.Lines.Add(' Color := ' + v+ ';'); + v := string(Attributes.Value('var_color')); + if (v <> '') then Editor.Lines.Add(' VarColor := ' + v + ';'); + // AV: fixed - final xforms can have ColorSpeed <> 1 + v := string(Attributes.Value('symmetry')); + if (v <> '') then Editor.Lines.Add(' Symmetry := ' + v + ';'); + v := string(Attributes.Value('opacity')); if v <> '' then begin - Editor.Lines.Add(' Opacity := ' + String(v) + ';'); + Editor.Lines.Add(' Opacity := ' + v + ';'); end; - v := Attributes.Value('coefs'); + v := string(Attributes.Value('coefs')); if (v <> '') then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); Editor.Lines.Add(Format(' coefs[0,0] := %.6g; // a', [StrToFloat(Tokens[0])])); Editor.Lines.Add(Format(' coefs[1,0] := %.6g; // b', [StrToFloat(Tokens[2]) * (-1)])); Editor.Lines.Add(Format(' coefs[0,1] := %.6g; // c', [StrToFloat(Tokens[1]) * (-1)])); @@ -5754,9 +5722,9 @@ begin Editor.Lines.Add(Format(' coefs[2,1] := %.6g; // f', [StrToFloat(Tokens[5]) * (-1)])); end; - v := Attributes.Value('post'); + v := string(Attributes.Value('post')); if v <> '' then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); Editor.Lines.Add(Format(' post[0,0] := %.6g;', [StrToFloat(Tokens[0])])); Editor.Lines.Add(Format(' post[0,1] := %.6g;', [StrToFloat(Tokens[1]) * (-1)])); Editor.Lines.Add(Format(' post[1,0] := %.6g;', [StrToFloat(Tokens[2]) * (-1)])); @@ -5766,13 +5734,13 @@ begin end; - v := Attributes.Value('chaos'); + v := string(Attributes.Value('chaos')); if v <> '' then begin chaosLines.Add(''); chaosLines.Add('{ Weight modifiers for transform ' + IntToStr(AddedXForms + 1) + ' }'); chaosLines.Add('SetActiveTransform(' + IntToStr(AddedXForms) + ');'); chaosLines.Add('with Transform do begin'); - GetTokens(String(v), tokens); + GetTokens(v, tokens); for i := 0 to Tokens.Count-1 do chaosLines.Add(' chaos[' + IntToStr(i) + '] := ' + Tokens[i] + ';') ; chaosLines.Add('end;'); @@ -5785,16 +5753,11 @@ begin end; end; -procedure TScriptEditor.F2SXMLEndTag(Sender: TObject; TagName: string); -begin -// -end; - procedure TScriptEditor.F2SXMLStartTag(Sender: TObject; TagName: string; Attributes: TAttrList); var Tokens: TStringList; - v: TStringType; + v: string; //TStringType; f, b: double; begin Tokens := TStringList.Create; @@ -5809,64 +5772,65 @@ begin // Editor.Lines.Add(' AngleTransform := 180 / PI else AngleTransform := 1;'); Editor.Lines.Add('with Flame do begin'); - v := Attributes.Value(TStringType('size')); + v := string(Attributes.Value('size')); if (v <> '') then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); Editor.Lines.Add(' Width := ' + Tokens[0] + ';'); Editor.Lines.Add(' Height := ' + Tokens[1] + ';'); f := 100 / StrToFloat(Tokens[0]); end else f := 0; - b := 0; - - v := Attributes.Value(TStringType('brightness')); + + b := 0; + v := string(Attributes.Value('brightness')); if (v <> '') then begin - Editor.Lines.Add(' Brightness := ' + String(v) + ';'); - b := StrToFloat(String(v)); + Editor.Lines.Add(' Brightness := ' + v + ';'); + b := StrToFloat(v); end; - v := Attributes.Value(TStringType('gamma')); - if (v <> '') then Editor.Lines.Add(' Gamma := ' + String(v) + ';'); - v := Attributes.Value(TStringType('vibrancy')); - if (v <> '') then Editor.Lines.Add(' Vibrancy := ' + String(v) + ';'); - v := Attributes.Value(TStringType('contrast')); - if (v <> '') then Editor.Lines.Add(' Contrast := ' + String(v) + ';'); - v := Attributes.Value(TStringType('gamma_threshold')); + v := string(Attributes.Value('gamma')); + if (v <> '') then Editor.Lines.Add(' Gamma := ' + v + ';'); + v := string(Attributes.Value('vibrancy')); + if (v <> '') then Editor.Lines.Add(' Vibrancy := ' + v + ';'); + v := string(Attributes.Value('contrast')); + if (v <> '') then Editor.Lines.Add(' Contrast := ' + v + ';'); + v := string(Attributes.Value('gamma_threshold')); if (v <> '') then begin - if b <> 0 then b := StrToFloat(String(v)) / b; + if b <> 0 then b := StrToFloat(v) / b; Editor.Lines.Add(' GammaThreshold := ' + FloatToStr(b) + ';'); end; - v := Attributes.Value(TStringType('zoom')); - if (v <> '') then Editor.Lines.Add(' Zoom := ' + String(v) + ';'); - v := Attributes.Value(TStringType('scale')); - if (v <> '') then Editor.Lines.Add(Format(' Scale := %.6g;', [StrToFloat(String(v)) * f])); - v := Attributes.Value(TStringType('angle')); - if (v <> '') then + v := string(Attributes.Value('zoom')); + if (v <> '') then Editor.Lines.Add(' Zoom := ' + v + ';'); + v := string(Attributes.Value('scale')); + if (v <> '') then + Editor.Lines.Add(Format(' Scale := %.6g;', [StrToFloat(v) * f])); + v := string(Attributes.Value('angle')); + if (v <> '') then // Editor.Lines.Add(' Angle := ' + FloatToStr(StrToFloat(String(v))* 180 / PI) + '; '); - Editor.Lines.Add(Format(' Angle := %.6g; // Flame rotation', [StrToFloat(String(v)) * 180 / PI])); + Editor.Lines.Add(Format(' Angle := %.6g; // Flame rotation', [StrToFloat(v) * 180 / PI])); // 3d - v := Attributes.Value(TStringType('cam_pitch')); - if (v <> '') then - Editor.Lines.Add(Format(' Pitch := %.6g;', [StrToFloat(String(v)) * 180 / PI])); - v := Attributes.Value(TStringType('cam_roll')); // AV + v := string(Attributes.Value('cam_pitch')); if (v <> '') then - Editor.Lines.Add(Format(' Roll := %.6g;', [StrToFloat(String(v)) * 180 / PI])); - v := Attributes.Value(TStringType('cam_yaw')); - if (v <> '') then - Editor.Lines.Add(Format(' Yaw := %.6g;', [StrToFloat(String(v)) * 180 / PI])); - v := Attributes.Value(TStringType('cam_perspective')); - if (v <> '') then Editor.Lines.Add(' Perspective := ' + String(v) + ';'); - v := Attributes.Value(TStringType('cam_zpos')); - if (v <> '') then Editor.Lines.Add(' Z := ' + String(v) + ';'); - v := Attributes.Value(TStringType('cam_dof')); - if (v <> '') then Editor.Lines.Add(' DOF := ' + String(v) + ';'); + Editor.Lines.Add(Format(' Pitch := %.6g;', [StrToFloat(v) * 180 / PI])); + v := string(Attributes.Value('cam_roll')); // AV + if (v <> '') then + Editor.Lines.Add(Format(' Roll := %.6g;', [StrToFloat(v) * 180 / PI])); + v := string(Attributes.Value('cam_yaw')); + if (v <> '') then + Editor.Lines.Add(Format(' Yaw := %.6g;', [StrToFloat(v) * 180 / PI])); + v :=string( Attributes.Value('cam_perspective')); + if (v <> '') then Editor.Lines.Add(' Perspective := ' + v + ';'); + v := string(Attributes.Value('cam_zpos')); + if (v <> '') then Editor.Lines.Add(' Z := ' + v + ';'); + v := string(Attributes.Value('cam_dof')); + if (v <> '') then Editor.Lines.Add(' DOF := ' + v + ';'); try - v := Attributes.Value(TStringType('center')); + v := string(Attributes.Value('center')); if (v <> '') then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); Editor.Lines.Add(' X := ' + Tokens[0] + ';'); Editor.Lines.Add(' Y := ' + Tokens[1] + ';'); end; @@ -5876,9 +5840,9 @@ begin end; try - v := Attributes.Value(TStringType('background')); + v := string(Attributes.Value('background')); if (v <> '') then begin - GetTokens(String(v), tokens); + GetTokens(v, tokens); Editor.Lines.Add(Format(' Background[0] := %g; // red component', [Int(StrToFloat(Tokens[0]) * 255)])); Editor.Lines.Add(Format(' Background[1] := %g; // green component', [Int(StrToFloat(Tokens[1]) * 255)])); @@ -5891,8 +5855,8 @@ begin Editor.Lines.Add(' Background[2] := 0; // blue component'); end; - v := Attributes.Value(TStringType('soloxform')); - if (v <> '') then Editor.Lines.Add('SoloXform := ' + String(v) + ';'); + v := string(Attributes.Value('soloxform')); + if (v <> '') then Editor.Lines.Add('SoloXform := ' + v + ';'); Editor.Lines.Add('end;'); end; @@ -5901,7 +5865,7 @@ begin end; end; -procedure TScriptEditor.LoadRunAndClear(scriptFile:string); +procedure TScriptEditor.LoadRunAndClear(scriptFile: string); begin LoadScriptFile(scriptFile); RunScript; diff --git a/Forms/ScriptRender.pas b/Forms/ScriptRender.pas index ea971ff..f4c8b0e 100644 --- a/Forms/ScriptRender.pas +++ b/Forms/ScriptRender.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,7 +27,7 @@ interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - ComCtrls, StdCtrls, RenderThread, cmap, ControlPoint, Translation; + ComCtrls, StdCtrls, RenderThread, ControlPoint; type TScriptRenderForm = class(TForm) @@ -37,9 +37,9 @@ type procedure FormCreate(Sender: TObject); procedure btnCancelClick(Sender: TObject); private -// PixelsPerUnit: double; StartTime: TDateTime; Remainder: TDateTime; + Filename: string; procedure HandleThreadCompletion(var Message: TMessage); message WM_THREAD_COMPLETE; @@ -47,12 +47,8 @@ type message WM_THREAD_TERMINATE; public Renderer: TRenderThread; - ColorMap: TColorMap; cp: TControlPoint; - Filename: string; - ImageWidth, ImageHeight, Oversample: Integer; - zoom, Sample_Density, Brightness, Gamma, Vibrancy, Filter_Radius: double; - center: array[0..1] of double; + procedure OnProgress(prog: double); procedure Render; procedure SetRenderBounds; @@ -64,20 +60,20 @@ var implementation -uses Global, Math, FormRender, ScriptForm, Main; +uses Global, Math, FormRender, ScriptForm, Main, Translation; + {$R *.DFM} procedure TScriptRenderForm.SetRenderBounds; +// AV: do not use it - just waste of time begin cp.copy(ScriptEditor.cp); cp.AdjustScale(ScriptEditor.Renderer.Width, ScriptEditor.Renderer.Height); - // --?-- cp.CalcBoundBox; - cp.center[0] := ScriptEditor.cp.center[0]; - cp.center[1] := ScriptEditor.cp.center[1]; - cp.zoom := ScriptEditor.cp.zoom; end; procedure TScriptRenderForm.Render; +var + ScrRender: TScriptRender; // AV begin assert(not Assigned(Renderer)); Renderer := TRenderThread.Create; @@ -86,27 +82,27 @@ begin ScriptEditor.Scripter.Paused := True; StartTime := Now; Remainder := 1; - cp.copy(ScriptEditor.cp); - Filename := ScriptEditor.Renderer.Filename; + //cp.copy(ScriptEditor.cp); // <-- AV: already done by RenderProc + ScrRender := ScriptEditor.Renderer; // AV: for speed + Filename := ScrRender.Filename; - cp.AdjustScale(ScriptEditor.Renderer.Width, ScriptEditor.Renderer.Height); + cp.AdjustScale(ScrRender.Width, ScrRender.Height); - //cp.Transparency := (PNGTransparency <> 0) and (UpperCase(ExtractFileExt(ScriptEditor.Renderer.FileName)) = '.PNG'); - if (UpperCase(ExtractFileExt(ScriptEditor.Renderer.FileName)) = '.PNG') then + if (UpperCase(ExtractFileExt(FileName)) = '.PNG') then begin // AV: added new property cp.Transparency := (PNGTransparency <> 0); - if ScriptEditor.Renderer.EmbedParameters then - Renderer.EmbedText(Trim(MainForm.RetrieveXML(cp))); // AV + if ScrRender.EmbedParameters then + Renderer.EmbedText(Trim(FlameToXML(cp))); // AV end else cp.Transparency := False; // AV Renderer.OnProgress := OnProgress; Renderer.SetCP(cp); - if (ScriptEditor.Renderer.MaxMemory > 0) then - Renderer.MaxMem := ScriptEditor.Renderer.MaxMemory; + if (ScrRender.MaxMemory > 0) then + Renderer.MaxMem := ScrRender.MaxMemory; Renderer.TargetHandle := Handle; - renderPath := ExtractFilePath(ScriptEditor.Renderer.Filename); + renderPath := ExtractFilePath(Filename); Renderer.Priority := tpLower; Renderer.NrThreads := NrTreads; // AV: now works fine @@ -135,7 +131,6 @@ end; procedure TScriptRenderForm.FormCreate(Sender: TObject); begin - //Renderer := TRenderThread.Create; self.Hint := TextByKey('script-rendering'); btnCancel.Caption := TextByKey('common-cancel'); cp := TControlPoint.Create; @@ -145,7 +140,7 @@ procedure TScriptRenderForm.btnCancelClick(Sender: TObject); begin ScriptEditor.Scripter.Halt; Cancelled := True; -// Renderer.Stop; + if Assigned(Renderer) then begin Renderer.Terminate; Renderer.WaitFor; diff --git a/Forms/SplashForm.pas b/Forms/SplashForm.pas index 0848c37..be3ca73 100644 --- a/Forms/SplashForm.pas +++ b/Forms/SplashForm.pas @@ -20,7 +20,7 @@ type public procedure SetInfo(info:string); end; -const DURATION: integer = 900; + var SplashWindow: TSplashWindow; @@ -28,6 +28,9 @@ implementation {$R *.dfm} +const + DURATION = 900; + procedure TSplashWindow.FormCreate(Sender: TObject); begin lblVersion.Caption := APP_VERSION + APP_BUILD; diff --git a/Forms/Template.pas b/Forms/Template.pas index 338a318..f946281 100644 --- a/Forms/Template.pas +++ b/Forms/Template.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -27,9 +27,9 @@ unit Template; interface uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Translation, - Dialogs, StdCtrls, ComCtrls, ImgList, ControlPoint, cmap, RenderingInterface, Main, - Global, Adjust, System.ImageList; + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ComCtrls, ImgList, System.ImageList, + ControlPoint, cmap, RenderingInterface, Main, Global, Adjust, Translation; type TTemplateForm = class(TForm) @@ -47,54 +47,55 @@ type private { Private declarations } Files: TStringList; // AV: replaced "useless" hidded TListBox + + procedure ListTemplateByFileName(filename: string); + procedure LoadUserTemplates; + procedure DropBlank; + procedure DropListItem(FileName: string; FlameName: string); + procedure ListTemplate; public { Public declarations } end; var TemplateForm: TTemplateForm; -const - blankFlameXML1 = ''; - blankFlameXML2 = ''; - blankFlameXML3 = ''; - - procedure ListTemplateByFileName(filename:string); implementation {$R *.dfm} -function LoadUserTemplates2(mask: string): integer; -var - FindResult: integer; - SearchRec : TSearchRec; - Path : string; -begin - Path := AppPath + 'Templates\'; // AV - result := 0; +procedure TTemplateForm.LoadUserTemplates; + procedure LoadUserTemplates2(mask: string); + var + FindResult: integer; + SearchRec : TSearchRec; + Path : string; + begin + Path := AppPath + 'Templates\'; // AV - FindResult := FindFirst(Path + Mask, faAnyFile - faDirectory, SearchRec); - while FindResult = 0 do - begin - ListTemplateByFileName(Path + SearchRec.Name); - result := result + 1; + FindResult := FindFirst(Path + Mask, faAnyFile - faDirectory, SearchRec); + while FindResult = 0 do + begin + ListTemplateByFileName(Path + SearchRec.Name); - FindResult := FindNext(SearchRec); - end; - { free memory } - FindClose(SearchRec); -end; - -function LoadUserTemplates: integer; + FindResult := FindNext(SearchRec); + end; + { free memory } + FindClose(SearchRec); + end; begin LoadUserTemplates2('*.flame'); LoadUserTemplates2('*.template'); - Result := 0; // make RTL happy end; +(* function BlankXML: string; +const + blankFlameXML1 = ''; + blankFlameXML2 = ''; + blankFlameXML3 = ''; var - i: integer; + i: smallint; s: string; const break = ' '; @@ -107,10 +108,10 @@ begin s := s + ''; Result := s; end; +*) -procedure DropBlank(); +procedure TTemplateForm.DropBlank; var - flameXML: string; cp: TControlPoint; bm: TBitmap; Render: TRenderer; @@ -120,38 +121,37 @@ begin Render := TRenderer.Create; bm := TBitmap.Create; - cp.Clear; - flameXML := BlankXML; - MainForm.ParseXML(cp, PCHAR(flameXML), true); - cp.AdjustScale(TemplateForm.UsedThumbnails.Width, TemplateForm.UsedThumbnails.Height); + // AV: we don't need any parsing and cleaning here + cp.xform[0].density := 0.5; // AV: that's all we need to create a new flame + cp.cmap := MainCp.cmap; // AV: make black dots visible + cp.pixels_per_unit := 5; // AV: decrease the scale + cp.AdjustScale(UsedThumbnails.Width, UsedThumbnails.Height); // start preview - cp.Width := TemplateForm.UsedThumbnails.Width; - cp.Height := TemplateForm.UsedThumbnails.Height; - cp.spatial_oversample := 1; - cp.spatial_filter_radius := 0.1; - cp.sample_density := 0.5; //3; - try - Render.SetCP(cp); - Render.Render; - finally - BM.Assign(Render.GetImage); - cp.Free; - Render.free; - end; -// Thumbnails - TemplateForm.UsedThumbnails.Add(bm, nil); + //cp.spatial_oversample := 1; // <-- AV: true by default + cp.spatial_filter_radius := 0.1; + cp.sample_density := 3; + try + Render.SetCP(cp); + Render.Render; + BM.Assign(Render.GetImage); + UsedThumbnails.Add(bm, nil); + finally + cp.Free; + Render.free; bm.Free; // AV: fixed multiple memory leaks! - ListItem := TemplateForm.TemplateList.Items.Add; - ListItem.Caption := 'Blank Flame'; - ListItem.ImageIndex := 0; - TemplateForm.Files.Add('n/a'); + end; + { Thumbnails} + ListItem := TemplateList.Items.Add; + ListItem.Caption := 'Blank Flame'; + ListItem.ImageIndex := 0; + Files.Add('n/a'); //end preview - // + Application.ProcessMessages; end; -procedure DropListItem(FileName: string; FlameName: string); +procedure TTemplateForm.DropListItem(FileName: string; FlameName: string); var flameXML: string; cp: TControlPoint; @@ -163,46 +163,42 @@ begin Render := TRenderer.Create; bm := TBitmap.Create; - cp.Clear; + //cp.Clear; flameXML := LoadXMLFlameText(filename, FlameName); - MainForm.ParseXML(cp, PCHAR(flameXML), true); - cp.AdjustScale(TemplateForm.UsedThumbnails.Width, TemplateForm.UsedThumbnails.Height); + MainForm.ParseXML(cp, flameXML, true); // AV: fixed - was PChar instead String + cp.AdjustScale(UsedThumbnails.Width, UsedThumbnails.Height); // start preview - cp.Width := TemplateForm.UsedThumbnails.Width; - cp.Height := TemplateForm.UsedThumbnails.Height; - cp.spatial_oversample := 1; - cp.spatial_filter_radius := 0.1; - cp.sample_density := 3; - try - Render.SetCP(cp); - Render.Render; - finally - BM.Assign(Render.GetImage); - cp.Free; - Render.free; - end; -// Thumbnails - TemplateForm.UsedThumbnails.Add(bm, nil); + //cp.spatial_oversample := 1; // <-- AV: true by default + cp.spatial_filter_radius := 0.1; + cp.sample_density := 3; + try + Render.SetCP(cp); + Render.Render; + BM.Assign(Render.GetImage); + UsedThumbnails.Add(bm, nil); + finally + cp.Free; + Render.free; bm.Free; // AV: fixed multiple memory leaks! - ListItem := TemplateForm.TemplateList.Items.Add; - ListItem.Caption := FlameName; - ListItem.ImageIndex := TemplateForm.TemplateList.Items.Count - 1; - TemplateForm.Files.Add(FileName); + end; + { Thumbnails } + ListItem := TemplateList.Items.Add; + ListItem.Caption := FlameName; + ListItem.ImageIndex := TemplateList.Items.Count - 1; + Files.Add(FileName); //end preview - // + Application.ProcessMessages; end; -procedure ListTemplateByFileName(filename:string); +procedure TTemplateForm.ListTemplateByFileName(filename:string); { List .flame file } var - sel: integer; i, p: integer; Title: string; FStrings: TStringList; begin - sel := 0; if not FileExists(FileName) then exit; FStrings := TStringList.Create; FStrings.LoadFromFile(FileName); @@ -214,17 +210,15 @@ begin p := Pos(' 0) then begin - MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FSTrings[i]))); + MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FStrings[i]))); // AV MainForm.ListXMLScanner.Execute; if Length(pname) = 0 then Title := '*untitled ' + ptime else Title := Trim(pname); - if Title <> '' then - begin { Otherwise bad format } + if Title <> '' then // Otherwise bad format DropListItem(FileName, Title); - end; end; end; end; @@ -233,27 +227,21 @@ begin end; end; -procedure ListTemplate; +procedure TTemplateForm.ListTemplate; begin - TemplateForm.TemplateList.Items.BeginUpdate; - TemplateForm.TemplateList.Items.Clear; - TemplateForm.UsedThumbnails.Clear; + TemplateList.Items.BeginUpdate; + TemplateList.Items.Clear; + UsedThumbnails.Clear; // AV: fixed - someone forgot to refresh the file list - TemplateForm.Files.Clear; - // hmmm... - (*for i := 0 to TemplateForm.UsedThumbnails.Count - 1 do - begin - TemplateForm.UsedThumbnails.GetBitmap(i, bm); - bm.Free; - end; *) + Files.Clear; DropBlank; ListTemplateByFileName(AppPath + templateFileName); LoadUserTemplates; - TemplateForm.TemplateList.Items.EndUpdate; - TemplateForm.TemplateList.Selected := TemplateForm.TemplateList.Items[0]; + TemplateList.Items.EndUpdate; + TemplateList.Selected := TemplateList.Items[0]; end; procedure TTemplateForm.FormCreate(Sender: TObject); @@ -273,20 +261,21 @@ procedure TTemplateForm.TemplateListChange(Sender: TObject; Item: TListItem; Change: TItemChange); var fn : string; + i: integer; // AV begin if (TemplateList.Selected = nil) then btnOK.Enabled := false else begin - if (TemplateList.Selected.Index >= 0) then begin + i := TemplateList.Selected.Index; + if (i >= 0) then begin btnOK.Enabled := true; - if (TemplateList.Selected.Index > 0) then begin - fn := ChangeFileExt(ExtractFileName(Files[TemplateList.Selected.Index]), ''); + if (i > 0) then begin + fn := ChangeFileExt(ExtractFileName(Files[i]), ''); if (LowerCase(fn) <> 'apophysisav') then - lblFile.Caption := TextByKey('template-filename') + fn + lblFile.Caption := TextByKey('template-filename') + #32 + fn else lblFile.Caption := ''; - end else begin + end else lblFile.Caption := ''; - end; end else btnOK.Enabled := false; end; @@ -295,46 +284,66 @@ end; procedure TTemplateForm.btnOKClick(Sender: TObject); var flameXML: string; - fn: string; - ci: integer; - blank: boolean; + i: integer; begin - fn := Files[TemplateList.Selected.Index]; - blank := (TemplateList.Selected.Index = 0); - if blank then - flameXML := BlankXML - else - flameXML := LoadXMLFlameText(fn, TemplateList.Selected.Caption); MainForm.UpdateUndo; - MainForm.StopThread; - MainForm.InvokeLoadXML(flameXML); - Transforms := MainCp.TrianglesFromCP(MainTriangles); + // MainForm.StopThread; // AV: this is already done in the Main unit + + i := TemplateList.Selected.Index; // AV + + if (i = 0) then // AV: we don't need to waste time to parse an empty flame + begin + with MainCp do begin // AV: make a blank flame easier! + Clear; + name := 'Blank Flame'; + // AV: fixed a bug with black flames on the black background + brightness := defBrightness; + gamma := defGamma; + gammaThreshRelative := defGammaThreshold; + contrast := defContrast; + vibrancy := defVibrancy; + sample_density := defSampleDensity; + { AV: 2D-camera resetting } + center[0] := 0; + center[1] := 0; + zoom := 0; + FAngle := 0; + { AV: 3D-camera resetting } + cameraPitch := 0; + cameraYaw := 0; + cameraRoll := 0; + cameraPersp := 0; + cameraZPos := 0; + cameraDOF := 0; + xform[0].density := 0.5; // AV: make the single xform visible + xform[1].symmetry := 1; // AV: hide final xform + CalcBoundBox; + end; + Transforms := 1; + EnableFinalXform := false; + end + else begin + flameXML := LoadXMLFlameText(Files[i], TemplateList.Selected.Caption); + MainForm.ParseXML(MainCP, flameXML, false); + Transforms := MainCp.TrianglesFromCP(MainTriangles); + end; + MainForm.Statusbar.Panels[3].Text := MainCp.name; {if ResizeOnLoad then} MainForm.ResizeImage; MainForm.RedrawTimer.Enabled := True; - Application.ProcessMessages; - MainForm.UpdateWindows; - // AV: fixed a bug with black flames on the black background - if RandomizeTemplates or blank then // AV + if RandomizeTemplates then // AV if (randGradient = 3) then // AV: only if user prefer new palettes AdjustForm.mnuRandomize.Click else begin // AV: use preset palette - ci := Random(NRCMAPS); - GetCMap(ci, 1, MainCp.cmap); - MainCp.cmapIndex := ci; + i := Random(NRCMAPS); + GetCMap(i, 1, MainCp.cmap); + MainCp.cmapIndex := i; end; - if blank then // AV: fixed resetting values to 1 - begin - MainCp.brightness := defBrightness; - MainCp.gamma := defGamma; - MainCp.gammaThreshRelative := defGammaThreshold; - MainCp.contrast := defContrast; - MainCp.Vibrancy := defVibrancy; - Maincp.sample_density := defSampleDensity; - end; + Application.ProcessMessages; + MainForm.UpdateWindows; ModalResult := mrOK; // AV end; diff --git a/Forms/Tracer.dfm b/Forms/Tracer.dfm index 80e13ef..0131a3f 100644 --- a/Forms/Tracer.dfm +++ b/Forms/Tracer.dfm @@ -96,6 +96,10 @@ object TraceForm: TTraceForm object TabFullscreen: TTabSheet Caption = 'Fullscreen' ImageIndex = 52 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object FullscreenTrace: TMemo Left = 0 Top = 0 @@ -116,9 +120,9 @@ object TraceForm: TTraceForm end end object cbTraceLevel: TComboBox - Left = 280 + Left = 240 Top = 0 - Width = 121 + Width = 147 Height = 21 Style = csDropDownList Anchors = [akTop, akRight] diff --git a/Forms/Tracer.pas b/Forms/Tracer.pas index 5353fef..06fe5d2 100644 --- a/Forms/Tracer.pas +++ b/Forms/Tracer.pas @@ -5,6 +5,7 @@ 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 @@ -23,13 +24,13 @@ unit Tracer; -{$define TRACEFORM_HIDDEN} +//{$define TRACEFORM_HIDDEN} interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, StdCtrls, ComCtrls, Translation; + Dialogs, StdCtrls, ComCtrls; type TTraceForm = class(TForm) @@ -50,9 +51,7 @@ type var TraceForm: TTraceForm; - -var - TraceLevel: integer; + TraceLevel: shortint; const MsgComplete = '< Received WM_THREAD_COMPLETE from RenderThread #'; @@ -65,8 +64,7 @@ implementation {$R *.dfm} uses - Registry, - Global, Main; + Registry, Global, Main, Translation; procedure TTraceForm.cbTraceLevelSelect(Sender: TObject); begin @@ -92,26 +90,17 @@ begin if Registry.ValueExists('Height') then self.Height := Registry.ReadInteger('Height'); -{$ifndef TRACEFORM_HIDDEN} + {$ifndef TRACEFORM_HIDDEN} if Registry.ValueExists('TraceLevel') then TraceLevel := Registry.ReadInteger('TraceLevel') else TraceLevel := 0; - MainForm.tbShowTrace.Visible := true; - MainForm.tbShowTrace.Enabled := true; - MainForm.tbTraceSeparator.Visible := true; - MainForm.tbTraceSeparator.Enabled := true; - -{$else} + {$else} TraceLevel := 0; - //MainForm.tbShowTrace.Visible := false; - //MainForm.tbShowTrace.Enabled := false; - //MainForm.tbTraceSeparator.Visible := false; - //MainForm.tbTraceSeparator.Enabled := false; - -{$endif} + MainForm.mnuTrace.Visible := False; // AV + {$endif} end; Registry.CloseKey; diff --git a/Forms/VarOrderForm.pas b/Forms/VarOrderForm.pas index eba08eb..22b3dc0 100644 --- a/Forms/VarOrderForm.pas +++ b/Forms/VarOrderForm.pas @@ -1,4 +1,4 @@ -{ Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina } +{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } unit VarOrderForm; @@ -6,9 +6,8 @@ interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, StrUtils, System.Variants, - System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Editor, Translation, Vcl.StdCtrls, - Vcl.ComCtrls, Vcl.ExtCtrls, Vcl.Buttons; + System.Classes, Vcl.Graphics, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons, + Vcl.Controls, Vcl.StdCtrls,Vcl.ComCtrls, Vcl.ExtCtrls, Editor; type TVarOrder = class(TForm) @@ -56,7 +55,7 @@ var implementation uses - XFormMan, Global; // to get default variation order + XFormMan, Global, Translation; // to get default variation order {$R *.dfm} @@ -66,7 +65,7 @@ begin if not assigned(VarListView.Selected) then begin Application.MessageBox(PChar(TextByKey('varorder-noselected')), - PChar('Apophysis AV'), MB_ICONWARNING); + 'Apophysis AV', MB_ICONWARNING); exit; end; @@ -108,7 +107,7 @@ begin if not assigned(VarListView.Selected) then begin Application.MessageBox(PChar(TextByKey('varorder-noselected')), - PChar('Apophysis AV'), MB_ICONWARNING); + 'Apophysis AV', MB_ICONWARNING); exit; end; @@ -123,7 +122,7 @@ begin if not assigned(VarListView.Selected) then begin Application.MessageBox(PChar(TextByKey('varorder-noselected')), - PChar('Apophysis AV'), MB_ICONWARNING); + 'Apophysis AV', MB_ICONWARNING); exit; end; @@ -150,7 +149,7 @@ begin if not assigned(VarListView.Selected) then begin Application.MessageBox(PChar(TextByKey('varorder-noselected')), - PChar('Apophysis AV'), MB_ICONWARNING); + 'Apophysis AV', MB_ICONWARNING); exit; end; @@ -255,7 +254,7 @@ begin or (s = 'affine3D') or (s = 'spherecrop') then ListItem.ImageIndex := 6 // violet else - ListItem.ImageIndex := 5 // blue; + ListItem.ImageIndex := 5 // green; end; procedure TVarOrder.ShowSelected(const i: integer); diff --git a/Forms/formPostProcess.dfm b/Forms/formPostProcess.dfm index 6dcef9a..b31d5ad 100644 --- a/Forms/formPostProcess.dfm +++ b/Forms/formPostProcess.dfm @@ -250,8 +250,8 @@ object frmPostProcess: TfrmPostProcess end end object btnSave: TButton - Left = 588 - Top = 510 + Left = 580 + Top = 509 Width = 97 Height = 25 Anchors = [akRight, akBottom] @@ -270,7 +270,6 @@ object frmPostProcess: TfrmPostProcess State = cbChecked TabOrder = 3 Visible = False - OnClick = chkFitToWindowClick end object ColorDialog: TColorDialog Left = 612 diff --git a/Forms/formPostProcess.pas b/Forms/formPostProcess.pas index 6f7d6ed..f374a95 100644 --- a/Forms/formPostProcess.pas +++ b/Forms/formPostProcess.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 @@ -28,8 +28,7 @@ interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, ExtCtrls, RenderingInterface, controlpoint, StdCtrls, ComCtrls, - Translation; + Dialogs, ExtCtrls, RenderingInterface, ControlPoint, StdCtrls, ComCtrls; type TfrmPostProcess = class(TForm) @@ -56,7 +55,7 @@ type btnApply: TButton; pnlRelGamma: TPanel; txtRelGamma: TEdit; - procedure chkFitToWindowClick(Sender: TObject); + // procedure chkFitToWindowClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnSaveClick(Sender: TObject); procedure btnApplyClick(Sender: TObject); @@ -87,18 +86,13 @@ type mousepos: TPoint; BkgColor: TColor; - Filter, - Gamma, Brightness, RelGamma, - Contrast, Vibrancy: double; - + Filter, Gamma, Brightness, RelGamma, Contrast, Vibrancy: double; ImCount: shortint; // AV: the number of saved images - NewName: string; // AV procedure UpdateFlame; procedure SetDefaultValues; procedure OnProgress(prog: double); - public cp : TControlPoint; @@ -113,7 +107,7 @@ var implementation uses - Registry, Global, Main; + Registry, Global, Main, Translation; {$R *.dfm} @@ -319,6 +313,7 @@ end; /////////////////////////////////////////////////////////////////////////////// procedure TfrmPostProcess.btnSaveClick(Sender: TObject); +var NewName: string; // AV begin inc(ImCount); if ImCount = 0 then @@ -554,15 +549,16 @@ begin chkFitToWindow.Caption := TextByKey('postprocess-fittowindow'); end; +{ procedure TfrmPostProcess.chkFitToWindowClick(Sender: TObject); begin - {if (chkFitToWindow.Checked) then begin + if (chkFitToWindow.Checked) then begin Image.Stretch := true; Image.Align := alClient; end else begin Image.Stretch := false; Image.Align := alNone; - end; } + end; end; - +} end. diff --git a/HARLOWSI.TTF b/HARLOWSI.TTF deleted file mode 100644 index 3c59ef94e57a21d370886f8f4233e5c2a21cdb9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55060 zcmbTf30zxM+CP5IT@sQ22?-DgOBNs@5C{+;fv|*qEtI{bE2X8-y|w#pH|?s`+FGqv zYpqMImaVu{ty=52)U8^VI(0_J8TZcL8ONpN@_Wv`HzBmn`@WyQ_Hu7dl6%j2&a-@< z<(wdl5DG>c5sjvoHdR%`|2v@wp_dH^h5oy~$)0iZ_sg;n!rkzx*3S7IiyDefYZ0P9 zgCnzZ`BH=AUCB0tWR>uK#O!&iy0$hgI*m}!-3aw1cF*dV`O5E2Zg}r|II_E;LHQrH z748=guj9MtFJ1Z8`hNw&_opMoxaQ7UvH+3(pqHcJ4>NCJXU7kl&%BC|RD}=~JHKP) zB0LvA4BscuGc4$sKP&QN%5Hdl2HuZcwD6{-7d0nC5PFfkZeO%y)}q#Fvwws8r@`kV z_#jSrmcu#cK%)$1P+mO$)o0uIN}Y%VsE9xMK4#SL926(@+ zW68XQE8tV}dS)7`mUhhR=@kC{!5e?j)H-X)O+5=27}8U-vxK+#JE0cTh}w_=HKB#5 z3oS(}PzOxZEM$YW5@=flgIt1o&}`HV?;21#%7OnKa5V$oF^J!<J?sW7cs$p71;eIo3@a~?T|l34)O z(7_?`vIv|Br+K-Ye2)AFpQ9O8A`Otq6@fv)N>zwj6B-t-jfm7mMaRVI4MtO3e1h4M zXiZACrKH-^(lZ>HS=mlkPOdvIzo5`lR9sS8R$ftARb5j%uC9K3Lt|5OOKaPNiS3gn zPnkMxdIy@(IdfLm?Czd9bLY)puyE1hB{wZywtU6PRjb#mUAKP2#+x^7-m-PuEw^sp zv2)k%J-6My_l`UF-L?O~-3RZv_t1U!AAaD$BM%*Y_}C+lKKA%=^u&oLpE}vw*FP|L zYUt@_o_+50^Dn%3=B1ZkIs59l*Z%bS8*jdK{_S_(Men_T;e!t^e)RDtpI-Xx&zC<( z384o;Z~T)Q8G(Bm&;#fsdK&K4h^O=SItTaq81AJpL>QtC z2L4_-H{2`IcdwanFFZ0b@+FxJghq~zOc~iYQaloh5T``w+NHnTFTC@Yt$(@eFI)bi z`h3pkt1j=qeB|=Z%eP)WhS24umlt22cG-S8?b9DsFYq#52~4_3_!j^7-|&|l2>p&Y zd_4#7Z@`~_dM|uu8a;%zpshFv?MGjrZDp`%EJcA(AZPV^n<`rYUNx)ptf zzD4(=$I*}I2XqA;K~JDRp>ya22vjG!9s2VIu=8u^b@VoR6TOAbqc1@)-$U=9cVRYW zqi@h&^a1G33m}kRp?{$5Xbv#`Tr?kqYyr@CAzBP0BI2+NL~l6=JqU4O)lR zq9ODk+5j`V5#5abj=o0Epo{2p^a=VDT|$@9N9fOJ5a#?9)Q<+xS+ohggl<7EBd{$f zLHvIudJ}KNzfp(ia(W@%OaF^m&0J&ySr6O89%O%%SR@CfA=0%0vViV@BeGc8X4zZv zc=<$mpZxENjzCM`_d)%^*})$w?^GqJehqnAouGa})1>(|^k|qT?49sAT1xv$L}$de zk*jnPU0+m3bawQcG1{1lm^)+6#9WS*$8L}PkG@6!fg#6m*jQlf1D<=tG!mB=_g=gw zetZ0tgwBKu=6v%pi_S8^@^oTg;)%qo*45U7NfAjilIAC^OfE{UO>Rq`kvuL`%G|QZIZ?-ynYWCyK0_W4NP}fq|`#GUGH|Hkg z-scW>Kbx1B_fX!i`3d>k^8Z~hx8Q+-k-`~;{e>?SzFzo&XM0g%(bS@SMZXlc7w;}U zQ<74$uw-?~){-YnOH0?5o+_JHj>8LEItg39ToK`ufa#`iZ%AJ+_ zD<7NlB ztEzjr?z8%``WMEpXoznNZXDORvhir+<)+l8MNLmNecCK(_B3y3e!Tf&i>hUM%i)$c zTK?0T*1ECvxz^v?651NtcD9{r`*}jV2D9i2h!$_{iHPw>13F2+h7Z!G(F!=8V&`MKqzTQZ8t_5tI~+uP zhj!Da@$K;5IXr@9;#<);IPa%1nh$Na!h6kd-VDdxaBPR;J~)m-JBBmd7fZu+`YG?(V|AeN~sc0H?a-@e|J3`YVsG3SfQ>lr= z@6wCm8q6;HHmYVYs;0-oXV;H7=vp|Jq892+R7G{8F8UMr{8Ol#*^RoX=TIcQfV)EL z;r=VoZScHJ^oo&(*%tH+88>v(w2#$H4XY!Rw~*Yl}ibd>rl+7In+W*GY4g7WF{ zBj>3Gq#@shb_Dm@1=qoF9Z#=A=gGldL;JmSBJ(YM9eu)@;QOc1CgyH5j`|U=CkGx7 z4ro6I-#xU!%moMGvE6XI0mpA}yi53$@CsaSBK%I~ zi1d~8nea2uQ>W1o)q~eiJ?I*orIJFtMm(ee?Gj5syL3LBe}Lm2I6j5f(kU zOoF498K4s2xB^E7939esNocm5u4Ky@7S7w?SOLdPY#aTaNfeYO zBvhTF3AGPtG1g-EvbUjEf(qeFNGkDuDLpMABRnir5@#}JWoBbqxNvH+9i$oOD58AR)36c?4===;0?a?2y|Ib&RRUh_d2K!UNalNb4_<9YC?6mJg1^E)8-!gI)$k46`(_QGoPYDa2rl| zqDzX4Jo(OSM|zswmSiy+Vzl9!5S21e4l|URYKQ;HU*X^Ab!sXaFdDSswAP+CfSf=( zxZuZos<@kj?Y3W(%@ev+9{Vlr#VSSp^pq>Gb!ugHA5u~R$=-;&Z&hm(5n zo>}&ZR%d9-g0}J6tc7jkBWI;eu)4xp?&-3VbMwLp^$}T%Ce-W5YiH=gS@&eo^M6~K zmY~geM_TR5znT2`eW^VzGV>jB(m9~nSpdz>0`jqlbZ+j=Hxn=9sgVVYksSwa&MZ%G zN|MPK8>Nd-E2R<|`RK`$)*}Zcs8GrkNdjl`41F@p-WR1)+w<~HrU|UnZ!${5RKt1w zQi(JT&OAx`Q&5@&D40X&lOd4Bqz%_<2yMIsaS9yn#u-_e7TQ9{Qiy>n^a0iCsV$o# zn`s>Kuybgg+S+EzlSNeIPicC3e&9f``L4CW@oh7h_a>KAL-xq60T^2Yd}2)G*zS?XB8=hi$}->DpAJ%1SV-=e&!)RrYbYC_ zWYO3=0!?@U7x}`Otu;%+LLC{-?5s>06K)C%l@iIz%KYyiqz<=t&#b9iIBD*p1>2mr zrsZYU_ER1_2$)BZ zOW+_uEP2@^9OP02#VbO+1OOc~fD$ddV4k$udv%ebfDUFj;3hVe_Ro2z$fYQs{RTZ7 z>1C=RImU2D2(^gHv`>u*lY#nl2grp-=wnAYj;4$zl$EJ=X7eKF1lbc<(If?Whr2P) zZNQOIY&1!OF|;`{vYqUKxD9RftBo0qT$vu*(KGA0oaPAyrKx4h%A3~f z=DHH~h1_4v=BH*Zy=&QYkVT@Kso!|rtn3AhXGi^l@`W+{?|SwIy-MyF#GRwRVP8Sv zD5FmuNEjTb6ChW6se}4KharvXtY#<}LuAd5nj%|D<)GuVK$SR?#T=r-1(;r&mY@IU zS0d=Hw!|!4HRopb6<2cNIPP0c!hN#!y;#lcC3nNee#S4|2F@@>yP*#~Vjsc+8KDm$ za^?^EAj249VWTrj`k)Pmrv_tQIXHDVB$H?cY7m~y4RvpJi+y2VS#p4TiBoWeyO)sO z;4pj@TQ*$OYi1KV+)h2t6aZzNXkl-lLS(W&5N^@b4Q8e!F-W00bN1|+v%OJj)!9?= z@y0L^{}8n{$Bu?97+ZW24+8Je#70OlPBF$tgas<3NahuMEid@?{&Y%-d3#_<#h}T+ zBIOq~ za#B7Ub8}Q!xV_xqWP-|6I(<%UsP&~!b5n|KVM+HF2bU)%R)tOLvxOuSTBBv=k59&{ zY8^H`2n>e!z;Py@F(Ex__XHA|4JWo#CJ{BhAhRHudbw=WWa=V`nUwj=O-_RA``5SEQ|JG> zG(A2deW)p?=!=`u;v+K173ufPk!IYBuA&f>-X9DKI2Cva4FzHh!R=9|@yJ*VPN8qM zgzoS%&l_fZ+fS>tdE{t)h=L@tk9 z87K>oLg<)iH9{To2Mv(6QTiYyg;`qSqfdI8hF37jG!NVyFCNuQo2EIcNy^Ghrcg_( z-D0-GbM}vXg-@VsfEvvwW!K}y{}m0IMD*tad~nD4AaA?bdmvV1>J63((ke<=4eeM(fqfLe8)60 zmw+;{sH~S*O`_Oi6m;0Att8+P#14An2WMlj^gC;M;RI&}Zw={8&R&a+S-MK7aH)K7I4niyti* zK@%$5hUVk&u0!znX7D_|V$MTcHsw@^%+D&>QLj`YYJq-)S&7%C^adk>;dl<^XOB0$ zpl}K?^s6*rqu?hPi9L%m5`J@HKo90P6IixU{o4@7gsVdV2TB_sj&KY6@E92~4&o zTH;N{7^O@QN73B#ED@=oGz!uA;h|F>d>Ei255WN^vKBAdJu+U1$B3-R`{AsgCqy8% zRKgEX91F4BV5I>ul1ZY(i6exN(#7}GZQ(|az1dZnRGJ%t<2rz8!oK!tVyi^mKZH z;{YOS!_*^4AFi;7^Iu>5)ajbVm8+lW3`41FLoswis~CG zN*sw)`0l2Hlo~D&-_3QyEZzsR*afqgg>Lr9voh?diRwTJkJ><~lJN*aEzv3h{dlz( z#wpGp$_hyJ&7V90Jllj(*OoVer)W?-S%Sxuqp|nO1o=0xw2t*-3y?RdFq=rQeWLs1 zn_6IFFD;zJ@ig*qIgUD6lceABAotB%cfByNJS|TmW86s-_T;CVOeKc+G*8G8T|pzR zFDsbbNPjmZ8#?eQ_tE3qIyX9Pp^=slO+wbtVpq8)KBUkdnS^gEice1SRFL^T3R>e! zkl}D-LgV{23YNDsgd7G1s~e-^Jb@~RQmQEAvwed3?-f;DOhAB^rAFxoL-iji2&p($ znh2`E$Y$!kIMvd_+?VGLomqtq)vYOo#*ia*yNfa!Z!e+q*n!QTac55-y!|Eo)^fMi zmZjrXK0Vu2J=E=n-eZh`Tgyb9r~V&wUcji%Q}SGA1wv+rqJI{E-YVb%el5jHz_ySTt&>uLExnpkdQEt5gS@Gs0mUC))@>m@qLmM zRJZMt?NL5=ROq!4klRvnuaxc=G{T zL1Z0b<>PspO8iKQ{isXd)WQAZrTfm_y|x+VA zPa%Plu?%D%ioiI+AL@Xy^!4zD{sGsBqy@$&#vacRd$+_7B#!oUc+(Adu@vp0pJTp+ z8i1l+2}=S_45&W{IQ0Q61g{i%0DQ3wO)*~j5l;7j4+~m%jQRlDg~`Bw$)cYd-bc;5 zww?L%D)%n;_OJNNhh(m{;K|HJh}@I8ngy6qh~R}OWZ=svWvV~-(F&#L*7Rv)Veo8^ zOdS*`l^}^yM%&<4)e@&rtDO$gpVf4sl~$VB^H<6dg~ zhW7g5lN;KzsRn@Y!%wYmrxycShkxAD!WnE$DP&uoWBy8L<0A`Cq&|wpUfMw56%xi` zY}88|AlP-Zac0SI77i<=<_+(oSM2^BQo!lIa-I)}JgP>%VnX-`Y&z;1uv>LX5`zU^ z4uX86!mgJq{n%L$OSugqur{#DVoa7dT)ay$Mlc~NO9a9c5a?qffz8LnW_dQ3N_@tu z06e}MFc?1Mjo3Esd%b1u6KYFriM`)>x81h z)E)1&=37!cH5r<`xJX<6hUrHx5PtY&9u?JcuQnW5I5owZ=yP!TLsV=y;Sqo|iR4`9 z;m>@4uP@n?NEj{9m5H${8{$^bF%p*%?V$o%vVldiRY~+=9 zoY7!0Q+%u@-eExC93*3t1%jzWoj|Nf>$RH@O@ye8m&(ka3hGyU)X!ZyeczFaZ8&#J zLdLz^HSVu>tl2hy`Z8SeG*;mHkq2jwkFF@1)3xqD_pWf-YphPCoJ-W!>WYFgOr;yC zz)$zy)%TZY|MtaA8EQwuoX#d3aNjO$T)h1N_vIItxd#dh?^xc4BOA*z%~5eWuD9?3 zLzph%aPxG~HX}cAwtxp9n~;HA!1d30bh$aMOh;OZEjiJg5Ko|Ebd)YUI7p0J^Po|f z6~9YRRfRICp#H&;BHWA3Oac=RsU*@$JOtt*^ucWbP7gU;aMR!*i8s3Kk>})sJv3rQ z66AA72N}#H6DJwM+V)czXL@G{IKEedNz$QM>Wj$`na93(S-jEV1h>qKRm8X%MSCxJ zha(ECk`l8plVa%1DH+Fo#|?hVz4$8k^V@w}aVZX}u7CK)gTEA32FjkO)h(J_9JPMo zL;U$->wIhP?Q`}{v2ryn+!v3|-LSgtz)}hgzryw4sP`Vn?(W)xz1Tjh$d#ehYq^FF zcN2GIdS27S3g;}`k2|HS4wqh;Q~Fl-v|IiJPS}X!+E>y{m_MA$OsU=NM^{9hos1TAXrcvVK5~bOgaM^3+Rd=65ySh z^XJc#>ES16prBC5KJ?~85=qEBI5N!%jF5Q{LgP3FW(5LpgV+N2IZsF^z-*LCV!SK> zvjMCR%GV8=7{HE%I|Iwd7d~?Fsjp@<&wmb2q1y6xRhk`DF_V;>wc+BziiykiHVr?< zT|3*7Kj|pb1tdT5z>d%C6F=F>{XBkN^t~H%55D{0?B4W3Is_M)=A|}8DXy-pwjXVp zG5*?>U9P&lL`SXSuCPzCbHFc7L+d&e3|jGd%uKbAdZ(ege-7BhSB+WzSqF>bt+@vJowY)#5q3)+G33U8iOh{;8mqjIxvLDe08eqQU|AF;DH4NBN)FD3AJpd13Ai)Q&H_7Yu z;|PJ}$n7&E5pj$kiT!!afWUf4nCschiX8?G3Cx(|MmejxGiu=^;H(5}#<|?j2e{4L zf69TiJdb?bM_B7w+=(L-arS$&mL1)F?Md#Jv#kY_j{!gBH*#Ndzi|t>zSB=cA6oA| zc;TU$Po+bOaSP7ee8;1|Z{L~2^AJxxk_mUAB6QYc0L|*m%z%tws@0&6jf#vQagGpW za8RH^E@c6V^BhH}c!PrF8$iVJWL7U@AYu@4AfsU948XKeX%=P(&Le{!K|dIPQQmxFKQ;^GCVE|B_C65^EjY6v&&k;6Q>HYSK%wb6 z;r6oWs5sNTZy1Z)DQ3r{k|?hA?sYt8K6RPu*DZpU;i#bUde0-D^a|vkaak5YWS=|8 z{d%^|)BZ4Z1%K0En_AGsZ3ksKd>O8I`oDi<*2(lj$~42>cn$5$8FvSwMn2-w18hM1 zcw|TSctVIN)5k<>!<5%Eu9w^})+CwIJ63_Z@k|_JVsH$U9g{aSDnV5ec12ohG&?(# zU?#U^MpLpk#CZF{uoNsAJS9acs%9S4do9vvt|#6BtOSY>q6Pw0v4Azg9T^(delwwz zZs6rNxTWuK|9o)o8eDOBx9yBVThUD6orGE~!@p;9ANQVHH|67<6froQkyByCoA+Zw zcUu>O@t4sB))~1?!}r{B;DxRoxDEW_#^Gp5INO7A!S2+f7d_#X6>e9GEfK^pCJHiS znz6AXk!HY^gfTr3%&t}>dgQ^Wf&l<~A{ZTl0}!JDgX1Njhy&atn3*?NQAy<7$CoKK zcoxGL{1{OoFyc^Fcvg5Q9SPVQk{kBk1VCqS^KncRvg!X40KiQ7``r%J!)%Gm2}T=H9vb z%QHCs{%KT8^oLJQ%WwMRKLdOIG_NvrW1>E>IMYzZwIn9&Y_6MkWRS7ml9;s`EYZlf zz{#s26XZq}=n0QD&+P*En4V-c>tnPbDp15MErj{WWcdFhFM!{QW!h1$CNo0w5Mb<# z^vVK2QNWFpta_iK@W}G=kvl}iuzKH=42I&+0GJdWmG#Bwp$a&sKNZJ8>Ij}yCKWTK zJa2n71P_7>DdY7#F4`{IsPURH@f&f*QBbCl7B4)ZTQsBXe8&>4s)>8)mDjn&A8b zMabm_rA*Y50_XD)@-ckxi;&0Q7;i|`-V1aCvZYAagThbuoldMWeD^wOG^hMX?^<9=64#fiBEr7^m~+?o&X z`UIDsxo!4Ff^njTquEO^vNWjt-{euGrzV<0#|S!jqCBR|mIcSi6ScBbe>oFiK4L=0 z43mfX>AZONV^Mks6L7-lkdp<^Do3KwG0EN=5`MW(Y%>Ae7@=y&>nq(z0PH8N%;~#! z%xF6+3h5o&9>>Y|f0Ngo+i}=gTG{H^(2pzseB_hN;m6(w!R)GCn(2}mJ}Zv z3~5LPN>2n`NSyanJ``n;C+TEqqvJ!pa+x=H!O#rEJ_Kyz34~0o!xB6;lwcps#wi%0 zYrI&+Fe#(_fi>ZRX&`wMs6-GVpCs7srPTGD0+DV})L7+(=*hTr_soghz?OM7?w5D+ z7N!=51Y*YBlGF9jx>}xrDn2{_(`8(XM^iG^wI7UEYH0dkaq*0O>(<3ZaOY*-P|*ZF)lr^>DW70YO=@g`u!RpnL80g$GOaai$KW|w96Cd$&HWJ1o^8VARKTU z!4x2cGstWB5|a|tH1|UBo`p2>quxXR}(ZQ5;B;Nv$2ts)4>zcq>qz==W}}Z2vp9bW~*; zEiRxAp{wjRpsNdQ@yJ|Rj*OJZkN}WlKImj8mec6<eG@%1Hz$GM=G=oVvoMJ?=j+X|H(o-h*#TEs=frvoVu{6|bNUegChdFTp zleu}CiyCi!O@kvar~ceDawC?1m~fP_1RYSY0n z#!@Z_v7M1?CGn$o1;0ehqB;>TtH6UsAsY_`#)9S(p$AN!pd@j225{c4Xzawfht8c| z_dEB&zNOQ*Vo9OO*qK%G=(pUd^W0S`^A!T#PEyB#)y()Y9;|U+pIxv8yS~d?Q&(`7 z`=G zWiwgecNiI*Xc@z6LY_S>-D^jXok{oF5kAx5PrKe=iU@6te_`(bE}=Xng@h%Lkq;^) zW7ctO?JcwSpL>tH269<Z zUEI5WZ&;3bo?5cAA~!#Qm&RA;FWme#meMVt{q`PsdRfbrP1V3t=b-BP4v@uIkjAZ^ zzzn-SS`$3RE9NOjcq&P*G08bGA;e*)X;1XzG+8C z8<*UZ-`?DM`jf4*XJWkm^xt3NzUf#nvt{q{l1URvWufMj(hOT>+}x%(EkMqmdt)&3 z*C+70b*r{>zhAt}mA0?Isr%<|9O&Xcx~XdmU07>#lw0$OPe63nYrthBPWZSdq`bhL zot2Sh*K7ZPXgtRe%9Y67iC$k|l-J53`I^Sq8GsLez-xa@TjB)By*7lHje_8@`B2Dy z(m+~ZzvM9<0YDe0FOr36hz0T?+y7=Re9XurngpnW1Ph#uC0Q4&#fkXHj_DIQ#|zcm z=i8Pt*j>2-f{AQ-}X|{go>3r2zFk| zStJDCWWpTm_5?w{(g5DX$En4fs!z^|pX!pQ#mblnxnE^2n3RF6>?G?bl0ljAaSUzs zd0Kq3)nA|ol~@_)tzYX+5tN~uNr_^{W?uE)q7&W@i!pGo4F>gRFp?|t^q zH=D}l^-{-|dS3Y8?R!7O`oCcHP)9*}aawxvJvA%tJ->6p?FV}5fqv&O{p`M1d-AR< zPj$h{;3s%F1$e* z%5Jo@U}*hKt;l~40Z_9)a>v$h=|1@C1@5>8d`zzpqP#8qC+`&$*4j$O*S+gOraHYpuf#Z^!K7{m}z$CYz~ zFYcWE01nunl~H!0yP!NOrpQ%uVgIMN{FQxEZ|1f)q-7LNT}@jjWK1pRsq^Bkm3)e1$tL=1UE?uRenh7aHFOo+i>MMmbjEhl+s zcJ<$zpQ9ce+HibgRU5{$N+$mK_}jQ*ch;$=xutYYa&j!5UQ!Eu^XkZX`A0yReDt74 zm7fdoWk-6lH7*A7bx<42dsPDBAnFLn6Y6E3QAC^1U>DTKlaYz>O+p@}0gAmG$%d#P ziLZP@AkYxD221IDo16Np?Udvf^hvKcjvI&Pn{yQU?qa8knq?NwnK4ZC_r&yf#+h_5^ag$c9r z)|9tmHGVnFx#Sgrlz(16rIk8=?LW(>HB#2p?=sCQa}iso)oXss>VVRud6^PYmkYnOuUpWfP&>epzMD^ zEB&FNj2!4_=feROo$5NQGJw+slILiM=7$HyNXNtkM$roJpM~}&*__xyw7P#yCDHkM ztjPw>6ob#0`Eq@L&4t$jB<8keubLAvk-HRLT$@o`j{7Y7WmE25xN=tQ_Gj_9&o&Rm zgk9DJMmwArK$^Ew`-g8e>%fdoT7xfehob6>GP2sJunUhJ?^+ZZ)?U!`&fS-B{h{qM zvDTonXu%MG?ZotObigg3?Z%;r=qZo7Zd`R`g)74r6&|L%E-b)@Q%D?>Bs-d9%6wUr zMV?`lxx9ktjWm<=CSt}hxUvF;T_4{R!uG({eRTm+h&%V=Kp`yPk=rA%Jt7=RaflDB zCF`Pkv%s)|zHOBRdYFiKCTsLjBuFI#7lIGVONHPvAEgqb%TUhgi^1Fwt%4d0A! z0!60w4`502xw~%x(D+={Y7%Gu_0Da_aq3}HmS@j%sUQ-~?&*iK%Y;Z))n^ZX9BD}? zPp_Jp`BHR4&G%rHuig3nqMjAAt0CeHI(9p-F^M++`pm9xA-2_|dvZ(JX1BXADXsKm zPhOcW+LKfJ0chN^a|bF*=X567i@P@9&&r%IlUMKYhM)mw4i1O0w}F*5!>XBG9yM>I zp&%eaqlP>R#GS>km(Qz#3t&x~+%Jy;+rr>zCW^r(BP=sjL+A_qUs2tVtg~-&1}urP z00M`6(=$La{uB@4;jVVZKW`GQ73YCMMzTl-S+UuUq1eI+;TcjKMPQ~B97BGo4EXHy z`YU0Zcg$$54(BFtfBTHPjEiv)zR7$rwmAp)a5I30RM8_YZt{0uOnCUf{D&}0-PHF! zs9Ekct`3J?_!293H>zxvDaH6<@CG;K7G6CTU-H1ro!CHlZ$IRVB~Zg2iAp?ykx*@` zk_SjxAuunhV5q?FCH&V1Z~BUgp(alXE=xa(l&HL}i@;@&l!FK#84$?@2_aue9DRyQ zy}Q2j4EMr{XevCm76xH6J6yK4%+aewso8f-im7C$)#qoLOVh!3#Q0V29Cc2tttXZ5 zP+K32h1z;j8t0EMNq!F=3R>Di3-x7MYGEtRNi1bsu`8*VW%GWQM=)0R6!w>J+UDkM zb1-*>Sr7Nuk#Xz7HR_N*8h0PGlOdDg^Hl}?NGBor-F|WWe3~~sjfDw=NAuzVQA=1` zV&ogZwBjlFLNg3}c%@uD{4ETe`^lC-1|G${NXD&;w*UTMU4bxgjDo2_`X_b@RB+i( zLAu?WA_0>K%S2d4$lcKtBt7_gHe$~BkOL6GNdBjBIQJ{A#Wi>w_scibAob|*1pGOf zX~aFtpppB)*2VWC8pcCmdmic~_Y#MO1E|rd3^Rrq8CWjS`6bN8y>un@J~IueP)xrv zn9K+CX9(^JMpm%EZ-bhGK8PV)o}-Bgqz)woTB8l76*=~}>T1R`Jti_bQ8yvUW=bL6 z$TXP8pJ@e(MoCZ|9TXcA8LA9a_!ZN_xcO=kVw$ZAWt_~<*%fk~F>EZ<^N%U&7wY;4 zV6_mxYNSsVOIE85;81VKus@tq3&7gUia9v{K)$a4il8AO4g-@qrT~hTEr10y8(Z}? z7znmX%MM_CWGc-k6FPAS{#fsABG>o`at5b$^@-H7y-co zibOei`mmId6(e&3bP?c)ilhr+Ogu+Iyq(}ZkQW$IxVLfz)D2aa61VjBw=3(Wb(SZ! zC+DdY_#uUTMoK=6>CTLjG-GO6X414AYB>1B4({i>GAk-viLe%fkwq_ZChE=6*VcQY z67I-N$=MCOM&`8?<`uRZ8Unqmgj7Etp(GlGbTvZ3XcXegLBStT05e6iQP(ZaK)|Ad zL9mSkisIF&y;sTyhr(E2)mD0%mCw@&E+GsuD>I9acN4QE*emK@?((|(F!ki}ebu>> zaaqyaw(jRQOgg#iIUKrWPW80bAelm5zN4kWJu$Bg=4CnrV0rCsh{pXYQX=P3h+W#+Q*nqY^y?v_s{=9hXrcdvg5XSPvsyI|%lQP(n@&zRJ) zNl(t2=#|MXn7eQo|9p=Ek{+aL#?NRH{)BPs6uyoMaeJDD(s7@K1bx6KXL}J8I0_0z z8^PB#@;b9u$xmc7>mwd$k5FIa3Y4iZp+Yc^fI(ch7+cp*9M64q|HBxH^A9h`Uv>9_ zxinoo87I`hxDM@q2}f*SbW2gfDLcf3@JP>a1+xj{D*;XMsQ8LNel`1bF<%%B5jo_6 zY6)y&jVz9iLLsb*m4acUkTx7tr=a7Y;!G$x^V$AhInA#`7oe5kA%NlI{cks^IuRHU z#7`onw(Zz3as1O!I_S@SSWB9y9U^+Edd8Q6+w1Iq}A&qD22+yfXx{2!;F zaYmJ>6jYBl*9WW3d3+BlD4ROI5;*r*(n0Rid(L;Z&guV1U+9{<6$d}MCg0wg1PgvQ zH^{RRD>u(*IentNvoxb}UNq>|+1&OQZkzH@n!C=tZ^ap$Iexs;qW5qwpNmw*CO$m5 zhqKp~*^8IJtfFdIKi~w3wm~jjo@7*m4Fi_uRV`6Te6hP$HmYp-Jd})ukBs4GWiUAL z1l$Gi+Gx-M>(F`i3*r#zU4FvbK|#ezX^||1CVcrUC|bY7rvQ$q!k*IUYa)7X0_J|* z)25vqQrlI&D689=t5o3roKCA-N4=jjw<*KT{SF*bl@;&$A~`(gN$!WunF-P6C?B@hP@1eT0t z0G5~wi$|lQL`8H8g~Db=LjI;dJdBM3)YF$lHc=3(_Qd=@%&LVIW1nPJy-cno1-o7@ z*NDO{!gj$|!v6HwwgBjHs3K+u$KCsWW6Au#z5C_74HFx#tO^_M+x3;lQMH)5OC*sM z4A53ORl9`=Y;tYZQlH|G! z`WueYPmN_uG3h&o3w=DO!q@YhAAFh911fZ&x-|yxBfWx^qJ+iD-TF%U3%(2HD1lNE z324qjh*1XSyC67peJKp^5=^yHmOm;Q1dfaq3~!ePvCARi$Q)Qzl1pV%=~N=D5FwQ1 zaabIi9m3{%_2U>|IjROEqk2G$TlzPEl?Ug^3qGZ6$O>5V@n&&j)YO1t$IRG8&K{y1 z7Aq5@<`ph;c3WZSuO&6Ng_X7xY%5u`Yx>RMJSB20C0~Vx6iu$>zTcLe5MznL+Jvxh z<00;^w`7@P%~AN<*^Rm8Wy=;eILLmQL`&uZrL3saBeR&sl1ZeIm=z__qW?~#0c`R@ z?ZJ4;K=H%@605yt;}3}9%my2O9Syu%w1n7)_wt*fC&1nbR>SPV8GZ!2ou1)EtzJ(+xVxB(#CmBsSqdRQ60SsMyG^bgPgrV;%e$h1+5uf zD+j~shkX$MQ4{47#>)O^{WOWRlRX*$qG(BoO4vZeOr`97Zbn_^!kG`{Y{Tk@s#kBS zwU!psil_I?y-;Y?TP6>@fWtq$W5QDVxXzq%c*uxjxPpEJdK3v#+%TY12l4v?2q}Dj za0T+L3%X98wXh0aLD7O;hQ7wJiWpWbm=nN%f)9=W8AUgS@449tK{tr{@EgBf$Cb&az|rleOSHcXynW9ho#^;@$N^o7jP_PpxDoBngJ z!yL`obXjv3cPtAcJIhWVuB6*xEX0$W=aIo+{A~{?CPGlNLTym!MkV9FEe;3Y79hWf zLNuZMS_)Q9@>7z?D&xiu6NbXawFHACKn`DdIqMHNvhjBdK<_?N+8q6McIC{i)2dfK zwEcvI`>{;nOe|g94V#3R+Ve|Forz`mYVyG)J(nw%+_$cLTIuoVs95Wvwi(f)9$QXt zgQ~i@o}k18-bjUqszZERI`F26;NwW|S|4v@RULxHdN=?hiB>TgA+~}N0Ve15({y+g z38xM!URzSvq*9TFgkuz$Px znBwr{^`I!v&fHMiN|~A$WhZK#SUam+9}zftgZ%EMCfF)v$Aa=L;PznH>=jXerMCjk z?DEL?Dq3wY85^I+7HXX06k4@RTq{26yct=;b!aI{2T=-Gng`rrAOj&Q>&dJfYJvGKCZDfSc_t|rdL^962_j>c6!%)pcIzw)Zy<_J984^ za&d5nBTg0@9#U9bziRRN#{ePDN`RUd4Et~*>Yt1pqJc9#A@MQMk>Jws2oQh)@0W@$ zfQT!ExB`la#%L@Ag!vL?jNrhNMqxeRpf((CVE{k0R-n&rwx6UV2*O7mF+@eyZ$8zS~BFCoQ-%-9JSDCG3UaF0Ov7kkhWyh z?Sc48geoWy!dHTmO$NgQ0pLNsOkBU~SE zdEiHaYQ#QE@}Gxh?O&^ND?!A#Jq67bjW}LfRWOag({Wx@vpY4T zjx#oNwyG8QwuYAJ!6w2r@N8Dk(>Q0y8fPF|brCt>|M3_rPCZs9d*o&+mI{N7q=kLl z2+q2`KZV}9M}B=h=@{)Jn(I4_yCNkwpW9wtU(`+;-}2OzwBl$7}@cWFv@V_*P&sG)6kNEr7uF6=6HX%*1_NT6Lh^gjV*4;f-~ znjm4@84^wdj0l1lqmhlx)(pjgrB=b92$F%$`(U6Tk7NrS$OedEB(ZQri{D&aQ3Jq9dt-~+mS6wa%b}4GDOHuXt_?46+njYn{V9=Y z<2O0`_=xA`jZ(35I2Sak?8pKd*p@4RI@i6XpIkWWbd(#-$y__Sd0#jKlod zCfy56$XyFqMbcQi;syJ_*@9o==h8a8(+cDujGyh-0MJ120jPsZL9&m;)NZ+U@ZH6e z=e+Y!Om)HBt;zEhX|rr@-3%?Ji&CctZIj!(Y;FkBoZ0pF!mO&rRuK8tJ-?sX(|J5O zy;48FEo%-A0*5I%rszs;NP4yjS41z)NdlaG?WNlt1xsM2NgS~rD5yg`06?GaZeI8IMgF?wV;T%xRf~V)*?_aM%miKcr3ZBTTl4}%Q_!MYPU;`J2# zAv2(pQ30|re{4Xq4ZTTL;&Q`6EER7Huao@&Y_URC0D7zeeucp)Nf9E+U=vMcCkBMC z#O7C@LE^9wt6@n6Q3w!xP(qxZvgVm4%GH>fQ0AJ}WHnX3WtkP7o)od8wBFdT601{8 zDJx%_P?S(=nMO^|@MKT?Ix00XiDgn8rS+KFUEYNQDidM*8KYr!tg^oKJ)A?~&V3ov zdb<_?wecqIIJE)19$(Czj1O`La@rec7X$Dl&>s11GXTi!&*e|dE zQ{xEjLV$LqV`*1b2ejjU^rxLQqbTbJ+Ht>%v|FWD)wRCIz2;9l^bE6+ImG?~o>fVI zaFDRJ8VzDte#_^9&YaPB6d{oEzHU)J&rD&AM1I{`I}1r10}u`;;;I!8JTL(+-6>}a zHguQn-I|eBV7{$3Uui4CV!$TP+b+k@P$Ld&`)`y5|lQMZ~MtWvMzWJJPuQ#?_$WGEwF@SrrQNL{^2KlbnKiO5|tn z7jgEWo?3DYTGRPfj2{S#yxAOH)d@GbrSuAEU+@X~J z?C#5>tN1l;^hVQ#)}~yd*eQ6H-E$sWI14(;_gFrbhP%8J{|V zZ8}x~+fBJ>aE&7i2=S;b$rcUzGT@l35j6FZx;!F=SSS z);)YHV0Y>?f8P(`4qCK(q?YF*(%#A6S!gfuYyX_-27GjJq<}n=Y{CcqBcH#*-<^Cu z978w;TKO0bLwKfv@83s!>vTW}tN3R&@~yicC7%^q$ykKe62De57NPZ`uk{4~G@*5m zuXPpwG@v%}jFzXWloB?;Z`0v^tmEy6=7wEOiTwqm2dnsr zbsz-{0`P-OhM@kW^rvTL9r_2i&{9({CkXF5VRcVzer|$uRz^WElQsR8Yle=>PJ@B| zdro3e*`@9IY4HhAHKeD8>DwXqKz5PIJE;_Rk&%(DWBS5mN)-p&$iP0nybz(2YVm#8 z=SRiyZT*mA7dE)`3o7%0Ct}J#rBV}a9vZrN)6meSlBrWmN~TU@JNwsf930%ZzJK48 zqT;Dji;JcJ_5Oiwq90^h;73+&^2k#X6XJ}~I;pUi92gq-pP(?6B0-@L3$z5^UKy)} zT^{3NqqQt#!vwEOsHn4h6tMm!DRJzkI{a-k(%2xW-}c1Fl|+`4cg&D4gT6McEQU%^A!VE3?FtxebrF$J!oyVA2Z zDY$2HqZ0NMKmYK7XF94=OEkgugn|l|x@B@f`LYRs)sylva~5>97gmJkg*6QQ{rIlA zy9<+}GR>jp^w|?D#{-5@1A2dfT>+M{5PY-n+#J}{Bh{Q>;&D^V{ZOG0vU;7?=({L#n4A08rSI0DEDk$!jtOU~wm zfLJeN2G@i{BKRUBQey%#Ans!ACWTa_iM$URf`ca}?tCpQg0tf|zKwc1YG@tz%a+N_ zZzg7tjjbPFR%Si6^6Q$y>5ZEr8$up-J-u%8;zUQ#g!z$;>SHYhD^5%F$)`$i3t+y~E5 z=YgYc*xC!;MnX6Z-Udk-o#AZi#PVaumcv26&!6BDxVoKtm2HPvF`!8v1zG4G9;zDM zRFA5(HD2xM;k{luaay)Kir!iCKcVF;(^ zYp%V$imai5QB=boQpefJP&?i_n4J}8e4R?qdlaF11J0L8J6h8u^6P8R$=)um}&0FtkSXf{S z2o4EkVij#$^mb2XQRCE}nJ(^jc}k~^QS z^9;%Ml(ZmqPfgGEYs;e-xso7HOFxQLPi$ZL4E(6WXE5XKU=s`woymdSqz-u0S=I!y zXAy}_Lb-+i(p;Z(@!M-vE35^ItT=_Qrd#j@$U6AG1hSb_UN1>>l0_E*L|cR1S_1obW&V=B4DQnMV{T8nRFKUGn8WQyz%@p#XOd;-UAz1_s zzj2h1TM&1Xf=mxzzzEJG@wdpTBPe2+8e$Hpm=-oIVf|)(t}a2wer~Fse(&28kFRh! zF~YScc1?cu?jWHr5 zEQqqWYEIOwZkA4Q;*;F7SD)v0EUL=Z*=jI#C+sA(1jnxY{`LQ?zE}_+o{~2OJMMc2 z>ZL}hZv;Oe5B7~X<_UG#U>herY%c<#d=)H4`s1B)fH|SSXPm-Tq;MrD^wenP*{jva zx}!l;9NDMDyFCQ#n!}RST|>wS_huQb&jTZy&SIn$Fmitel!C%M04%RyGxAxhh4rl# z^ZH@liY77s3MZoODB{-wuM1o0#F_rD(_we#l$@=e{?5V;nSp@?X>maX`HwYMP3OKe zRnDU*B> zy2?UWo}QWl>uSt#Mt;?G@aXzO-XZo{8)83wyWSENL3ZmwtQox8NEX9)y%yVBwL@|( zmPD_GNlh8uRP9EU9EbxWMFFu7=Ha{)pC|=p!zS}N*$xP{3&oc_80xRVWiWftrLZyE z=#r&kg7SoQ#SrZ!%bAEk2-yHq9!o44k2?kD+NmL*hb75gl}p0IdM^S6bDsTT1t6oP ztM9?#FLce`anGuvj@%c!oAa~ra%EXT78TM8*Yj?U*xZton4t`Oz+4(@l?VJ}$jR54 z9>~i~$dCmwFLTzXHrPuKta@U&rcxfXdG_YTd+)Y#|ta}iepX8guQD+ZXJZYUL`M)`DX`ciox^v!|wOnAzN}*#))3pHC~R z!xL*Voay-D@L8@K>(3v<1>JRdcYe5HOG;*51FX>Ql;89~`H%UjrLT8)+%iAcK;nw? zM=r1(YzJV6bToHJuT!gn`7OamojALkGJAh{f=35X)~ABc5OyPZSSSaAiUMGHL4olN z(KrGk2t1nNLp4_LLYN4_4HC^yc$f-))fJ+Bf?N@I4fZMoy`~ks64tk>n1ouvF=dsy z&u4JI-uh~HW{%D@Ih zvw`8>qFiFvK7HF`x9xal?=#Qcd0bszmtI0KXrV=r5sQFdoM<&9Y{EtkKYd3{Mo#baGz8c-Jwxy5!;6%nPpn>|9X2eC= z$<^>1@CW|EXiHHr{Ty2hb!u`nW9;s}!ZtKg0&~TEeueU4-d&W+nE>yINckJt&DMXK zNxGBY_SS!nVSvK+zc|e3+X9$gacw(W`y=-S_r;I+{tt$mzyJRFevRE(x0iH@@0@p! z-Cn70VZSV3bYVZ~7ukXM`hJl`9%H}+{GNrd^)Ajbdbi)bww+#qGk=7%Ow5nm#1Dq^ zp<5upUqZ#!K8SC)(4Jm?t_^xGzOkn&e3R^vCC0(eO@S^qtNvei-vQplv9&$BtCeiY zy~8v*7+k;w69{0Ogg_vH5KirE2mAUtduXCHevcS8YbYZ$oImFw76wciy4oY zqFK!6@Z)PUGPy;H!chfqJr zG#v&?^crp1n0n&8qcLtE5O5H}B@)Hs5JeG1?T9Q*!B=bvl0ejih~?0;l{ECzNSCR4 z1j{noRK!a7);rKpiDi+?(l7=t3h2u8DJ8uXeko-;GbbQ8B8NSPkO`Fm5feU6=7d!sJO9DD1N(YZDHgwUOP=XWPd`;f5aEIdC=BkOjeEZ{;anFRS)eOP(} z#v)7~!6^*HOHLEaL^v1&V1^il0igYZ(-YA?Ff1h!nZQ6}uy=P;$e}~{0UAfBkYLYH z*F-2b+6D1v=tMqo-@g8XyG{PP`w#8iD<$WCKYi|;G*bLd^$8*gBtLU+!vdcyCWZ;O z6)L#!67vA}Vt{E$gIHMrV2aCYWAe5;h>v^I)y z1=9yaT!vlUQ|9R^!b*+tW1{nQ{$qYGXpYZ|ZD(BkE8nd&d4A+EZr)_>JI15vSklOS%Wob1!orw;k0R0&&JjM~1dndMcdhI!!#zxk^Y1B-@6Ymg*&#GopGD zmu;-VJwjnc1)!$7gH$wjkY@5__TX9+{h>l~&;=REJSQ+x_Qj`b_(Y7IICy#Cf2kkke<$LZV}VFPvu)C1aC3EEojl)W<}Q z&aHJjfd*Ojz*X4$e&*$ls!{X`e<*)Pj~4mQG}p zhda-yttzWW!P?QG)vHa6)Zgf0m-kGaeA zcqk}MvA4WUq&zn(^sbbfubr>Y(5o|Zl=U~iJKmTU8)G2nKmD%3%dNSeHF*)N~{MpROQpJGE3MtP|_R+8|6qsTB)EKwVJiuVrE> z%m7dUp}uUcxdugwX7uN%JfTf36)R7C{OBDoRn|Z378$@PEH#8peYEsMMOMV%(i7Ig z6x6D7N3WL%z4k}#V?XziY99}+$RZT^vGx&Nq&;(J_hrxxf`aA z_ku=6)9S~e^HPci9{s{Gc4Aq6N~E8z zx(SN74B$c3V6&PPI&H9PaB{FK`*i;*9Dwxa`p@FZ_{UcuV#k?uikWKEN-;Q#jO5fZ z;#db-pwyezf`QU=kfCm*RpC(>Sg=t9OU!CFQgVBN(Ez-h)L;}X4LJ`ZGwlH52>65- zz!UgRKtv#Jp!5V8%mj0=Xi#G}(an$HE1=?bn|hZ#!>o_;viI~VdO~{txj)9Rx^qug zzXTPS&$*xn>rCHCE&y?hAoC0^0>ii9dAL$$YA7GVQ$}w$-qoC$szg0&bFXM%x=;+k zs@X0V-2hl|z?)|V5{KleUb-2^e+=#84*XFEh$lZu|zpU`} z1sfVt?pPg_I9iR?`T4iqkZ5kz(}A!QT)b%!Dz&1KnmX zPG|L|&uH26bDW;8{1apWm(IQiY+OT<4#kE0DLvuCMZ^NkMDSyPJpsfRflBG%m~Irz zjuyxcAgdN~2Fj9QO+$cNl;MW(tyB43P<5vJ^MR=<;-Zs4mc%Sv*49&h^pWmM%o3(=J5Ec`O*IQLsEO zea7zoWzCvOT;hO z>?5|G3ftcqOT|$(6-DQ1xh^)GxVk2~aP6a+~ry68WKvDTxM(yNWXCOqvaEX3C}6?u29rJ92C;^RIzoDM`%2%1Pwqd%KDJ@@l#9=% zm$Nw?*PQtL$Tr5C@$c+YDgDOGVSWm2Nei2C;meyIUD@4OQTySXy)z~AOsklw8~Wd$ zlUK;($Xrt*&m23!eDxwTYr*Wi;^>OJ1eNm5ZKl$DYP*j0Fq+>M-$JDcaicuVnNuMz zJ&EizIK%I$^7nRg9&GK3z`khZY8C!rL(Da7aD%N|I>OYh?It)J3i8<-7tgCKds;7o zai~EH2MVfj#S16F13t*|K}A;4|D3@4MDR|*yfqr%V&Pfo8DQhdgrHxWUkWO z89yFe4wFWWDKs*UUi;=g#VG6QZfaYV9mcrcKBWb=U-Fpg+C=1YGNg;CkRW~yR>0NQ z4Hg6eH9VGNEi$ARc4j>Z_ANYmh#h+2XCGqI3p={L(}Z65g_wI0dfPrYcW*b8^2YEUoSCA*R1V(En^dNKGVWQ_KL-7CyRSg$io z6>+B(%U)aT6QROnH-^`YdJD2-9o?ZrIdtf*a2KIc@8G+j`?$-WcXepjsJ3~5Yy-8Q zR`9Nek_JouVvnbS?orOcsAp(T15tbYgwRw@VUe<48Sz9p!?d(sDZ>dOW|Ozu?I3kI zODok$QO&T&P3nMa1u~dlr4-nTAfOF$!zMU2hf=Wg>m(`0oMG4doMQ}KJveEr- z^}or+V22g5*q#*Pqo)h|?yZN=Dl!HN`2v~34vSq2-iXgGonfDqTq2Gnpxc3m?KZ5a zd$*iAQPk9R02!wSdvcN!JI+U+?AU)mnUWkM*_{yO=yPGFF4BSO!Ybgl4*^-sMSTY& zab$W+o@Z#x?t|@L%uG`SZ$*SxyU_I-NKt zK3PJ*kDQ=X20QQu)Qm4dI9ZC>|C6Xsp&PV55x=0T-d>W2 zq7zD^vH~jR)Qny6&>9bC*~;Y)E@oB!OP^Zt5J;Tzr!#@`rerudc`eV5o#0SP+*m_97e=74Mrw(YecJg1p9bIYuM&~N;2qvFn8S`y8}LXO*af(-0$Bo zXh$?&A>owy2qaXL`6v^)2RjVPF=>eAfVb|?Sdc`UPKbgw*pCryD~cV4V&rn!2wu&T ze}^IoXHp?Jr#mjzY>M=ZlI5E9La&~syh7+Q6^wy{>1FtnET5vboK3!^ZOPj|rC4HO zX|^@EX*}*zXuyr-qOg$DT%LUC;;#VN#*Pk25P55YBK>TLYk))1v3}S*)=LfE|K30o zLoi16YQ~jXd302J^~ff?%26C}@c;S9McI(8&uv%gFrl(Bv2ie0%YRir1>mrKMn_OylXfpRd z@yh<_^r>Yu`9o{)%z74Y{|{4HJ*oiNV1 z6eP#_xjRX*&k6qwUW80n6jUloaujiyisVRzdx*m7HxxlB5lffn0nNe}hRPCpMT;aC zMWgIGz72{6!KDu*z@z0L9K&#n$$U{6pEsIMNaLf!cxBK)E%t$1080?0RiJYe%mmTC z5~h%Dt=+*bX!#LoEa=$?r-p`dFA8ju1%m|zt=+SC; z1TjvvM8OH?L8xuB=nBxKH@LvXgR7c-wnHBrsHtdAkMi-CD<&rD!h$v2BiVsT!D(?> zLEd)uxzV~%O*HP=%@uP8k*^p`fFik=?+8{1YUqeD%Le-ZM?3t_aj54mn6}WuKD?vF z6vAWB-GL^Pn9DDk%aBvF!~B5EYmspVl+$*UJ2-lK2C7q7)-PSH*CYm@u258ba2)qt zLRyHYy`$1o7XqS_xM-z&WPAv<1ekPg1(zs^Mr3ueLGI!xA6)hmP>|@yr5R~<@B>&L z{T%+mBEZuHoA)dWrolYSc)DMc6yt9CT0j~k(G_ZqCPJ;Dck96%bW4_D=0m#O9nIr` z%31^C(MyvTFadPi1bT*E3u*LL%s|g_{;Ghm1YKBQkbj6~b6xFbjbxcJIypI7sSTNO z{SA{tw73(S%9V2kLTq>V2sF%Zrz_QU3A$UZYHZkqu4;BvWY$^F84Hp_yObOR zcv)zi+akR7_ro!XVQxY8bt+<~gAt=?AB4cU!Ss?4As1UJUjdz?V+>*g-X?GnHQ^Aa z0vOg2fQJx{aVP*hE!K@1t~*@H&6a7BhcME~5WLHX)euR&M6(8O;q=Hhy1C}fq3O|$ z<0`TOeQBzFMUXDtYqFR@KSjud_EFuFs#k^rxjD`iOF-ZO2@EFDhg5+9-p=L-e`=0_ z`34>KV6kohvql{fhmo%#QDO45*QJ>35~T9Mi-ek zl>5Lu$-zVEvQoGR$30+lKv3U#WDbi9!JC+#m6ekRUIoXD+Oj-^)9`&>%0w`-b z0`!LJC`$y65WGa4e!?$QZu0CSlH}H+xAa^|b9PcB=4#NmoW)CK@n_Oe&dv$&r$+xl z+!^Z7TIRJcJ~l=IcG64~gN`#~VMrvrP*72r?_MSpHb2U}(;F8^Lp2hcz$x_F9FD5b2v<3xuFMcZ&>lRrJ|AkD#7{txg8RY6f6gdF|{ltMq%b|6irhX zFPNr&Uhb5d8y^=9RM820Aes#&VBQq70(E?7EI&AxTWwj}Rb%F*UxPG5Y#iH+gQ{L|>2QVAsmo^J`se#!Y#IvL?D5^o+3ZCfXhLk!sZiK1ySR zYkYolrH`z1yqAwDcdY)J*D}X~P4P)aIl!i9#oDMHBw}sgaWvy{`voon5tqB=5YTB_ zhfMkbMvYdx>oh3DYIjlLVyQcG*qx9_fI4?RgX-LM6AiSBKG~vTv^t5#qGE>CaRQcz zydJad4<5r1OFbw5LB;K4e_lBeD&CnzRXB{Sxwf5Tt;f7IRbp+sCT8O9;;P~)=F)b3 z_008|O}ZQxhZ#)vt+j7QmF}39!^pKJ)5k@NXlXmY*A}iDo1T$@YGI>jWxIc&&g4^f zWW)qV27Kyf`ufl!p}ZZ&NnohNI0eFHEjtk8=k6$GSqx*Rr@`$(Lpdsyj0-2nP7Og4 z9CndB8^YVLzGD@NyO$U%tu_ZHSR$qoB|x)BMZy3CPqX@*NwXH4xhc(@mF!EYby2CH zsNY~iR>?kFxT{m3s7x@^R!UE=)2mgHeiu6iI4c=)2w^A%+);Q+^ACmigHA$@V)k_Q z@gK}AM;XHiMN0{66WbsKgFMIw-Sx3ftq?YZ-dIdh4d8GAOGvT0rPP?K zmk}E2O?Skl%qN_i%VVB%{)!;zzqG``?_B<>rN;3x-@|zUH)&w}2&r5fb&i2Hj9h*LGI~ zI4P_JzUW3Q#0?93Fc5ZYIFCWDLTxX6S=NLwa4>0HZHZw;)Wuvw1Yj}@Yuh?N=5b_x zeW)xm+4Slp6*JK{HXzT*F)mb-bL-qWT{-O1w5a&8VZlt9FYL3?p1w-=;F!syXRU0V zGARe+Cu2U~reOSHDI>5s)6^evk%D_i#GEW;3Rw36(k1k(2WhF6_|e{A)j%4}A#h|^ z-3YW-2SMOTRCMW61cRDwo)%Um!QdP)pauI40S!W8s2E3P$&+9O`|ZHY2d}H`%F+5q zAwp@4#%N6Obez^%mKNoFuGW`(Y}EYa`x+~=ry{Jz)yYSZIVCMm=^E>=bgWJbOBfgK zhn<{Rdg+Wb3myk|*mMQt0fSq9RvJjC!b3w;K7%F596(EP4!UtBE3&kTd^(Y044fEH z6*4F*0(}4(;ivqow*wWnSG&j>nb#Gj0Y#Aj6 zw*U&r+a+>lOt6y4s05vJoaw_azQD-JFtW86*;vHTPX#{rn!#_z^l6hzipCXSfHO1F z5-zu-EwXJMV=CWD#mFnXuV`FOwsp`gOa0)q85x;8mpw4}f3oZkX&FXqEB6O0nCTTP z$ux_7Z$8X6bK1DI`T!L5U)K)YARpoI34;{|VhfAT#Ee~0n|vzx7#)O#!ENxT(-#mX zPM_XjnLl^a$8~S~x!$?(g^iPv@gA7c#2Ao)2y^NeFU%<`Rr5OpUcJAR`AxIvsFDC+ zV>x@;fCa%ezuOg!W5lhCmh$wKy1s6C;lBvTvdtQ8Ou2sF^fQx^z~c zlGaR$iJ>)<80i*%i`^YKB@V^SY_Iy4a5LF~4t;=1C*o!bxrm$bzh?*PLNX|BW;vPS zp6~LT?P&biVBF01j{iPxW{%>s!Of%>)wZ}`=&O>kte4Qj^9X7O9? zj)H-a%1=tSJ<>p6=6iC^X4V}Sfp>=vp6w$aaC2~TAT$#U9&9W+8^N)~fKZHmFa{*O zGy(?1qWH}Y*sTE$?Csdn5r@F+bb|%luHr3|k$8`C$wAUEK1knICSfFh8M-P?ya}bIV@AIQ&yRq9VQF&EG1C9MjtPs5%??Wpa*`_mzXw9c3_|8@b&NX1 zR>yE-`5giy=-<4)`8tdI?7D*dNO*n^pLiAW!@FXS@{g9-kF-Z|tN2}#r>;hRBsZb1 zpPzY;Dun#_`wrCgW4I1}3*Yj0$d6>B?fSmb9>ultoB2imarxmk3G!p{?fhl=VYpZE ze6I{26XZsijhPV;5-Qp=B7Obs9K?NFT9yr0L1M75b5oBO z#gqvvapreO5B>dGPpUNwt7(T>d`GgZP(*Eybo5n7tG~87Hod`Z#M&J12yOc!ws>no%`2%z*Z=G}SoQ z486T`Vn~Q*Li37Q3v(AN9TT3F#oeK|QzWY*Ju}j?rqrj&U6txI->4{mC*OFPB1skH zovhc*otI_rhIVCI>615>q#8H9G5CK9`MEu$j zdqN|s91u_IgxDPycnaNsba}w5?S=Dz5*#|dsQKg%uAo5h=%{dt2_d0CeZ!G|r$&@V z6tZJufG5Nu`&fhcG#%nA5|NRS4DUb+A|=v*G-SZ5FbZ|mvxtFYlN=yAd6?-jK-0#; zH&zJdgd)@hF9w_71Tfi^f_b(aHP0%^Brq6H0ZuWEOb1pm6FDEV5Uo3#RFgTRhSZWe zGMChod1O9mfLE`HG?N8nA!#A4q>Z$bMWll)CfAZBWGT6hEQ6G-Af03-=_1#Iuk1#$ zirhq2lQraKvX-nPw~$-Oda{AsMmCb$$tH3Kxs%*Q?k1bb7IF{SO16>hWCz(vc9Gp= z54o4zNA4#NkO#>_WG~rA_LE1*qvSClPd%g;d=3Z5K?GzRCXbUR$Un%FjD$Q*o*_rb zv*bB)lsr$4A)@?6@)G$cIZj?CuOP1WB>5LPMP4PZlQ+nlJoyGJ`rji@=|}PtqHKN{Hsyc4;VC}8slB1WrK!28 zv8rW$eN$aaO)e`_ zR#k4cHqhHKO|MPTrfG$LQ@tJW0)cr6iOFfnX;c3jkFauwZNC|wa4T;i+LdeAl`F~7 z*XwIanN8*UB43!T>@BZ2mUmNrVa9XIPrv^5OP#B3IqmSh*Vb3&KNQuoeo^bjmyXT8 zKl6Mb-~OFDY48~T#@!oaPuI7uJUqKt7x?PMe>!}_mHD~eB2NK#_T=zz>-m|ntpNviNdAzi6qO#Le7Ps_G-MV8no3pbuKRi;s8F3aJ$258 z^W`UxzyA8EYrd7-bC&HovpTB#Xvuvi7S7RSWdjv~@cdKBFWz&@ z>f=Gj%PMcPeP9XXXytZYkTyV+8ZWDGl()3EwyBD1+B%wB=3B%{F-)vtwb7zjg%12> zePfNPtgWhX0oJ0btfpmAeRYkhw7I!Wm!wS)KOIwCqAD_G=NOBO_PQNq^jI*U2mWk1yQxX2@jCo3D8AH|U?(w6|}3;g{cJgzT@} zygYbo!>S{N1$WKsyI=q2MfP z#XoSJz1Qs?x!?WjHU2Hxt@pSzOg71r?>fF_#|M%HTcej%-TLeoiiKMqe6exWc_X#*=in1ZBQoN`6Heaq@iT^kuTD1>Ec)z-c8_!C$rYzFmhb%i zj%Zzs=N~V5oImr}mlfFy#>B-g*LKIxLN+yHnp+mct7c!TDy^xFkEQ!Zd{KEG-7`{kqqUjhb&~Vy>+0KJ(-`wq zxeZmVt*S&-oN9c1bxU(AtegQ;r?RS{eoj?eeRGp)QG!mPwWohCb!RKebnaSL`ohj# zKB=m8F1E3@<|dts)`>RC+-0RTa~hkQ=I8>o{jE`SiJ7RCo4C9Tv_QQo9aE`1?|~yqkj71@Y%Lq&5ulrk{1LmKlMQQb7u=qJkb^- zedERuUBGYBDO(gN)3*PfcPMN6+5OuLv(!_SlL~!WQy1yK=}uGeJ7fM?o~b)5?+Ll^ zQq9&q=L&MZc;(ht>arTfhqU~&@U7ElHy-}R-|n}L&#{R1bn(sFE`Gi+G6C)qR!g)B zbU46S0t|Xwj6UugVaferSaed`;>swXTH7#xRwe{6iZ8fTTL2#*1)U;CRZKp| zRn=|Ox`MgYR?}G1)TWBWlSIj}j#}vlbn#l;WKmUpL)GjC`Xqy|Hn74}Rc-0=%XKt^ zK6QRvBQAr_sc?t5mYRj_HLY!}2HO>zp=xfCvNrM_-1x>OydOH0#R2SL1?N|oKv zpem)GXoW&(g`HV5Ctj7CUs|4RES68oE-lS2E;r_vsq&0vxkcH=@%eeG?BYBdyR*nR z-UzcZUQRz@nYpxwCi*@y_IK|e?QQ;_0#j3WxW=@&75VG5_GG@190m*9?+dxw3 z+A?Ox%lGIzlP)Lyw)>Dp+8dhdn&a#0Yqff+NH~c`8>fxg8MRZrDx6*h%Ayr3vb}Zi zhE`3tBVBxTOM}+SM&I~J?6gQkzJ&jWSOL@!uXy|J6Xk^$wdea@ed9OgmA$uk{rdUB z?+X|FHa#`o^V2cTzm(=Y^1xZr*iw~L`+UW*if2zfIgJ^=$L)u#t#?1)FmYze2ix}> z7Oc)BUp<)V5dD38^WJa2YFu&CwsTwV@lEZ0q~X(X{v{ty_CI;X^}y-7OcT2w*9}L&_^(h2Ei~pS3a%vu_7V%oX%FgORysk zD0_tf;S9X?(gqFup+x52is%e8Pd?o#8Z8!wV9T^!yP&zQrE0<4YgM*$ z48vKnvQzU#UTJj1*e5n@n7sJ6FFt+#U&qI@Ke=w*|J^T(UwVq%SkU?Dv47k#YD#9z zJEPQIE^DiLZh!jzl|R3C?w6)xExzloziZ1!eS06cF*fFz`v?w`MUzj4F;M;7ck_+Vc4>Xy8+=k9$){>Pftdcl)8lm3S04U9f5g7rDRHpmOwlR_y2$Ai))z7ca$^Aj?RlNE05NEF$vS;< za#GUNVRADuuOsK)pC^25eEfXH;>X7O44=~tRr3E?{dlCWW^>b>$G&rXbHl#nK?@K5 z_DI2!m&ZGNxVFPff6-LED*1-bZ;)@`M-hIJ0lb{Z-F>TYUR`wf_1q zuU~fb#x2Pnqe4H}zIo13@5iUVwKnD`^IYs_iSNFefA=-+_nkC4Eq&-%`p;gWwUgGp R^^s%ai<+}*?oKeK{4d9Wtg-+A diff --git a/IO/Binary.pas b/IO/Binary.pas new file mode 100644 index 0000000..80fb6c0 --- /dev/null +++ b/IO/Binary.pas @@ -0,0 +1,177 @@ +unit Binary; + +interface + +const + + HIB_BLOCKSIZE = $10; // 16 bytes + HIB_MAXOFFSET = $0F; // HIB_BLOCKSIZE - 1 + +type + + // low-level binary types + TBlock = array[0..HIB_MAXOFFSET] of byte; + TWord = array[0..1] of byte; + TDWord = array[0..3] of byte; + TQWord = array[0..7] of byte; + THibRawString = array of byte; + +// procedures to write blocks at low level +procedure WriteData2(var target: TBlock; data: TWord; pos: integer); +procedure WriteData4(var target: TBlock; data: TDWord; pos: integer); +procedure WriteData8(var target: TBlock; data: TQWord; pos: integer); + +// procedures to read blocks at low level +procedure ReadData2(source: TBlock; var data: TWord; pos: integer); +procedure ReadData4(source: TBlock; var data: TDWord; pos: integer); +procedure ReadData8(source: TBlock; var data: TQWord; pos: integer); + +// procedures to write typed data to blocks +procedure Int16ToBlock(var target: TBlock; pos: integer; data: SmallInt); +procedure Int32ToBlock(var target: TBlock; pos: integer; data: Integer); +procedure LongWordToBlock(var target: TBlock; pos: integer; data: LongWord); +procedure Int64ToBlock(var target: TBlock; pos: integer; data: Int64); +procedure SingleToBlock(var target: TBlock; pos: integer; data: Single); +procedure DoubleToBlock(var target: TBlock; pos: integer; data: Double); + +// procedures to read typed data from blocks +function BlockToInt16(source: TBlock; pos: integer): SmallInt; +function BlockToInt32(source: TBlock; pos: integer): Integer; +function BlockToLongWord(source: TBlock; pos: integer): LongWord; +function BlockToInt64(source: TBlock; pos: integer): Int64; +function BlockToSingle(source: TBlock; pos: integer): Single; +function BlockToDouble(source: TBlock; pos: integer): Double; + +implementation + +procedure ReadData2(source: TBlock; var data: TWord; pos: integer); +const size = 2; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + data[i] := source[i + pos]; +end; +procedure ReadData4(source: TBlock; var data: TDWord; pos: integer); +const size = 4; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + data[i] := source[i + pos]; +end; +procedure ReadData8(source: TBlock; var data: TQWord; pos: integer); +const size = 8; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + data[i] := source[i + pos]; +end; + +procedure WriteData2(var target: TBlock; data: TWord; pos: integer); +const size = 2; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + target[i + pos] := data[i]; +end; +procedure WriteData4(var target: TBlock; data: TDWord; pos: integer); +const size = 4; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + target[i + pos] := data[i]; +end; +procedure WriteData8(var target: TBlock; data: TQWord; pos: integer); +const size = 8; +var i: integer; +begin + for i := 0 to size - 1 do + if i + pos < HIB_BLOCKSIZE then + target[i + pos] := data[i]; +end; + +function BlockToInt16(source: TBlock; pos: integer): SmallInt; +var temp: TWord; data: SmallInt; +begin + ReadData2(source, temp, pos); + Move(temp, data, SizeOf(TWord)); + Result := data; +end; +function BlockToInt32(source: TBlock; pos: integer): Integer; +var temp: TDWord; data: Integer; +begin + ReadData4(source, temp, pos); + Move(temp, data, SizeOf(TDWord)); + Result := data; +end; +function BlockToLongWord(source: TBlock; pos: integer): LongWord; +var temp: TDWord; data: LongWord; +begin + ReadData4(source, temp, pos); + Move(temp, data, SizeOf(TDWord)); + Result := data; +end; +function BlockToInt64(source: TBlock; pos: integer): Int64; +var temp: TQWord; data: Int64; +begin + ReadData8(source, temp, pos); + Move(temp, data, SizeOf(TQWord)); + Result := data; +end; +function BlockToSingle(source: TBlock; pos: integer): Single; +var temp: TDWord; data: Single; +begin + ReadData4(source, temp, pos); + Move(temp, data, SizeOf(TDWord)); + Result := data; +end; +function BlockToDouble(source: TBlock; pos: integer): Double; +var temp: TQWord; data: Double; +begin + ReadData8(source, temp, pos); + Move(temp, data, SizeOf(TQWord)); + Result := data; +end; + +procedure Int16ToBlock(var target: TBlock; pos: integer; data: SmallInt); +var temp: TWord; +begin + Move(data, temp, SizeOf(TWord)); + WriteData2(target, temp, pos); +end; +procedure Int32ToBlock(var target: TBlock; pos: integer; data: Integer); +var temp: TDWord; +begin + Move(data, temp, SizeOf(TDWord)); + WriteData4(target, temp, pos); +end; +procedure LongWordToBlock(var target: TBlock; pos: integer; data: LongWord); +var temp: TDWord; +begin + Move(data, temp, SizeOf(TDWord)); + WriteData4(target, temp, pos); +end; +procedure Int64ToBlock(var target: TBlock; pos: integer; data: Int64); +var temp: TQWord; +begin + Move(data, temp, SizeOf(TQWord)); + WriteData8(target, temp, pos); +end; +procedure SingleToBlock(var target: TBlock; pos: integer; data: single); +var temp: TDWord; +begin + Move(data, temp, SizeOf(TDWord)); + WriteData4(target, temp, pos); +end; +procedure DoubleToBlock(var target: TBlock; pos: integer; data: double); +var temp: TQWord; +begin + Move(data, temp, SizeOf(TQWord)); + WriteData8(target, temp, pos); +end; + +end. diff --git a/IO/CommandLine.pas b/IO/CommandLine.pas new file mode 100644 index 0000000..e727894 --- /dev/null +++ b/IO/CommandLine.pas @@ -0,0 +1,48 @@ +unit CommandLine; + +interface + +uses RegularExpressionsCore; + +type TCommandLine = class + public + CreateFromTemplate: boolean; + TemplateFile: string; + TemplateName: string; + //Lite: boolean; + + procedure Load; + end; + +implementation + +procedure TCommandLine.Load; +var + Regex: TPerlRegEx; +begin + Regex := TPerlRegEx.Create; + Regex.RegEx := '-template\s+"(.+)"\s+"(.+)"'; + Regex.Options := [preSingleLine, preCaseless]; + Regex.Subject := CmdLine; // Utf8String(CmdLine); + CreateFromTemplate := false; + if Regex.Match then + if Regex.GroupCount = 2 then begin + CreateFromTemplate := true; + TemplateFile := Regex.Groups[1]; + TemplateName := Regex.Groups[2]; + end; + Regex.Destroy; + + { // AV: this is not so useful since NXFORMS still equals to 100 + Regex := TPerlRegEx.Create; + Regex.RegEx := '-lite'; + Regex.Options := [preSingleLine, preCaseless]; + Regex.Subject := CmdLine; // Utf8String(CmdLine); + CreateFromTemplate := false; + if Regex.Match then + Lite := true; + Regex.Destroy; + } +end; + +end. diff --git a/IO/MissingPlugin.pas b/IO/MissingPlugin.pas new file mode 100644 index 0000000..b853089 --- /dev/null +++ b/IO/MissingPlugin.pas @@ -0,0 +1,99 @@ +{ + Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne + Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina +} + +unit MissingPlugin; + +interface + + uses Windows, Global, Classes, LoadTracker, ComCtrls, SysUtils, + ControlPoint, Translation; + + const RegisteredAttributes : array[0..29] of string = ( + 'weight', 'color', 'symmetry', 'color_speed', 'coefs', 'chaos', + 'plotmode', 'opacity', 'post', 'var', 'var1', 'var_color', + 'name', 'linear3D', 'GlynnSim3_thickness2', 'var_order', + 'perspective', 'perspective_dist', 'perspective_angle', + 'fan', 'rings', 'waves', 'popcorn', 'bent', 'secant', 'arch', + 'droste', 'droste_r1', 'droste_r2', 'Spherical3D' + ); + + var MissingPluginList : TStringList; + Parsing : boolean; + ErrorMessageString : string; + + procedure BeginParsing; + procedure CheckAttribute(attr: string); + function EndParsing(cp : TControlPoint; var statusPanelText : string): boolean; + procedure AnnoyUser; + +implementation + + procedure BeginParsing; + begin + // AV: moved into main unit to be sure that it's created only 1 time + //MissingPluginList := TStringList.Create; + MissingPluginList.Clear; // AV + if (AutoOpenLog = true) then + if (LoadForm.Showing = false) then + LoadForm.Show; + end; + + procedure CheckAttribute(attr: string); + var i : integer; + begin + for i := 0 to Length(RegisteredAttributes)-1 do + if attr = RegisteredAttributes[i] then exit; + + if MissingPluginList.IndexOf(attr) < 0 then + MissingPluginList.Add(attr); + end; + + function EndParsing(cp : TControlPoint; var statusPanelText : string): boolean; + var + str, str2 : string; + i : integer; + newl : TStringList; + begin + str2 := TextByKey('main-status-variationsorvariables'); + if (cp.used_plugins.Count > 0) then begin + newl := TStringList.Create; + for i := 0 to MissingPluginList.Count - 1 do begin + if cp.used_plugins.IndexOf(MissingPluginList[i]) >= 0 then + newl.Add(MissingPluginList[i]); + end; + str2 := TextByKey('main-status-plugins'); + // MissingPluginList.Free; + // MissingPluginList := newl; // AV: here was a memory leak + MissingPluginList.Clear; // AV + MissingPluginList.Assign(newl); // AV + newl.Free; // AV + end; + + if MissingPluginList.Count > 0 then + begin + statusPanelText := Format(TextByKey('main-status-loadingerrorcount'), [MissingPluginList.Count]); + + for i := 0 to MissingPluginList.Count - 1 do + str := str + #13#10 + ' - ' + MissingPluginList[i]; + ErrorMessageString := Format(TextByKey('main-status-morepluginsneeded'), [cp.name, str2]) + str; + LoadForm.Output.Text := LoadForm.Output.Text + + ErrorMessageString + #13#10#13#10; + Result := false; + end else begin + statusPanelText := TextByKey('main-status-noloadingerrors'); + ErrorMessageString := ''; + Result := true; + end; + // AV: moved into main unit to be sure that it's destroyed only 1 time + //MissingPluginList.Free; + MissingPluginList.Clear; // AV + end; + + procedure AnnoyUser; + begin + if (ErrorMessageString = '') or (not WarnOnMissingPlugin) then exit; + MessageBox($00000000, PChar(ErrorMessageString), PChar('Apophysis AV'), MB_ICONHAND or MB_OK); + end; +end. diff --git a/IO/Settings.pas b/IO/Settings.pas new file mode 100644 index 0000000..b79d044 --- /dev/null +++ b/IO/Settings.pas @@ -0,0 +1,1474 @@ +{ + 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 Settings; + +interface + +uses Graphics; + +function ReadPluginDir: string; +procedure ReadSettings; +procedure SaveSettings; + +implementation + +uses + Windows, Classes, SysUtils, StrUtils, Forms, Registry, Global, Dialogs, + XFormMan; + +(* +function ReadPluginDir: string; +var + settingFileName: string; + sl : TStringList; +begin + sl := TStringList.Create; + + settingFileName := ExtractFilePath(Application.ExeName) + 'ApoPluginSrc.dat'; + if FileExists(settingFileName) then + sl.LoadFromFile(settingFileName) + else begin + settingFileName := GetEnvVarValue('APPDATA') + '\ApoPluginSrc.dat'; + + if FileExists(settingFileName) then + sl.LoadFromFile(settingFileName) + else + sl.Text := ExtractFilePath(Application.ExeName) + 'Plugins\'; + end; + + if Trim(sl.Text) = '' then + sl.Text := ExtractFilePath(Application.ExeName) + 'Plugins\'; + + Result := Trim(sl.Text); + if (RightStr(Result, 1) <> '\') and (Result <> '') then + Result := Result + '\'; + + sl.Free; +end; + +procedure SavePluginDir(data: string); + var + settingFileName: string; + sl : TStringList; + begin + settingFileName := ExtractFilePath(Application.ExeName) + 'ApoPluginSrc.dat'; + sl := TStringList.Create; + sl.Text := PluginPath; + + try + sl.SaveToFile(settingFileName); + sl.Destroy; + except + // not elevated? + settingFileName := GetEnvVarValue('APPDATA') + '\ApoPluginSrc.dat'; + try + sl.SaveToFile(settingFileName); + except + MessageBox(0, PCHAR(TextByKey('main-status-pluginpath-ioerror')), + PCHAR('Apophysis'), MB_ICONWARNING); + end; + sl.Free; + end; +end; +*) + +// AV: rewrote to save the plugin directory in the Windows registry +// because this 'ApoPluginSrc.dat' always resets my settings! +function ReadPluginDir: string; +var + Registry: TRegistry; + plugdir: string; +begin + plugdir := ExtractFilePath(Application.ExeName) + 'Plugins\'; + Result := plugdir; + Registry := TRegistry.Create; + try + Registry.RootKey := HKEY_CURRENT_USER; + if Registry.OpenKey('Software\' + APP_NAME + '\Defaults', False) then + begin + if Registry.ValueExists('PluginPath') then + begin + Result := Trim(Registry.ReadString('PluginPath')); + if (RightStr(Result, 1) <> '\') and (Result <> '') then + Result := Result + '\'; + end + else + Result := plugdir; + + Registry.CloseKey; + end + else + Result := plugdir; + finally + Registry.Free; + + if (Result = '') or (not DirectoryExists(Result)) then + Result := ExtractFilePath(Application.ExeName); // AV + end; +end; + +procedure ReadSettings; +var + Registry: TRegistry; + DefaultPath: string; + i: integer; + VarUsed: byte; +begin + // DefaultPath := GetEnvVarValue('USERPROFILE'); + DefaultPath := AppPath; // AV: backward compatibility is more convenient + PluginPath := ReadPluginDir; // AV + Registry := TRegistry.Create; + try + Registry.RootKey := HKEY_CURRENT_USER; + + { Defaults } + if Registry.OpenKey('Software\' + APP_NAME + '\Defaults', False) then + begin + if Registry.ValueExists('DefaultFlameFile3D') then + defFlameFile := Registry.ReadString('DefaultFlameFile3D') + else + defFlameFile := ''; + + if Registry.ValueExists('AlwaysCreateBlankFlame') then + AlwaysCreateBlankFlame := Registry.ReadBool('AlwaysCreateBlankFlame') + else + AlwaysCreateBlankFlame := false; + + if Registry.ValueExists('GradientFile') then + GradientFile := Registry.ReadString('GradientFile') + else + GradientFile := ''; + + if Registry.ValueExists('SavePath3D') then + SavePath := Registry.ReadString('SavePath3D') + else + SavePath := DefaultPath + 'Flames.flame'; + + if Registry.ValueExists('RandomizeTemplates') then + RandomizeTemplates := Registry.ReadBool('RandomizeTemplates') + else + RandomizeTemplates := True; + + if Registry.ValueExists('WarnOnMissingPlugin') then + WarnOnMissingPlugin := Registry.ReadBool('WarnOnMissingPlugin') + else WarnOnMissingPlugin := true; + + if Registry.ValueExists('SetEnglishLayout') then + SetEngLayout := Registry.ReadBool('SetEnglishLayout') + else SetEngLayout := false; + + if Registry.ValueExists('ApplyFlatten') then + ApplyFlatten := Registry.ReadBool('ApplyFlatten') + else ApplyFlatten := true; + + if Registry.ValueExists('LanguageFile') then + LanguageFile := Registry.ReadString('LanguageFile') + else LanguageFile := ''; + + if Registry.ValueExists('SmoothPaletteFile') then + defSmoothPaletteFile := Registry.ReadString('SmoothPaletteFIle') + else + defSmoothPaletteFile := DefaultPath + 'Gradients\SmoothPalette.ugr'; + + if Registry.ValueExists('PlaySoundOnRenderComplete') then + PlaySoundOnRenderComplete := Registry.ReadBool('PlaySoundOnRenderComplete') + else + PlaySoundOnRenderComplete := false; + if Registry.ValueExists('RenderCompleteSoundFile') then + RenderCompleteSoundFile := Registry.ReadString('RenderCompleteSoundFile') + else + RenderCompleteSoundFile := ''; + + if Registry.ValueExists('ConfirmDelete') then + ConfirmDelete := Registry.ReadBool('ConfirmDelete') + else + ConfirmDelete := True; + if Registry.ValueExists('OldPaletteFormat') then + OldPaletteFormat := Registry.ReadBool('OldPaletteFormat') + else + OldPaletteFormat := false; + + if Registry.ValueExists('ConfirmExit') then + ConfirmExit := Registry.ReadBool('ConfirmExit') + else + ConfirmExit := True; + + if Registry.ValueExists('ConfirmClearScript') then // AV + ConfirmClearScript := Registry.ReadBool('ConfirmClearScript') + else + ConfirmClearScript := False; + + if Registry.ValueExists('ConfirmResetUndo') then // AV + ConfirmResetUndo := Registry.ReadBool('ConfirmResetUndo') + else + ConfirmResetUndo := False; + + if Registry.ValueExists('PreserveQuality') then + PreserveQuality := Registry.ReadBool('PreserveQuality') + else + PreserveQuality := true; + + if Registry.ValueExists('KeepBackground') then + KeepBackground := Registry.ReadBool('KeepBackground') + else + KeepBackground := False; + + if Registry.ValueExists('NumTries') then + NumTries := Registry.ReadInteger('NumTries') + else + NumTries := 10; + if Registry.ValueExists('TryLength') then + TryLength := Registry.ReadInteger('TryLength') + else + TryLength := 100000; + + if Registry.ValueExists('MinTransforms') then + begin + randMinTransforms := Registry.ReadInteger('MinTransforms'); + if randMinTransforms < 2 then randMinTransforms := 2; + end + else + randMinTransforms := 2; + + if Registry.ValueExists('MaxTransforms') then + begin + randMaxTransforms := Registry.ReadInteger('MaxTransforms'); + if randMaxTransforms < randMinTransforms then randMaxTransforms := randMinTransforms; + end + else + randMaxTransforms := randMinTransforms + 1; + + if Registry.ValueExists('MutationMinTransforms') then + begin + mutantMinTransforms := Registry.ReadInteger('MutationMinTransforms'); + if mutantMinTransforms < 2 then mutantMinTransforms := 2; + end + else + mutantMinTransforms := 2; + + if Registry.ValueExists('MutationMaxTransforms') then + begin + mutantMaxTransforms := Registry.ReadInteger('MutationMaxTransforms'); + if mutantMaxTransforms < mutantMinTransforms then mutantMinTransforms := mutantMinTransforms; + end + else + mutantMaxTransforms := mutantMinTransforms + 1; + + if Registry.ValueExists('RandomGradient') then + randGradient := Registry.ReadInteger('RandomGradient') + else + randGradient := 0; + + if Registry.ValueExists('ParameterFolder3D') then + ParamFolder := Registry.ReadString('ParameterFolder3D') + else + ParamFolder := DefaultPath; + + if Registry.ValueExists('UPRPath') then + UPRPath := Registry.ReadString('UPRPath') + else + UPRPath := DefaultPath + 'ApophysisAV_export.upr'; // AV + + if Registry.ValueExists('ImageFolder') then + ImageFolder := Registry.ReadString('ImageFolder') + else + ImageFolder := GetEnvVarValue('USERPROFILE') + '\Pictures\'; // AV + + if Registry.ValueExists('ScreenshotsFolder') then // AV + ScreenShotPath := Registry.ReadString('ScreenshotsFolder') + else + ScreenShotPath := DefaultPath + 'ScreenShots\'; + + if Registry.ValueExists('DefaultScript') then // AV + defScriptFile := Registry.ReadString('DefaultScript') + else + defScriptFile := ''; + + if Registry.ValueExists('AutoSaveXML') then // AV + AutoSaveXML := Registry.ReadBool('AutoSaveXML') + else + AutoSaveXML := true; + + if Registry.ValueExists('UPRWidth') then + UPRWidth := Registry.ReadInteger('UPRWidth') + else + UPRWidth := 640; + + if Registry.ValueExists('UPRHeight') then + UPRHeight := Registry.ReadInteger('UPRHeight') + else + UPRHeight := 480; + + if Registry.ValueExists('BrowserPath') then + BrowserPath := Registry.ReadString('BrowserPath') + else + BrowserPath := DefaultPath; + + if Registry.ValueExists('EditPreviewQaulity') then + EditPrevQual := Registry.ReadInteger('EditPreviewQaulity') + else + EditPrevQual := 1; + + if Registry.ValueExists('MutatePreviewQaulity') then + MutatePrevQual := Registry.ReadInteger('MutatePreviewQaulity') + else + MutatePrevQual := 0; // AV: hack, to speed up the calculations + + if Registry.ValueExists('AdjustPreviewQaulity') then + AdjustPrevQual := Registry.ReadInteger('AdjustPreviewQaulity') + else + AdjustPrevQual := 1; + + if Registry.ValueExists('ThumbPrevQuality') then // AV + ThumbPrevQual := Registry.ReadInteger('ThumbPrevQuality') + else + ThumbPrevQual := 1; + + if Registry.ValueExists('AnimPrevQuality') then // AV + AnimPrevQual := Registry.ReadInteger('AnimPrevQuality') + else + AnimPrevQual := 1; + + if Registry.ValueExists('RandomPrefix') then + RandomPrefix := Registry.ReadString('RandomPrefix') + else + RandomPrefix := 'ApoAV-'; + if Registry.ValueExists('RandomDate') then + RandomDate := Registry.ReadString('RandomDate') + else + RandomDate := ''; + if Registry.ValueExists('RandomIndex') then + RandomIndex := Registry.ReadInteger('RandomIndex') + else + RandomIndex := 0; + + if Registry.ValueExists('SymmetryType') then + SymmetryType := Registry.ReadInteger('SymmetryType') + else + SymmetryType := 0; + + if Registry.ValueExists('SymmetryOrder') then + SymmetryOrder := Registry.ReadInteger('SymmetryOrder') + else + SymmetryOrder := 4; + + if Registry.ValueExists('SymmetryNVars') then + SymmetryNVars := Registry.ReadInteger('SymmetryNVars') + else + SymmetryNVars := 12; + + if Registry.ValueExists('RandBackColor') then + RandBackColor := Registry.ReadInteger('RandBackColor') + else + RandBackColor := $000000; + + if Registry.ValueExists('MinNodes') then + begin + MinNodes := Registry.ReadInteger('MinNodes'); + if MinNodes < 2 then MinNodes := 2; + end + else + MinNodes := 2; + + if Registry.ValueExists('MinHue') then + MinHue := Registry.ReadInteger('MinHue') + else + MinHue := 0; + + if Registry.ValueExists('MinSat') then + MinSat := Registry.ReadInteger('MinSat') + else + MinSat := 0; + + if Registry.ValueExists('MinLum') then + MinLum := Registry.ReadInteger('MinLum') + else + MinLum := 0; + + if Registry.ValueExists('MaxNodes') then + begin + MaxNodes := Registry.ReadInteger('MaxNodes'); + if MaxNodes < MinNodes then MaxNodes := MinNodes; + end + else + MaxNodes := 10; + + if Registry.ValueExists('MaxHue') then + begin + MaxHue := Registry.ReadInteger('MaxHue'); + if MaxHue < 0 then MaxHue := 0; + end + else + MaxHue := 600; + + if Registry.ValueExists('MaxSat') then + begin + MaxSat := Registry.ReadInteger('MaxSat'); + if MaxSat < 0 then MaxSat := 0; + end + else + MaxSat := 100; + + if Registry.ValueExists('EqualStripes') then // AV + EqualStripes := Registry.ReadBool('EqualStripes') + else + EqualStripes := True; // gradient color stripes' width + + if Registry.ValueExists('ColorBlendType') then // AV + randColorBlend := Registry.ReadInteger('ColorBlendType') + else + randColorBlend := 0; // RGB-blending + + if Registry.ValueExists('RandomGradientFile') then + randGradientFile := Registry.ReadString('RandomGradientFile') + else + randGradientFile := ''; + + if Registry.ValueExists('RotationMode') then + MainForm_RotationMode := Registry.ReadInteger('RotationMode') + else MainForm_RotationMode := 0; + + if Registry.ValueExists('EnumerationMode') then // AV + FlameEnumMode := Registry.ReadInteger('EnumerationMode') + else FlameEnumMode := 0; + + if Registry.ValueExists('MaxLum') then + begin + MaxLum := Registry.ReadInteger('MaxLum'); + if MaxLum <= 0 then MaxLum := 100; + end + else + MaxLum := 100; + + if Registry.ValueExists('BatchSize') then + begin + BatchSize := Registry.ReadInteger('BatchSize'); + if BatchSize <= 0 then BatchSize := 10; + end + else + BatchSize := 10; + + if Registry.ValueExists('ScriptPath') then + ScriptPath := Registry.ReadString('ScriptPath') + else + ScriptPath := DefaultPath + 'Scripts\'; + + if Registry.ValueExists('FunctionLibrary') then + defLibrary := Registry.ReadString('FunctionLibrary') + else // AV: moved back into the scripting folder + defLibrary := DefaultPath + 'Scripts\Functions.asc'; + + if Registry.ValueExists('ExportFileFormat') then + ExportFileFormat := Registry.ReadInteger('ExportFileFormat') + else + ExportFileFormat := 1; + + if Registry.ValueExists('ExportWidth') then + begin + ExportWidth := Registry.ReadInteger('ExportWidth'); + if ExportWidth <= 0 then ExportWidth := 640; + end + else + ExportWidth := 640; + + if Registry.ValueExists('ExportHeight') then + begin + ExportHeight := Registry.ReadInteger('ExportHeight'); + if ExportHeight <= 0 then ExportHeight := 480; + end + else + ExportHeight := 480; + + if Registry.ValueExists('ExportDensity') then + begin + ExportDensity := Registry.ReadFloat('ExportDensity'); + if ExportDensity <= 0 then ExportDensity := 100; + end + else + ExportDensity := 100; + + if Registry.ValueExists('ExportOversample') then + begin + ExportOversample := Registry.ReadInteger('ExportOversample'); + if ExportOversample <= 0 then ExportOversample := 2; + end + else + ExportOversample := 2; + + if Registry.ValueExists('ExportFilter') then + begin + ExportFilter := Registry.ReadFloat('ExportFilter'); + if ExportFilter <= 0 then ExportFilter := 0.6; + end + else + ExportFilter := 0.6; + + // AV: don't need to waste our time for these properties + (* + if Registry.ValueExists('ExportBatches') then + begin + ExportBatches := Registry.ReadInteger('ExportBatches'); + if ExportBatches <= 0 then ExportBatches := 3; + end + else + ExportBatches := 3; + + if Registry.ValueExists('Nick') then + begin + SheepNick := Registry.ReadString('Nick'); + end + else + begin + SheepNick := ''; + end; + if Registry.ValueExists('URL') then + begin + SheepURL := Registry.ReadString('URL'); + end + else + begin + SheepURL := ''; + end; + if Registry.ValueExists('Pass') then + begin + SheepPW := Registry.ReadString('Pass'); + end + else + begin + SheepPW := ''; + end; + if Registry.ValueExists('Server') then + begin + SheepServer := Registry.ReadString('Server'); + end + else + begin + SheepServer := 'http://v2d5.sheepserver.net/'; + end; + *) + + if Registry.ValueExists('Renderer') then + flam3Path := Registry.ReadString('Renderer') + else + flam3Path := GetEnvVarValue('PROGRAMFILES') + '\flam3-3.0.1\flam3-render.exe'; // AV + + if Registry.ValueExists('ShowProgress') then + ShowProgress := Registry.ReadBool('ShowProgress') + else + ShowProgress := true; + + if Registry.ValueExists('LineCenterColor') then + LineCenterColor := Registry.ReadInteger('LineCenterColor') + else + LineCenterColor := $FFFFFF; + + if Registry.ValueExists('LineThirdsColor') then + LineThirdsColor := Registry.ReadInteger('LineThirdsColor') + else + LineThirdsColor := $0000FF; + + if Registry.ValueExists('LineGRColor') then + LineGRColor := Registry.ReadInteger('LineGRColor') + else + LineGRColor := $00FF00; + + if Registry.ValueExists('EnableGuides') then + EnableGuides := Registry.ReadBool('EnableGuides') + else + EnableGuides := false; + + { FormRender } + if Registry.ValueExists('SaveIncompleteRenders') then + SaveIncompleteRenders := Registry.ReadBool('SaveIncompleteRenders') + else + SaveIncompleteRenders := false; + + if Registry.ValueExists('ShowRenderStats') then + ShowRenderStats := Registry.ReadBool('ShowRenderStats') + else + ShowRenderStats := false; + if Registry.ValueExists('ShowRenderImage') then // AV + ShowRenderImage := Registry.ReadBool('ShowRenderImage') + else + ShowRenderImage := false; + if Registry.ValueExists('LowerRenderPriority') then + LowerRenderPriority := Registry.ReadBool('LowerRenderPriority') + else + LowerRenderPriority := false; + + if Registry.ValueExists('PNGTransparency') then begin + PNGTransparency := Registry.ReadInteger('PNGTransparency'); + if PNGTransparency > 1 then PNGTransparency := 1; // tmp + end else + PNGTransparency := 0; + + if Registry.ValueExists('ShowTransparency') then + ShowTransparency := Registry.ReadBool('ShowTransparency') + else + ShowTransparency := False; + + if Registry.ValueExists('ExtendMainPreview') then + ExtendMainPreview := Registry.ReadBool('ExtendMainPreview') + else + ExtendMainPreview := true; + + if Registry.ValueExists('MainPreviewScale') then begin + MainPreviewScale := Registry.ReadFloat('MainPreviewScale'); + if MainPreviewScale < 1 then MainPreviewScale := 1 + else if MainPreviewScale > 3 then MainPreviewScale := 3; + end else + MainPreviewScale := 1.2; + + if Registry.ValueExists('NrTreads') then begin + NrTreads := Registry.ReadInteger('NrTreads'); + if NrTreads < 1 then NrTreads := 1; // AV + end else + NrTreads := 1; + + if Registry.ValueExists('UseNrThreads') then begin + UseNrThreads := Registry.ReadInteger('UseNrThreads'); + if UseNrThreads < 1 then UseNrThreads := 1; + end else + UseNrThreads := 1; + + (* + if Registry.ValueExists('StartupCheckForUpdates') then begin + StartupCheckForUpdates := Registry.ReadBool('StartupCheckForUpdates'); + end else begin + StartupCheckForUpdates := true; + end; + *) + + // AV: animation defaults + if Registry.ValueExists('AnimPrefix') then + defAnimPrefix := Registry.ReadString('AnimPrefix') + else + defAnimPrefix := 'animate-'; + if Registry.ValueExists('AnimFPS') then + AnimFPS := Registry.ReadInteger('AnimFPS') + else + AnimFPS := 25; + if Registry.ValueExists('FrameExt') then + defFrameExt := Registry.ReadInteger('FrameExt') + else + defFrameExt := 1; + if Registry.ValueExists('CreateAnimFolder') then + CreateAnimFolder := Registry.ReadBool('CreateAnimFolder') + else + CreateAnimFolder := True; + + if Registry.ValueExists('AutoOpenLog') then + AutoOpenLog := Registry.ReadBool('AutoOpenLog') + else + AutoOpenLog := false; + + if Registry.ValueExists('ClassicListMode') then + ClassicListMode := Registry.ReadBool('ClassicListMode') + else + ClassicListMode := true; + + if Registry.ValueExists('LastOpenFile') then + LastOpenFile := Registry.ReadString('LastOpenFile') + else + LastOpenFile := ''; + + if Registry.ValueExists('LastOpenFileEntry') then + LastOpenFileEntry := Registry.ReadInteger('LastOpenFileEntry') + else + LastOpenFileEntry := 1; + + if Registry.ValueExists('RememberLastOpenFile') then + RememberLastOpenFile := Registry.ReadBool('RememberLastOpenFile') + else + RememberLastOpenFile := false; + + if Registry.ValueExists('UseSmallThumbnails') then + UseSmallThumbnails := Registry.ReadBool('UseSmallThumbnails') + else + UseSmallThumbnails := true; + + if Registry.ValueExists('HelpPath') then + HelpPath := Registry.ReadString('HelpPath') + else + HelpPath := DefaultPath + 'Apophysis AV.chm'; // TODO + + if Registry.ValueExists('ChaoticaPath') then + ChaoticaPath := Registry.ReadString('ChaoticaPath') + else + ChaoticaPath := ''; + { + if Registry.ValueExists('UseX64IfPossible') then + UseX64IfPossible := Registry.ReadBool('UseX64IfPossible') + else + UseX64IfPossible := false; + } + end + else + begin + // StartupCheckForUpdates := true; + AlwaysCreateBlankFlame := false; + MainForm_RotationMode := 0; + FlameEnumMode := 0; // AV + EditPrevQual := 1; + MutatePrevQual := 0; // AV: hack, to speed up the calculations + AdjustPrevQual := 1; + ThumbPrevQual := 1; // AV + AnimPrevQual := 1; // AV + GradientFile := ''; + defFlameFile := ''; + SavePath := DefaultPath + 'Flames.flame'; + WarnOnMissingPlugin := true; + SetEngLayout := false; + ApplyFlatten := true; + LanguageFile := ''; + HelpPath := DefaultPath + 'Apophysis AV.chm'; + defSmoothPaletteFile := DefaultPath + 'Gradients\SmoothPalette.ugr'; + ConfirmDelete := True; + ConfirmExit := True; + ConfirmClearScript := False; // AV + ConfirmResetUndo := False; // AV + OldPaletteFormat := false; + NumTries := 10; + TryLength := 100000; + randMinTransforms := 2; + randMaxTransforms := 3; + mutantMinTransforms := 2; + mutantMaxTransforms := 6; + randGradient := 0; + PreserveQuality := false; + KeepBackground := False; + RandBackColor := $000000; + RandomizeTemplates := True; + UPRPath := DefaultPath + 'ApophysisAV_export.upr'; // AV + ImageFolder := GetEnvVarValue('USERPROFILE') + '\Pictures\'; // AV + ParamFolder := DefaultPath; + ScreenShotPath := DefaultPath + 'ScreenShots\'; // AV + defScriptFile := ''; // AV + AutoSaveXML := True; // AV + UPRWidth := 640; + UPRHeight := 480; + AnimFPS := 25; + defFrameExt := 1; + defAnimPrefix := 'animate-'; + CreateAnimFolder := True; + RandomPrefix := 'ApoAV-'; + RandomIndex := 0; + RandomDate := ''; + SymmetryType := 0; + SymmetryOrder := 4; + SymmetryNVars := 12; + MinNodes := 2; + MaxNodes := 10; + MinHue := 0; + MinSat := 0; + MinLum := 0; + MaxHue := 600; + MaxSat := 100; + MaxLum := 100; + randGradientFile := ''; + randColorBlend := 0; // AV + EqualStripes := True; // AV + BatchSize := 10; + ScriptPath := DefaultPath + 'Scripts\'; + defLibrary := DefaultPath + 'Scripts\Functions.asc'; // AV + ExportFileFormat := 1; + ExportWidth := 640; + ExportHeight := 480; + ExportDensity := 100; + ExportOversample := 2; + ExportFilter := 0.6; + (* + ExportBatches := 3; + SheepNick := ''; + SheepURL := ''; + SheepPW := ''; + SheepServer := 'http://v2d5.sheepserver.net/'; + *) + flam3Path := GetEnvVarValue('PROGRAMFILES') + '\flam3-3.0.1\flam3-render.exe'; // AV + ShowProgress := true; + SaveIncompleteRenders := false; + LowerRenderPriority := false; + ShowRenderStats := false; + ShowRenderImage := false; + PNGTransparency := 0; + ShowTransparency := False; + MainPreviewScale := 1.2; + ExtendMainPreview := true; + NrTreads := 1; + UseNrThreads := 1; + AutoOpenLog := false; + ClassicListMode := true; + LastOpenFile := ''; + LastOpenFileEntry := 1; + RememberLastOpenFile := false; + UseSmallThumbnails := true; + LineCenterColor := $FFFFFF; + LineThirdsColor := $0000FF; + LineGRColor := $00FF00; + EnableGuides := false; + ChaoticaPath := ''; + //UseX64IfPossible := false; + end; + Registry.CloseKey; + + SetLength(Variations, NRVAR); + SetLength(FavouriteVariations, NRVAR); // AV + if Registry.OpenKey('Software\' + APP_NAME + '\Variations', False) then + begin + for i := 0 to NRVAR-1 do + begin + if Registry.ValueExists(Varnames(i)) then + begin + VarUsed := Registry.ReadInteger(Varnames(i)); + Variations[i] := (VarUsed and 1) <> 0; + FavouriteVariations[i] := (VarUsed and 2) <> 0; + end + else + Variations[i] := false; + end; + end + else begin + // AV: we dont't need multiple z- and pre_ variations by default... + Variations[0] := True; // linear + Variations[3] := True; // spherical + for i := 10 to 14 do + Variations[i] := True; + Variations[46] := True; // pdj + Variations[47] := True; // julian + end; + Registry.CloseKey; + + { Editor } // --Z-- moved from EditForm + if Registry.OpenKey('Software\' + APP_NAME + '\Forms\Editor', False) then + begin + if Registry.ValueExists('UseTransformColors') then + UseTransformColors := Registry.ReadBool('UseTransformColors') + else + UseTransformColors := False; + if Registry.ValueExists('HelpersEnabled') then + HelpersEnabled := Registry.ReadBool('HelpersEnabled') + else + HelpersEnabled := true; + if Registry.ValueExists('ShowAllXforms') then + ShowAllXforms := Registry.ReadBool('ShowAllXforms') + else + ShowAllXforms := true; + + if Registry.ValueExists('AllowResetCoefs') then // AV + AllowResetCoefs := Registry.ReadBool('AllowResetCoefs') + else + AllowResetCoefs := false; + if Registry.ValueExists('AllowResetLinear') then // AV + AllowResetLinear := Registry.ReadBool('AllowResetLinear') + else + AllowResetLinear := true; + if Registry.ValueExists('SyncTriangles') then // AV + UseTriangleSync := Registry.ReadBool('SyncTriangles') + else + UseTriangleSync := false; + + if Registry.ValueExists('EnableEditorPreview') then + EnableEditorPreview := Registry.ReadBool('EnableEditorPreview') + else + EnableEditorPreview := false; + if Registry.ValueExists('EditorPreviewTransparency') then + EditorPreviewTransparency := Registry.ReadInteger('EditorPreviewTransparency') + else + EditorPreviewTransparency := 192; + + if Registry.ValueExists('BackgroundColor') then + EditorBkgColor := Registry.ReadInteger('BackgroundColor') + else + EditorBkgColor := integer(clBlack); + if Registry.ValueExists('GridColor1') then + GridColor1 := Registry.ReadInteger('GridColor1') + else + GridColor1 := $444444; + if Registry.ValueExists('GridColor2') then + GridColor2 := Registry.ReadInteger('GridColor2') + else + GridColor2 := $333333; + if Registry.ValueExists('HelpersColor') then + HelpersColor := Registry.ReadInteger('HelpersColor') + else + HelpersColor := $808080; + if Registry.ValueExists('ReferenceTriangleColor') then + ReferenceTriangleColor := Registry.ReadInteger('ReferenceTriangleColor') + else + ReferenceTriangleColor := $7f7f7f; + if Registry.ValueExists('FlipColor') then + FlipColor := Registry.ReadInteger('FlipColor') + else + FlipColor := $808080; + if Registry.ValueExists('ExtendedEdit') then + ExtEditEnabled := Registry.ReadBool('ExtendedEdit') + else ExtEditEnabled := true; + if Registry.ValueExists('LockTransformAxis') then + TransformAxisLock := Registry.ReadBool('LockTransformAxis') + else TransformAxisLock := true; + if Registry.ValueExists('RebuildXaosLinks') then + RebuildXaosLinks := Registry.ReadBool('RebuildXaosLinks') + else RebuildXaosLinks := true; + end + else begin + UseTransformColors := false; + HelpersEnabled := true; + ShowAllXforms := true; + EnableEditorPreview := false; + EditorPreviewTransparency := 192; + EditorBkgColor := $000000; + GridColor1 := $444444; + GridColor2 := $333333; + HelpersColor := $808080; + FlipColor := $808080; + ReferenceTriangleColor := integer(clGray); + ExtEditEnabled := true; + TransformAxisLock := true; + RebuildXaosLinks := true; + AllowResetCoefs := false; // AV + AllowResetLinear := true; // AV + UseTriangleSync := false; // AV + end; + Registry.CloseKey; + + { Render } + if Registry.OpenKey('Software\' + APP_NAME + '\Render', False) then + begin + if Registry.ValueExists('Path') then + RenderPath := Registry.ReadString('Path') + else + RenderPath := DefaultPath; + + if Registry.ValueExists('SampleDensity') then + renderDensity := Registry.ReadFloat('SampleDensity') + else + renderDensity := 200; + + if Registry.ValueExists('FilterRadius') then + renderFilterRadius := Registry.ReadFloat('FilterRadius') + else + renderFilterRadius := 0.4; + + if Registry.ValueExists('Oversample') then + renderOversample := Registry.ReadInteger('Oversample') + else + renderOversample := 2; + + if Registry.ValueExists('Width') then + renderWidth := Registry.ReadInteger('Width') + else + renderWidth := 1024; + + if Registry.ValueExists('Height') then + renderHeight := Registry.ReadInteger('Height') + else + renderHeight := 768; + + if Registry.ValueExists('JPEGQuality') then + JPEGQuality := Registry.ReadInteger('JPEGQuality') + else + JPEGQuality := 100; + + if Registry.ValueExists('FileFormat') then + renderFileFormat := Registry.ReadInteger('FileFormat') + else + renderFileFormat := 3; + + if Registry.ValueExists('EmbedFlame') then // AV + EmbedFlame := Registry.ReadBool('EmbedFlame') + else + EmbedFlame := True; + if Registry.ValueExists('SaveInFlame') then // AV + SaveInFlame := Registry.ReadBool('SaveInFlame') + else + SaveInFlame := True; + { + if Registry.ValueExists('BitsPerSample') then + renderBitsPerSample := Registry.ReadInteger('BitsPerSample') + else + renderBitsPerSample := 0; + + if Registry.ValueExists('StoreEXIF') then begin + StoreEXIF := Registry.ReadBool('StoreEXIF'); + end else begin + StoreEXIF := false; + end; + if Registry.ValueExists('StoreParamsEXIF') then begin + StoreParamsEXIF := Registry.ReadBool('StoreParamsEXIF'); + end else begin + StoreParamsEXIF := false; + end; + if Registry.ValueExists('ExifAuthor') then begin + ExifAuthor := Registry.ReadString('ExifAuthor'); + end else begin + ExifAuthor := ''; + end; + } + end + else + begin + renderFileFormat := 2; + JPEGQuality := 100; + renderPath := DefaultPath; + renderDensity := 200; + renderOversample := 2; + renderFilterRadius := 0.4; + renderWidth := 1024; + renderHeight := 768; + EmbedFlame := True; // AV + SaveInFlame := True; // AV + { + renderBitsPerSample := 0; + StoreEXIF := false; + ExifAuthor := ''; + StoreParamsEXIF := false; + } + end; + Registry.CloseKey; + + {UPR} + if Registry.OpenKey('Software\' + APP_NAME + '\UPR', False) then + begin + if Registry.ValueExists('FlameColoringFile') then + UPRColoringFile := Registry.ReadString('FlameColoringFile') + else + UPRColoringFile := 'apophysis.ucl'; + + if Registry.ValueExists('FlameColoringIdent') then + UPRColoringIdent := Registry.ReadString('FlameColoringIdent') + else + UPRColoringIdent := 'apophysis-205'; // AV: fixed + + if Registry.ValueExists('FlameFormulaFile') then + UPRFormulaFile := Registry.ReadString('FlameFormulaFile') + else + UPRFormulaFile := 'mt.ufm'; + if Registry.ValueExists('FlameFormulaIdent') then + UPRFormulaIdent := Registry.ReadString('FlameFormulaIdent') + else + UPRFormulaIdent := 'mt-pixel'; + + if Registry.ValueExists('FlameIterDensity') then + UPRSampleDensity := Registry.ReadInteger('FlameIterDensity') + else + UPRSampleDensity := 35; + if Registry.ValueExists('FlameFilterRadius') then + UPRFilterRadius := Registry.ReadFloat('FlameFilterRadius') + else + UPRFilterRadius := 0.7; + if Registry.ValueExists('FlameOversample') then + UPROversample := Registry.ReadInteger('FlameOversample') + else + UPROversample := 3; + if Registry.ValueExists('FlameAdjustDensity') then + UPRAdjustDensity := Registry.ReadBool('FlameAdjustDensity') + else + UPRAdjustDensity := true; + end + else + begin + UPRColoringFile := 'apophysis.ucl'; + UPRColoringIdent := 'apophysis-205'; + UPRFormulaFile := 'mt.ufm'; + UPRFormulaIdent := 'mt-pixel'; + UPRSampleDensity := 35; + UPRFilterRadius := 0.7; + UPROversample := 3; + UPRAdjustDensity := True; ; + end; + Registry.CloseKey; + + if Registry.OpenKey('Software\' + APP_NAME + '\Display', False) then + begin + if Registry.ValueExists('SampleDensity') then + defSampleDensity := Registry.ReadFloat('SampleDensity') + else + defSampleDensity := 5; + if Registry.ValueExists('Gamma') then + defGamma := Registry.ReadFloat('Gamma') + else + defGamma := 4; + if Registry.ValueExists('Brightness') then + defBrightness := Registry.ReadFloat('Brightness') + else + defBrightness := 4; + if Registry.ValueExists('Contrast') then // AV + defContrast := Registry.ReadFloat('Contrast') + else + defContrast := 1; // AV + if Registry.ValueExists('Vibrancy') then + defVibrancy := Registry.ReadFloat('Vibrancy') + else + defVibrancy := 1; + if Registry.ValueExists('FilterRadius') then + defFilterRadius := Registry.ReadFloat('FilterRadius') + else + defFilterRadius := 0.2; + if Registry.ValueExists('GammaThreshold') then + defGammaThreshold := Registry.ReadFloat('GammaThreshold') + else + defGammaThreshold := 0.01; + if Registry.ValueExists('Oversample') then + defOversample := Registry.ReadInteger('Oversample') + else + defOversample := 1; + if Registry.ValueExists('Fuse') then // AV + Fuse := Registry.ReadInteger('Fuse') + else + Fuse := 15; + + if Registry.ValueExists('RhombicTileRadius') then // AV + RhombTR := Registry.ReadFloat('RhombicTileRadius') + else + RhombTR := 1; + if Registry.ValueExists('SquareTileRadius') then // AV + SquareTR := Registry.ReadFloat('SquareTileRadius') + else + SquareTR := 1.414214; //Round6(sqrt(2)); + if Registry.ValueExists('HexagonalTileRadius') then // AV + HexTR := Registry.ReadFloat('HexagonalTileRadius') + else + HexTR := 2; + + if Registry.ValueExists('PreviewLowQuality') then + prevLowQuality := Registry.ReadFloat('PreviewLowQuality') + else + prevLowQuality := 0.1; + if Registry.ValueExists('PreviewMediumQuality') then + prevMediumQuality := Registry.ReadFloat('PreviewMediumQuality') + else + prevMediumQuality := 1; + if Registry.ValueExists('PreviewHighQuality') then + prevHighQuality := Registry.ReadFloat('PreviewHighQuality') + else + prevHighQuality := 5; + end + else + begin + defSampleDensity := 5; + defGamma := 4; + defBrightness := 4; + defVibrancy := 1; + defContrast := 1; // AV + defFilterRadius := 0.2; + defOversample := 1; + defGammaThreshold := 0.01; + prevLowQuality := 0.1; + prevMediumQuality := 1; + prevHighQuality := 5; + Fuse := 15; + RhombTR := 1; + HexTR := 2; + SquareTR := 1.414214; //Round6(sqrt(2)); + end; + Registry.CloseKey; + + if Registry.OpenKey('Software\' + APP_NAME + '\Autosave', False) then + begin + if Registry.ValueExists('AutoSaveEnabled') then + AutoSaveEnabled := Registry.ReadBool('AutoSaveEnabled') + else + AutoSaveEnabled := false; + + if Registry.ValueExists('AutoSaveFreq') then + AutoSaveFreq := Registry.ReadInteger('AutoSaveFreq') + else + AutoSaveFreq := 2; + + if Registry.ValueExists('AutoSavePath') then + AutoSavePath := Registry.ReadString('AutoSavePath') + else + AutoSavePath := DefaultPath + 'autosave.flame'; + end else begin + AutoSaveEnabled := false; + AutoSaveFreq := 2; + AutoSavePath := DefaultPath + 'autosave.flame'; + end; + Registry.CloseKey; + finally + Registry.Free; + end; + + PluginPath := ReadPluginDir; + + // AV: create a folder for Apophysis temp files + AppData := GetEnvVarValue('APPDATA') + '\Apophysis AV\'; + if not DirectoryExists(AppData) then // AV + if not CreateDir(AppData) then AppData := AppPath; + + UseX64IfPossible := CheckX64; +end; + +procedure SaveSettings; +var + Registry: TRegistry; + i: integer; + VarUsed: byte; + + function VarState(const a, b: boolean): byte; inline; + begin + Result := 0; + if a and b then Exit(3) + else if a then Exit(1) + else if b then Exit(2); + end; + +begin + // SavePluginDir(PluginPath); // AV: moved into main procedure + + Registry := TRegistry.Create; + try + Registry.RootKey := HKEY_CURRENT_USER; + { Defaults } + if Registry.OpenKey('\Software\' + APP_NAME + '\Defaults', True) then + begin + // Registry.WriteBool('StartupCheckForUpdates', StartupCheckForUpdates); + Registry.WriteBool('AlwaysCreateBlankFlame', AlwaysCreateBlankFlame); + Registry.WriteString('GradientFile', GradientFile); + Registry.WriteString('PluginPath', PluginPath); // AV + Registry.WriteString('HelpPath', HelpPath); + Registry.WriteString('SmoothPaletteFile', SmoothPaletteFile); + Registry.WriteString('DefaultScript', defScriptFile); // AV + Registry.WriteBool('PlaySoundOnRenderComplete', PlaySoundOnRenderComplete); + Registry.WriteString('RenderCompleteSoundFile', RenderCompleteSoundFile); + Registry.WriteBool('AutoOpenLog', AutoOpenLog); + Registry.WriteBool('ClassicListMode', ClassicListMode); + + Registry.WriteBool('WarnOnMissingPlugin', WarnOnMissingPlugin); + Registry.WriteBool('SetEnglishLayout', SetEngLayout); + Registry.WriteBool('RandomizeTemplates', RandomizeTemplates); + Registry.WriteBool('ConfirmClearScript', ConfirmClearScript); + Registry.WriteBool('ConfirmResetUndo', ConfirmResetUndo); + Registry.WriteBool('AutoSaveXML', AutoSaveXML); + Registry.WriteBool('ApplyFlatten', ApplyFlatten); + Registry.WriteString('LanguageFile', LanguageFile); + Registry.WriteString('LastOpenFile', LastOpenFile); + Registry.WriteInteger('LastOpenFileEntry', LastOpenFileEntry); + Registry.WriteBool('RememberLastOpenFile', RememberLastOpenFile); + Registry.WriteBool('UseSmallThumbnails', UseSmallThumbnails); + Registry.WriteInteger('LineCenterColor', LineCenterColor); + Registry.WriteInteger('LineThirdsColor', LineThirdsColor); + Registry.WriteInteger('LineGRColor', LineGRColor); + Registry.WriteBool('EnableGuides', EnableGuides); + Registry.WriteString('ChaoticaPath', ChaoticaPath); + //Registry.WriteBool('UseX64IfPossible', UseX64IfPossible); + + Registry.WriteBool('ConfirmDelete', ConfirmDelete); + Registry.WriteBool('OldPaletteFormat', OldPaletteFormat); + Registry.WriteBool('ConfirmExit', ConfirmExit); + Registry.WriteInteger('NumTries', NumTries); + Registry.WriteInteger('TryLength', TryLength); + Registry.WriteInteger('MinTransforms', randMinTransforms); + Registry.WriteInteger('MaxTransforms', randMaxTransforms); + Registry.WriteInteger('MutationMinTransforms', mutantMinTransforms); + Registry.WriteInteger('MutationMaxTransforms', mutantMaxTransforms); + Registry.WriteInteger('RandomGradient', randGradient); + Registry.WriteString('ParameterFolder3D', ParamFolder); + Registry.WriteString('UPRPath', UPRPath); + Registry.WriteString('ImageFolder', ImageFolder); + Registry.WriteString('SavePath3D', SavePath); + Registry.WriteInteger('UPRWidth', UPRWidth); + Registry.WriteInteger('UPRHeight', UPRHeight); + Registry.WriteString('BrowserPath', BrowserPath); + Registry.WriteInteger('EditPreviewQaulity', EditPrevQual); + Registry.WriteInteger('MutatePreviewQaulity', MutatePrevQual); + Registry.WriteInteger('AdjustPreviewQaulity', AdjustPrevQual); + Registry.WriteInteger('ThumbPrevQuality', ThumbPrevQual); // AV + Registry.WriteInteger('AnimPrevQuality', AnimPrevQual); // AV + Registry.WriteString('RandomPrefix', RandomPrefix); + Registry.WriteString('RandomDate', RandomDate); + Registry.WriteInteger('RandomIndex', RandomIndex); + Registry.WriteString('DefaultFlameFile3D', defFlameFile); + Registry.WriteString('SmoothPalettePath', SmoothPalettePath); + Registry.WriteString('GradientFile', GradientFile); + Registry.WriteInteger('TryLength', TryLength); + Registry.WriteInteger('NumTries', NumTries); + Registry.WriteString('SmoothPaletteFile', defSmoothPaletteFile); + Registry.WriteInteger('SymmetryType', SymmetryType); + Registry.WriteInteger('SymmetryOrder', SymmetryOrder); + Registry.WriteInteger('SymmetryNVars', SymmetryNVars); + Registry.WriteInteger('RotationMode', MainForm_RotationMode); + Registry.WriteInteger('EnumerationMode', FlameEnumMode); // AV + Registry.WriteInteger('MinNodes', MinNodes); + Registry.WriteInteger('MinHue', MinHue); + Registry.WriteInteger('MinSat', MinSat); + Registry.WriteInteger('MinLum', MinLum); + Registry.WriteInteger('MaxNodes', MaxNodes); + Registry.WriteInteger('MaxHue', MaxHue); + Registry.WriteInteger('MaxSat', MaxSat); + Registry.WriteInteger('MaxLum', MaxLum); + Registry.WriteString('RandomGradientFile', randGradientFile); + Registry.WriteInteger('ColorBlendType', randColorBlend); //AV + Registry.WriteBool('EqualStripes', EqualStripes); // AV + Registry.WriteInteger('BatchSize', BatchSize); + Registry.WriteString('ScriptPath', ScriptPath); + Registry.WriteInteger('ExportFileFormat', ExportFileFormat); + Registry.WriteInteger('ExportWidth', ExportWidth); + Registry.WriteInteger('ExportHeight', ExportHeight); + Registry.WriteFloat('ExportDensity', ExportDensity); + Registry.WriteFloat('ExportFilter', ExportFilter); + Registry.WriteInteger('ExportOversample', ExportOversample); + (* + Registry.WriteInteger('ExportBatches', ExportBatches); + Registry.WriteString('Nick', SheepNick); + Registry.WriteString('URL', SheepURL); + Registry.WriteString('Server', SheepServer); + Registry.WriteString('Pass', SheepPW); + *) + Registry.WriteString('Renderer', flam3Path); + Registry.WriteBool('ShowProgress', ShowProgress); + Registry.WriteBool('KeepBackground', KeepBackground); + Registry.WriteInteger('RandBackColor', RandBackColor); + Registry.WriteBool('PreserveQuality', PreserveQuality); + Registry.WriteString('FunctionLibrary', defLibrary); + Registry.WriteString('ScreenshotsFolder', ScreenShotPath); // AV + + Registry.WriteBool('ShowTransparency', ShowTransparency); + Registry.WriteInteger('PNGTransparency', PNGTransparency); + Registry.WriteBool('ExtendMainPreview', ExtendMainPreview); + Registry.WriteFloat('MainPreviewScale', MainPreviewScale); + + Registry.WriteBool('SaveIncompleteRenders', SaveIncompleteRenders); + Registry.WriteBool('ShowRenderStats', ShowRenderStats); + Registry.WriteBool('ShowRenderImage', ShowRenderImage); + Registry.WriteBool('LowerRenderPriority', LowerRenderPriority); + + // AV: for animation + Registry.WriteInteger('AnimFPS', AnimFPS); + Registry.WriteString('AnimPrefix', defAnimPrefix); + Registry.WriteInteger('FrameExt', defFrameExt); + Registry.WriteBool('CreateAnimFolder', CreateAnimFolder); + + Registry.WriteInteger('NrTreads', NrTreads); + Registry.WriteInteger('UseNrThreads', UseNrThreads); + end; + Registry.CloseKey; + + if Registry.OpenKey('\Software\' + APP_NAME + '\Variations', True) then + begin + for i := 0 to NRVAR-1 do + begin + VarUsed := 0; + if Registry.ValueExists(Varnames(i)) then + begin + VarUsed := VarState(Variations[i], FavouriteVariations[i]); + if Registry.ReadInteger(Varnames(i)) = VarUsed then continue; //? + end; + Registry.WriteInteger(Varnames(i), VarUsed); + end; + end; + Registry.CloseKey; + + { Editor } + if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Editor', True) then + begin + Registry.WriteBool('UseTransformColors', UseTransformColors); + Registry.WriteBool('HelpersEnabled', HelpersEnabled); + Registry.WriteBool('ShowAllXforms', ShowAllXforms); + Registry.WriteBool('EnableEditorPreview', EnableEditorPreview); + Registry.WriteInteger('EditorPreviewTransparency', EditorPreviewTransparency); + Registry.WriteInteger('BackgroundColor', EditorBkgColor); + Registry.WriteInteger('GridColor1', GridColor1); + Registry.WriteInteger('GridColor2', GridColor2); + Registry.WriteInteger('HelpersColor', HelpersColor); + Registry.WriteInteger('FlipColor', FlipColor); + Registry.WriteInteger('ReferenceTriangleColor', ReferenceTriangleColor); + Registry.WriteBool('ExtendedEdit', ExtEditEnabled); + Registry.WriteBool('LockTransformAxis', TransformAxisLock); + Registry.WriteBool('RebuildXaosLinks', RebuildXaosLinks); + Registry.WriteBool('AllowResetCoefs', AllowResetCoefs); // AV + Registry.WriteBool('AllowResetLinear', AllowResetLinear); // AV + Registry.WriteBool('SyncTriangles', UseTriangleSync); // AV + end; + Registry.CloseKey; + + { Display } + if Registry.OpenKey('\Software\' + APP_NAME + '\Display', True) then + begin + Registry.WriteFloat('SampleDensity', defSampleDensity); + Registry.WriteFloat('Gamma', defGamma); + Registry.WriteFloat('Brightness', defBrightness); + Registry.WriteFloat('Contrast', defContrast); + Registry.WriteFloat('Vibrancy', defVibrancy); + Registry.WriteFloat('FilterRadius', defFilterRadius); + Registry.WriteInteger('Oversample', defOversample); + Registry.WriteInteger('Fuse', Fuse); + Registry.WriteFloat('GammaThreshold', defGammaThreshold); + Registry.WriteFloat('PreviewLowQuality', prevLowQuality); + Registry.WriteFloat('PreviewMediumQuality', prevMediumQuality); + Registry.WriteFloat('PreviewHighQuality', prevHighQuality); + Registry.WriteFloat('HexagonalTileRadius', HexTR); + Registry.WriteFloat('SquareTileRadius', SquareTR); + Registry.WriteFloat('RhombicTileRadius', RhombTR); + end; + Registry.CloseKey; + + { UPR } + if Registry.OpenKey('\Software\' + APP_NAME + '\UPR', True) then + begin + Registry.WriteString('FlameColoringFile', UPRColoringFile); + Registry.WriteString('FlameColoringIdent', UPRColoringIdent); + Registry.WriteString('FlameFormulaFile', UPRFormulaFile); + Registry.WriteString('FlameFormulaIdent', UPRFormulaIdent); + Registry.WriteInteger('FlameIterDensity', UPRSampleDensity); + Registry.WriteFloat('FlameFilterRadius', UPRFilterRadius); + Registry.WriteInteger('FlameOversample', UPROversample); + Registry.WriteBool('FlameAdjustDensity', UPRAdjustDensity); + end; + Registry.CloseKey; + + if Registry.OpenKey('\Software\' + APP_NAME + '\Render', True) then + begin + Registry.WriteString('Path', renderPath); + Registry.WriteFloat('SampleDensity', renderDensity); + Registry.WriteInteger('Oversample', renderOversample); + Registry.WriteFloat('FilterRadius', renderFilterRadius); + Registry.WriteInteger('Width', renderWidth); + Registry.WriteInteger('Height', renderHeight); + Registry.WriteInteger('JPEGQuality', JPEGQuality); + Registry.WriteInteger('FileFormat', renderFileFormat); + Registry.WriteBool('EmbedFlame', EmbedFlame); // AV + Registry.WriteBool('SaveInFlame', SaveInFlame); // AV + { + Registry.WriteBool('StoreEXIF', StoreEXIF); + Registry.WriteBool('StoreParamsEXIF', StoreParamsEXIF); + Registry.WriteString('ExifAuthor', ExifAuthor); + } + end; + Registry.CloseKey; + + if Registry.OpenKey('\Software\' + APP_NAME + '\Autosave', True) then + begin + Registry.WriteBool('AutoSaveEnabled', AutoSaveEnabled); + Registry.WriteInteger('AutoSaveFreq', AutoSaveFreq); + Registry.WriteString('AutoSavePath', AutoSavePath); + end; + Registry.CloseKey; + finally + Registry.Free; + end; +end; + +end. + diff --git a/Rendering/BucketFillerThread.pas b/Rendering/BucketFillerThread.pas index 308a177..ea4e4ac 100644 --- a/Rendering/BucketFillerThread.pas +++ b/Rendering/BucketFillerThread.pas @@ -5,6 +5,7 @@ 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 @@ -26,7 +27,7 @@ unit BucketFillerThread; interface uses - Classes, Windows, ControlPoint, RenderingInterface, XForm; + Classes, Windows, ControlPoint; type TBucketFillerThread = class(TThread) @@ -39,7 +40,7 @@ type nrbatches: integer; batchcounter: Pinteger; - ColorMap: TColorMapArray; + //ColorMap: TColorMapArray; CriticalSection: TRTLCriticalSection; AddPointsProc: procedure (const points: TPointsArray) of object; @@ -53,8 +54,6 @@ type implementation -//uses SysUtils, FormRender; - /////////////////////////////////////////////////////////////////////////////// constructor TBucketFillerThread.Create(cp: TControlPoint); begin diff --git a/Rendering/ImageMaker.pas b/Rendering/ImageMaker.pas index edd0285..7291094 100644 --- a/Rendering/ImageMaker.pas +++ b/Rendering/ImageMaker.pas @@ -27,7 +27,7 @@ unit ImageMaker; interface uses - Windows, Graphics, ControlPoint, RenderingCommon, PngImage, Bezier; + Windows, Graphics, ControlPoint, RenderingCommon, Vcl.Imaging.PngImage, Bezier; type TPalette = record logpal : TLogPalette; @@ -97,7 +97,7 @@ type implementation uses - Math, SysUtils, JPEG, Global, Types; + Math, SysUtils, Vcl.Imaging.JPEG, Global, Types; { TImageMaker } @@ -108,12 +108,11 @@ type red: byte; end; + // AV: specific types used only for transparency PByteArray = ^TByteArray; - TByteArray = array[0..0] of byte; -// PLongintArray = ^TLongintArray; -// TLongintArray = array[0..0] of Longint; + TByteArray = array[0..0] of byte; // AV: single-element array?! why not [word] instead [0..0]?! PRGBArray = ^TRGBArray; - TRGBArray = array[0..0] of TRGB; + TRGBArray = array[0..0] of TRGB; // AV: single-element array?! why not [word] instead [0..0]?! /////////////////////////////////////////////////////////////////////////////// constructor TImageMaker.Create; @@ -394,7 +393,6 @@ var f_select : double; f_select_int, f_coef_idx : integer; arr_filt_width : integer; - c : array of double; ss : integer; scf:boolean; scfact : double; @@ -407,7 +405,6 @@ var bx, by: integer; label zero_alpha; begin - SetLength(c, 4); if fcp.gamma = 0 then gamma := fcp.gamma @@ -716,7 +713,7 @@ end; procedure TImageMaker.SaveImage(FileName: String); var i,row: integer; - PngObject: TPngObject; + PngObject: TPNGImage; rowbm, rowpng: PByteArray; JPEGImage: TJPEGImage; PNGerror: boolean; @@ -725,7 +722,7 @@ begin if UpperCase(ExtractFileExt(FileName)) = '.PNG' then begin pngError := false; - PngObject := TPngObject.Create; + PngObject := TPNGImage.Create; try PngObject.Assign(FBitmap); if fcp.Transparency then // PNGTransparency <> 0 diff --git a/Rendering/RenderThread.pas b/Rendering/RenderThread.pas index 8d5871c..f61a85d 100644 --- a/Rendering/RenderThread.pas +++ b/Rendering/RenderThread.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + 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 diff --git a/Rendering/RenderingCommon.pas b/Rendering/RenderingCommon.pas index 5522c03..0867551 100644 --- a/Rendering/RenderingCommon.pas +++ b/Rendering/RenderingCommon.pas @@ -5,7 +5,7 @@ Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne - ``Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina + Apophysis AV "Phoenix Edition" Copyright (C) 2021 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 @@ -28,7 +28,7 @@ type TOnFinish = procedure of object; TOnProgress = procedure(prog: double) of object; - {$ifdef Apo7X64} + {$ifdef CPUX64} TBucket = Record Red, Green, @@ -55,6 +55,7 @@ type procedure TrimWorkingSet; implementation + uses Windows; procedure TrimWorkingSet; diff --git a/Rendering/RenderingImplementation.pas b/Rendering/RenderingImplementation.pas index 65d7659..b032dae 100644 --- a/Rendering/RenderingImplementation.pas +++ b/Rendering/RenderingImplementation.pas @@ -23,16 +23,14 @@ } unit RenderingImplementation; -{$ifdef Apo7X64} -{$else} +{$ifndef CPUX64} {$define _ASM_} {$endif} interface uses -{$ifndef _ASM_} -{$else} +{$ifdef _ASM_} AsmRandom, {$endif} Windows, Classes, Forms, Graphics, Global, diff --git a/Rendering/RenderingInterface.pas b/Rendering/RenderingInterface.pas index 1d06a5b..a66fb03 100644 --- a/Rendering/RenderingInterface.pas +++ b/Rendering/RenderingInterface.pas @@ -26,8 +26,8 @@ unit RenderingInterface; interface uses - Windows, Graphics, Classes, RenderingCommon, - Controlpoint, ImageMaker, PngImage, Translation; + Windows, Graphics, Classes, RenderingCommon, ImageMaker, + ControlPoint, Vcl.Imaging.PngImage, Translation; /////////////////////////////////////////////////////////////////////////////// // @@ -51,7 +51,7 @@ type Green, Blue: - {$ifdef Apo7X64} + {$ifdef CPUX64} double {$else} single @@ -71,9 +71,6 @@ type const MAX_FILTER_WIDTH = 25; -//const - //SizeOfBucket: array[0..3] of byte = (32, 32, 32, 32); - function TimeToString(t: TDateTime): string; type @@ -296,9 +293,7 @@ type implementation uses - Math, SysUtils, Forms, - RenderingImplementation, - Binary, Global; + Math, SysUtils, Forms, RenderingImplementation, Binary, Global; /////////////////////////////////////////////////////////////////////////////// // @@ -309,6 +304,7 @@ procedure TBaseRenderer.Hibernate(filePath: string); begin // todo end; + procedure TBaseRenderer.Resume(filePath: string); begin // todo @@ -344,10 +340,11 @@ begin // entered memory - imagesize MaxMemory := FMaxMem * 1024 * 1024 - 4 * image_Height * int64(image_Width); - if (SingleBuffer) then - ApproxMemory := 16 * sqr(oversample) * image_Height * int64(image_Width) - else - ApproxMemory := 32 * sqr(oversample) * image_Height * int64(image_Width); + {$ifdef CPUX86} + ApproxMemory := 16 * sqr(oversample) * image_Height * int64(image_Width); + {$else} + ApproxMemory := 32 * sqr(oversample) * image_Height * int64(image_Width); + {$endif} assert(MaxMemory > 0); if MaxMemory <= 0 then exit; @@ -816,10 +813,12 @@ begin try // FStop := 0; // TrimWorkingSet; - if SingleBuffer then - TimeTrace(Format(TextByKey('common-trace-allocating'), [BucketSize * 16 / 1048576])) - else - TimeTrace(Format(TextByKey('common-trace-allocating'), [BucketSize * 32 / 1048576])); + + {$ifdef CPUX86} + TimeTrace(Format(TextByKey('common-trace-allocating'), [BucketSize * 16 / 1048576])); + {$else} + TimeTrace(Format(TextByKey('common-trace-allocating'), [BucketSize * 32 / 1048576])); + {$endif} AllocateBuckets; diff --git a/System/CurvesControl.pas b/System/CurvesControl.pas index 9947a44..ecf43e9 100644 --- a/System/CurvesControl.pas +++ b/System/CurvesControl.pas @@ -3,15 +3,9 @@ unit CurvesControl; interface uses - Windows, Messages, SysUtils, Variants, Classes, Math, ControlPoint, + Windows, SysUtils, Classes, Math, ControlPoint, Graphics, Controls, Forms, Bezier, CustomDrawControl, Vcl.ExtCtrls; -const - point_size: double = 8; - accurancy: double = 3; - channel_count: integer = 4; - padding = 3; - const MAX_CHANNEL = 3; @@ -73,6 +67,9 @@ implementation uses Main, Editor, Mutate, Adjust; +const + point_size: double = 8; + constructor TCurvesControl.Create(AOwner: TComponent); begin inherited Create(AOwner); @@ -94,6 +91,7 @@ begin FrameCreate; end; + destructor TCurvesControl.Destroy; begin FCP.Destroy; @@ -101,7 +99,7 @@ begin end; procedure TCurvesControl.SetCp(cp: TControlPoint); -var i, j: integer; +var i, j: smallint; begin FCP.Copy(cp, true); for i := 0 to 3 do @@ -113,6 +111,7 @@ begin Invalidate; FFrame.Invalidate; end; + procedure TCurvesControl.UpdateFlame; begin MainForm.StopThread; @@ -130,6 +129,7 @@ procedure TCurvesControl.FrameMouseLeave(Sender: TObject); begin FrameMouseUp(nil, mbLeft, [], 0, 0); end; + procedure TCurvesControl.FrameMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ps_half: double; @@ -152,12 +152,12 @@ begin Break; end; end; + procedure TCurvesControl.FrameMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var m: BezierPoints; tmp: BezierPoint; - i: Integer; - j: Integer; + i, j: shortint; begin if (y < 0) then Exit; @@ -194,10 +194,10 @@ begin FCP.curvePoints[i,j].y := FPoints[i,j].y; end; - FFrame.Refresh; end; end; + procedure TCurvesControl.FrameMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FDragIndex := -1; @@ -207,9 +207,9 @@ begin end; procedure TCurvesControl.FrameCreate; -var i: integer; +var i: shortint; begin - for i := 0 to channel_count - 1 do + for i := 0 to MAX_CHANNEL do begin FPoints[i][0].x := 0.00; FPoints[i][0].y := 0.00; FWeights[i][0] := 1; FPoints[i][1].x := 0.00; FPoints[i][1].y := 0.00; FWeights[i][1] := 1; @@ -220,12 +220,14 @@ begin FDragIndex := -1; FDragging := false; end; + procedure TCurvesControl.FrameResize(Sender: TObject); begin FRect.x0 := 0; FRect.y0 := 0; FRect.x1 := self.Width - 1; FRect.y1 := self.Height - 1; end; + procedure TCurvesControl.FramePaint(Sender: TObject); var clientRect: TRect; @@ -261,7 +263,7 @@ begin LineTo(Round(FRect.x1), Round(0.25 * y * FRect.y1)); end; - for i := 0 to channel_count - 1 do begin + for i := 0 to MAX_CHANNEL do begin for j := 0 to 3 do wsum[i] := wsum[i] + FWeights[i][j]; for j := 0 to 3 do @@ -282,9 +284,11 @@ begin end; procedure TCurvesControl.PaintCurve(Bitmap: TBitmap; c: integer; p: BezierPoints; w: BezierWeights; widgets: boolean); +const + step = 0.001; // AV var pos0, pos1: BezierPoint; - t, step: Double; + t: Double; r, g, b: array [0 .. MAX_CHANNEL] of integer; rgbv: integer; begin @@ -303,7 +307,6 @@ begin rgbv := RGB(r[c], g[c], b[c]); t := 0; - step := 0.001; BezierSolve(0, p, w, pos1); pos0.x := 0; pos0.y := pos1.y; @@ -332,18 +335,19 @@ begin LineTo(Round(FRect.x1), Round(pos0.y)); if widgets then begin + t := point_size / 2.0; // AV Brush.Color := rgbv; Ellipse( - Round(p[1].x - point_size / 2.0), - Round(p[1].y - point_size / 2.0), - Round(p[1].x + point_size / 2.0), - Round(p[1].y + point_size / 2.0) + Round(p[1].x - t), + Round(p[1].y - t), + Round(p[1].x + t), + Round(p[1].y + t) ); Ellipse( - Round(p[2].x - point_size / 2.0), - Round(p[2].y - point_size / 2.0), - Round(p[2].x + point_size / 2.0), - Round(p[2].y + point_size / 2.0) + Round(p[2].x - t), + Round(p[2].y - t), + Round(p[2].x + t), + Round(p[2].y + t) ); end; end; @@ -355,12 +359,14 @@ begin FChannelIndex := Integer(value); FFrame.Refresh; end; + procedure TCurvesControl.SetWeightLeft(value: double); begin FWeights[FChannelIndex][1] := value; FCP.curveWeights[FChannelIndex][1] := value; FFrame.Refresh; end; + procedure TCurvesControl.SetWeightRight(value: double); begin FWeights[FChannelIndex][2] := value; @@ -372,10 +378,12 @@ function TCurvesControl.GetChannel: TCurvesChannel; begin Result := FActiveChannel; end; + function TCurvesControl.GetWeightLeft: double; begin Result := FWeights[FChannelIndex][1]; end; + function TCurvesControl.GetWeightRight: double; begin Result := FWeights[FChannelIndex][2]; diff --git a/System/CustomDrawControl.pas b/System/CustomDrawControl.pas index d2b687f..dbf5dfe 100644 --- a/System/CustomDrawControl.pas +++ b/System/CustomDrawControl.pas @@ -5,6 +5,7 @@ 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 diff --git a/System/MathExpressions.pas b/System/MathExpressions.pas new file mode 100644 index 0000000..9647446 --- /dev/null +++ b/System/MathExpressions.pas @@ -0,0 +1,337 @@ +{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } + +unit MathExpressions; + +interface + +uses + System.Rtti, System.SysUtils, System.Bindings.EvalProtocol, + System.Bindings.Evaluator, System.Bindings.EvalSys, System.Bindings.Methods; + +function CalculateExpression(const Expr: string): string; + +var + InDegrees: boolean; + +implementation + +uses + System.Math, Windows, Translation; + +var + LScope: IScope; + +function Sine: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + ANum: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['Sin()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + ANum := IAValue.GetValue.AsExtended; // AV: check the parameter type + if InDegrees then // AV: translate the parameter into radians + ANum := DegToRad(ANum); + Exit(TValueWrapper.Create(RoundTo(sin(ANum), -6))); + except + MessageBox(0, PChar('Sin(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function CoSine: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + ANum: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['Cos()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + ANum := IAValue.GetValue.AsExtended; + if InDegrees then // AV: translate the parameter into radians + ANum := DegToRad(ANum); + Exit(TValueWrapper.Create(RoundTo(cos(ANum), -6))); + except + MessageBox(0, PChar('Cos(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function ArcSine: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + AValue: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['ArcSin()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + AValue := IAValue.GetValue.AsExtended; + if InRange(AValue, -1, 1) then + begin + AValue := arcsin(AValue); + if InDegrees then + AValue := RadToDeg(AValue); + Exit(TValueWrapper.Create(RoundTo(AValue, -6))); + end + else + MessageBox(0, PChar('ArcSin(): ' + TextByKey('formula-outofrange')), + 'Apophysis AV', 48); + except + MessageBox(0, PChar('ArcSin(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function ArcCoSine: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + AValue: Double; + begin + //AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['ArcCos()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + AValue := IAValue.GetValue.AsExtended; + if InRange(AValue, -1, 1) then + begin + AValue := arccos(AValue); + if InDegrees then + AValue := RadToDeg(AValue); + Exit(TValueWrapper.Create(RoundTo(AValue, -6))); + end + else + MessageBox(0, PChar('ArcCos(): ' + TextByKey('formula-outofrange')), + 'Apophysis AV', 48); + except + MessageBox(0, PChar('ArcCos(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function ArcTangentYX: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IYValue, IXValue: IValue; + AValue: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 2 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['ArcTan2()', 2, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IYValue := Args[0]; + IXValue := Args[1]; + + try + AValue := arctan2(IYValue.GetValue.AsExtended, + IXValue.GetValue.AsExtended); + if InDegrees then + AValue := RadToDeg(AValue); + Exit(TValueWrapper.Create(RoundTo(AValue, -6))); + except + MessageBox(0, PChar('ArcTan2(): ' + TextByKey('common-invalidformat')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function SquareRoot: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + ANum: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['Sqrt()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + ANum := IAValue.GetValue.AsExtended; + if ANum >= 0 then + Exit(TValueWrapper.Create(RoundTo(sqrt(ANum), -6))) + else + MessageBox(0, PChar('Sqrt(): ' + TextByKey('formula-unsigned')), + 'Apophysis AV', 48); + except + MessageBox(0, PChar('Sqrt(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function NatLog: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IAValue: IValue; + ANum: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 1 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['Ln()', 1, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IAValue := Args[0]; + + try + ANum := IAValue.GetValue.AsExtended; + if ANum > 0 then + Exit(TValueWrapper.Create(RoundTo(ln(ANum), -6))) + else + MessageBox(0, PChar('Ln(): ' + TextByKey('formula-unsigned')), + 'Apophysis AV', 48); + except + MessageBox(0, PChar('Ln(): ' + TextByKey('formula-wrongdatatype')), + 'Apophysis AV', 16); + end; + end + ); +end; + +function PowerXY: IInvokable; +begin + Result := MakeInvokable( + function(Args: TArray): IValue + var + IYValue, IXValue: IValue; + ANum: Double; + begin + // AV: check the number of passed parameters + if Length(Args) <> 2 then begin + MessageBox(0, PChar(Format(TextByKey('formula-wrongargscount'), + ['Power()', 2, Length(Args)])), 'Apophysis AV', 48); + exit; + end; + + IXValue := Args[0]; + IYValue := Args[1]; + + try + ANum := IXValue.GetValue.AsExtended; + if ANum >= 0 then + Result := TValueWrapper.Create(RoundTo(power(ANum, + IYValue.GetValue.AsExtended), -6)) + else + MessageBox(0, PChar('Power(): ' + TextByKey('formula-unsigned')), + 'Apophysis AV', 48); + except + MessageBox(0, PChar('Power(): ' + TextByKey('common-invalidformat')), + 'Apophysis AV', 16); + end; + end + ); +end; + +procedure RegisterMathFunctions; +begin + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + Sine, 'sin', 'sin', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + CoSine, 'cos', 'cos', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + ArcSine, 'arcsin', 'arcsin', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + ArcCoSine, 'arccos', 'arccos', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + ArcTangentYX, 'arctan2', 'arctan2', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + SquareRoot, 'sqrt', 'sqrt', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + PowerXY, 'power', 'power', '', True, '', nil)); + TBindingMethodsFactory.RegisterMethod(TMethodDescription.Create( + NatLog, 'ln', 'ln', '', True, '', nil)); + + LScope := BasicOperators; + TDictionaryScope(LScope).Map.Add('pi', TValueWrapper.Create(pi)); + TDictionaryScope(LScope).Map.Add('exp', TValueWrapper.Create(exp(1))); + // AV: add the registered methods + LScope := TNestedScope.Create(LScope, TBindingMethodsFactory.GetMethodScope); +end; + +function CalculateExpression(const Expr: string): string; +var + LCompiledExpr : ICompiledBinding; + LResult : TValue; +begin + Result := ''; + + try + LCompiledExpr := Compile(Expr, LScope); + LResult := LCompiledExpr.Evaluate(LScope, nil, nil).GetValue; + if not LResult.IsEmpty then + Result := LResult.ToString; + except + Result := ''; + MessageBox(0, PChar(TextByKey('formula-cannotevaluate')), + 'Apophysis AV', 16); + end; +end; + +/////////////////////////////////////////////////////////////////////////////// +initialization + RegisterMathFunctions; + +end. diff --git a/System/RegexHelper.pas b/System/RegexHelper.pas index c3279cd..d6f2686 100644 --- a/System/RegexHelper.pas +++ b/System/RegexHelper.pas @@ -33,27 +33,31 @@ begin Regex.Subject := text; if Regex.Match and (Regex.GroupCount >= group) then - Result := String(Regex.Groups[group]) + Result := Regex.Groups[group] else Result := def; Regex.Free; end; + function GetBoolPart(text, expression: string; group: integer; def: boolean): boolean; begin Result := GetFloatPart(text, expression, group, StrToFloat(IfThen(def, '1', '0'))) <> 0; end; + function GetIntPart(text, expression: string; group: integer; def: integer): integer; var str: string; begin str := GetStringPart(text, expression, group, ''); Result := StrToIntDef(str, def); end; + function GetFloatPart(text, expression: string; group: integer; def: extended): extended; var str: string; begin str := GetStringPart(text, expression, group, ''); Result := StrToFloatDef(str, def); end; + function Get2IntPart(text, expression: string; group: integer; def: integer): T2Int; const expr : string = '(\d+)\s+(\d+)'; var str, s1, s2: string; @@ -64,6 +68,7 @@ begin Result.i1 := StrToIntDef(s1, def); Result.i2 := StrToIntDef(s2, def); end; + function Get2FloatPart(text, expression: string; group: integer; def: extended): T2Float; const expr : string = '([\d.eE+-]+)\s+([\d.eE+-]+)'; var str, s1, s2: string; @@ -74,6 +79,7 @@ begin Result.f1 := StrToFloatDef(s1, def); Result.f2 := StrToFloatDef(s2, def); end; + function GetRGBPart(text, expression: string; group: integer; def: integer): TRGB; const expr : string = '(\d+)\s+(\d+)\s+(\d+)'; var str, s1, s2, s3: string; diff --git a/System/sdStringTable.pas b/System/sdStringTable.pas deleted file mode 100644 index 1b31cca..0000000 --- a/System/sdStringTable.pas +++ /dev/null @@ -1,633 +0,0 @@ -{ unit sdStringTable - - Author: Nils Haeck M.Sc. (n.haeck@simdesign.nl) - Original Date: 28 May 2007 - Version: 1.1 - Copyright (c) 2007 - 2010 Simdesign BV - - It is NOT allowed under ANY circumstances to publish or copy this code - without accepting the license conditions in accompanying LICENSE.txt - first! - - This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF - ANY KIND, either express or implied. - - Please visit http://www.simdesign.nl/xml.html for more information. -} -unit sdStringTable; - -interface - -{$i NativeXml.inc} - -uses - Classes, SysUtils, Contnrs; - -type - - // A record describing a string by its first position and length (Count) - TsdStringRec = record - First: Pbyte; - Count: integer; - end; - - // A string reference item used in string reference lists (do not use directly) - TsdRefString = class - private - FID: integer; - FFrequency: integer; - FFirst: Pbyte; - FCharCount: integer; - protected - procedure SetString(const SR: TsdStringRec); - function CompareToSR(const SR: TsdStringRec): integer; - function StringRec: TsdStringRec; - public - destructor Destroy; override; - function AsString: UTF8String; - property CharCount: integer read FCharCount; - property Frequency: integer read FFrequency; - end; - - // A list of string reference items (do not use directly) - TsdRefStringList = class(TObjectList) - private - function GetItems(Index: integer): TsdRefString; - protected - // Assumes list is sorted by StringID - function IndexOfID(AID: integer; var Index: integer): boolean; - // Assumes list is sorted by string rec - function IndexOfSR(const AStringRec: TsdStringRec; var Index: integer): boolean; - public - property Items[Index: integer]: TsdRefString read GetItems; default; - end; - - // A string table, holding a collection of unique strings, sorted in 2 ways - // for fast access. Strings can be added with AddString or AddStringRec, - // and should be updated with SetString. When a string is added or updated, - // an ID is returned which the application can use to retrieve the string, - // using GetString. - TsdStringTable = class(TPersistent) - private - FByID: TsdRefStringList; - FBySR: TsdRefStringList; - protected - procedure DecFrequency(AItem: TsdRefString; ByIdIndex: integer); - function NextUniqueID: integer; - public - constructor Create; - destructor Destroy; override; - procedure Clear; - // Add a new string rec, return fresh ID or ID of existing item, and increase - // the existing item's ref count - function AddStringRec(const SR: TsdStringRec): integer; - // Add a new string S to the table, the function returns its ID. - function AddString(const S: UTF8String): integer; - // Get the refstring by ID - function ById(index: integer): TsdRefString; - // Delete refstring by ID - procedure Delete(ByIdIndex: integer); - // determine if the stringrec exists - function ExistStringRec(const SR: TsdStringRec): boolean; - // Get the string of refstring with ID - function GetString(ID: integer): UTF8String; - // Set the string value of refstring with ID. - procedure SetString(var ID: integer; const S: UTF8String); - // Number of refstrings - function StringCount: integer; - procedure SaveToFile(const AFileName: string); - procedure SaveToStream(S: TStream); - end; - -{utility functions} - -// convert a string into a string rec -function sdStringToSR(const S: Utf8String): TsdStringRec; - -// convert a string rec into a string -function sdSRToString(const SR: TsdStringRec): Utf8String; - -// compare two string recs. This is NOT an alphabetic compare. SRs are first -// compared by length, then by first byte, then last byte then second, then -// N-1, until all bytes are compared. -function sdCompareSR(const SR1, SR2: TsdStringRec): integer; - -// compare 2 bytes -function sdCompareByte(Byte1, Byte2: byte): integer; - -// compare 2 integers -function sdCompareInteger(Int1, Int2: integer): integer; - -function sdUtf16ToUtf8Mem(Src: Pword; Dst: Pbyte; Count: integer): integer; -function sdUtf8ToUtf16Mem(var Src: Pbyte; Dst: Pword; Count: integer): integer; -procedure sdStreamWrite(S: TStream; const AString: AnsiString); -procedure sdStreamWriteStringRec(S: TStream; const AStringRec: TsdStringRec); -procedure sdStreamWriteRefString(S: TStream; ARefString: TsdRefString); - -implementation - -{ TsdRefString } - -function TsdRefString.AsString: UTF8String; -begin - Result := sdSRToString(StringRec); -end; - -function TsdRefString.CompareToSR(const SR: TsdStringRec): integer; -begin - if SR.Count = 0 then - begin - // shortcut - Result := 1; - exit; - end; - Result := sdCompareSR(StringRec, SR); -end; - -destructor TsdRefString.Destroy; -begin - FreeMem(FFirst); - inherited; -end; - -procedure TsdRefString.SetString(const SR: TsdStringRec); -begin - FCharCount := SR.Count; - ReallocMem(FFirst, FCharCount); - Move(SR.First^, FFirst^, FCharCount); -end; - -function TsdRefString.StringRec: TsdStringRec; -begin - Result.First := FFirst; - Result.Count := FCharCount; -end; - -{ TsdRefStringList } - -function TsdRefStringList.GetItems(Index: integer): TsdRefString; -begin - Result := Get(Index); -end; - -function TsdRefStringList.IndexOfID(AID: integer; var Index: integer): boolean; -var - Min, Max: integer; -begin - Result := False; - - // Find position - binary method - Index := 0; - Min := 0; - Max := Count; - while Min < Max do - begin - Index := (Min + Max) div 2; - case sdCompareInteger(Items[Index].FID, AID) of - -1: Min := Index + 1; - 0: begin - Result := True; - exit; - end; - 1: Max := Index; - end; - end; - - Index := Min; -end; - -function TsdRefStringList.IndexOfSR(const AStringRec: TsdStringRec; var Index: integer): boolean; -var - Min, Max: integer; - SR: TsdStringRec; -begin - Result := False; - - // Find position - binary method - Index := 0; - Min := 0; - Max := Count; - while Min < Max do - begin - Index := (Min + Max) div 2; - SR := TsdRefString(Get(Index)).StringRec; - case sdCompareSR(SR, AStringRec) of - -1: Min := Index + 1; - 0: begin - Result := True; - exit; - end; - 1: Max := Index; - end; - end; - - Index := Min; -end; - -{ TsdStringTable } - -function TsdStringTable.AddString(const S: UTF8String): integer; -var - SR: TsdStringRec; -begin - SR := sdStringToSR(S); - Result := AddStringRec(SR); -end; - -function TsdStringTable.AddStringRec(const SR: TsdStringRec): integer; -var - BySRIndex: integer; - Item: TsdRefString; - NewSR: TsdStringRec; - Res: boolean; -begin - // zero-length string - if SR.Count = 0 then - begin - Result := 0; - exit; - end; - - // Try to find the new string - if FBySR.IndexOfSR(SR, BySRIndex) then - begin - Item := FBySR.Items[BySRIndex]; - inc(Item.FFrequency); - Result := Item.FID; - exit; - end; - - // Not found.. must make new item - Item := TsdRefString.Create; - Item.SetString(SR); - NewSR := Item.StringRec; - Item.FID := NextUniqueID; - FById.Add(Item); - Item.FFrequency := 1; - - // debug: - //SetLength(Item.FValue, Item.FCount); - //Move(Item.FirstPtr(FBase)^, Item.FValue[1], Item.FCount); - - // Insert in BySR lists - Res := FBySR.IndexOfSR(NewSR, BySRIndex); - assert(Res = False); - FBySR.Insert(BySRIndex, Item); - Result := Item.FID; -end; - -function TsdStringTable.ById(index: integer): TsdRefString; -begin - Result := FById[Index]; -end; - -procedure TsdStringTable.Clear; -begin - FByID.Clear; - FBySR.Clear; -end; - -constructor TsdStringTable.Create; -begin - inherited Create; - FByID := TsdRefStringList.Create(False); - FBySR := TsdRefStringList.Create(True); -end; - -procedure TsdStringTable.DecFrequency(AItem: TsdRefString; ByIdIndex: integer); -var - BySRIndex: integer; - Res: boolean; -begin - dec(AItem.FFrequency); - assert(AItem.FFrequency >= 0); - - if AItem.FFrequency = 0 then - begin - // We must remove it - FById.Delete(ByIdIndex); - Res := FBySR.IndexOfSR(AItem.StringRec, BySRIndex); - assert(Res = True); - FBySR.Delete(BySRIndex); - end; -end; - -procedure TsdStringTable.Delete(ByIdIndex: integer); -var - Item: TsdRefString; - BySRIndex: integer; - Res: boolean; -begin - Item := FById[ByIdIndex]; - if Item = nil then - exit; - FById.Delete(ByIdIndex); - Res := FBySR.IndexOfSR(Item.StringRec, BySRIndex); - assert(Res = True); - FBySR.Delete(BySRIndex); -end; - -destructor TsdStringTable.Destroy; -begin - FreeAndNil(FByID); - FreeAndNil(FBySR); - inherited; -end; - -function TsdStringTable.ExistStringRec(const SR: TsdStringRec): boolean; -var - BySRIndex: integer; -begin - // zero-length string - if SR.Count = 0 then - begin - Result := False; - exit; - end; - - // Try to find the new string - Result := FBySR.IndexOfSR(SR, BySRIndex); - -end; - -function TsdStringTable.GetString(ID: integer): UTF8String; -var - Index, Count: integer; - Item: TsdRefString; -begin - if ID = 0 then - begin - Result := ''; - exit; - end; - - // Find the ID - if FByID.IndexOfID(ID, Index) then - begin - Item := FById[Index]; - Count := Item.FCharCount; - SetLength(Result, Count); - Move(Item.FFirst^, Result[1], Count); - exit; - end; - - Result := ''; -end; - -function TsdStringTable.NextUniqueID: integer; -begin - if FById.Count = 0 then - Result := 1 - else - Result := FByID[FByID.Count - 1].FID + 1; -end; - -procedure TsdStringTable.SaveToFile(const AFileName: string); -var - F: TFileStream; -begin - F := TFileStream.Create(AFileName, fmCreate); - try - SaveToStream(F); - finally - F.Free; - end; -end; - -procedure TsdStringTable.SaveToStream(S: TStream); -var - i: integer; - R: UTF8String; -begin - for i := 0 to FBySR.Count - 1 do - begin - R := FBySR[i].AsString + #13#10; - S.Write(R[1], length(R)); - end; -end; - -procedure TsdStringTable.SetString(var ID: integer; const S: UTF8String); -var - ByIdIndex: integer; - Item: TsdRefString; - SR: TsdStringRec; -begin - // Make temp string record - SR := sdStringtoSR(S); - - // Do we have a ref string with this ID? - if (ID > 0) and FByID.IndexOfID(ID, ByIdIndex) then - begin - // Is the string still the same? - Item := FById[ByIdIndex]; - if Item.CompareToSR(SR) = 0 then - exit; - // The string changed.. - DecFrequency(Item, ByIdIndex); - end; - - ID := AddStringRec(SR); -end; - -{utility functions} - -function TsdStringTable.StringCount: integer; -begin - Result := FBySR.Count; -end; - -function sdStringToSR(const S: UTF8String): TsdStringRec; -begin - Result.Count := length(S); - if Result.Count = 0 then - Result.First := nil - else - Result.First := @S[1]; -end; - -function sdSRToString(const SR: TsdStringRec): UTF8String; -begin - SetLength(Result, SR.Count); - if SR.Count > 0 then - Move(SR.First^, Result[1], SR.Count); -end; - -function sdCompareByte(Byte1, Byte2: byte): integer; -begin - if Byte1 < Byte2 then - Result := -1 - else - if Byte1 > Byte2 then - Result := 1 - else - Result := 0; -end; - -function sdCompareInteger(Int1, Int2: integer): integer; -begin - if Int1 < Int2 then - Result := -1 - else - if Int1 > Int2 then - Result := 1 - else - Result := 0; -end; - -function sdCompareSR(const SR1, SR2: TsdStringRec): integer; -var - Count: integer; - First1, First2, Last1, Last2: Pbyte; -begin - // Compare string length first - Result := sdCompareInteger(SR1.Count, SR2.Count); - if Result <> 0 then - exit; - - // Compare first - Result := sdCompareByte(SR1.First^, SR2.First^); - if Result <> 0 then - exit; - Count := SR1.Count; - - // Setup First & Last pointers - First1 := SR1.First; - First2 := SR2.First; - Last1 := First1; inc(Last1, Count); - Last2 := First2; inc(Last2, Count); - - // Compare each time last ptrs then first ptrs, until they meet in the middle - repeat - dec(Last1); - dec(Last2); - if First1 = Last1 then - exit; - Result := sdCompareByte(Last1^, Last2^); - if Result <> 0 then - exit; - inc(First1); inc(First2); - if First1 = Last1 then - exit; - Result := sdCompareByte(First1^, First2^); - if Result <> 0 then - exit; - until False; -end; - -function sdUtf16ToUtf8Mem(Src: Pword; Dst: Pbyte; Count: integer): integer; -// Convert an Unicode (UTF16 LE) memory block to UTF8. This routine will process -// Count wide characters (2 bytes size) to Count UTF8 characters (1-3 bytes). -// Therefore, the block at Dst must be at least 1.5 the size of the source block. -// The function returns the number of *bytes* written. -var - W: word; - DStart: Pbyte; -begin - DStart := Dst; - while Count > 0 do - begin - W := Src^; - inc(Src); - if W <= $7F then - begin - Dst^ := byte(W); - inc(Dst); - end else - begin - if W > $7FF then - begin - Dst^ := byte($E0 or (W shr 12)); - inc(Dst); - Dst^ := byte($80 or ((W shr 6) and $3F)); - inc(Dst); - Dst^ := byte($80 or (W and $3F)); - inc(Dst); - end else - begin // $7F < W <= $7FF - Dst^ := byte($C0 or (W shr 6)); - inc(Dst); - Dst^ := byte($80 or (W and $3F)); - inc(Dst); - end; - end; - dec(Count); - end; - Result := integer(Dst) - integer(DStart); -end; - -function sdUtf8ToUtf16Mem(var Src: Pbyte; Dst: Pword; Count: integer): integer; -// Convert an UTF8 memory block to Unicode (UTF16 LE). This routine will process -// Count *bytes* of UTF8 (each character 1-3 bytes) into UTF16 (each char 2 bytes). -// Therefore, the block at Dst must be at least 2 times the size of Count, since -// many UTF8 characters consist of just one byte, and are mapped to 2 bytes. The -// function returns the number of *wide chars* written. Note that the Src block must -// have an exact number of UTF8 characters in it, if Count doesn't match then -// the last character will be converted anyway (going past the block boundary!) -var - W: word; - C: byte; - DStart: Pword; - SClose: Pbyte; -begin - DStart := Dst; - SClose := Src; - inc(SClose, Count); - while integer(Src) < integer(SClose) do - begin - // 1st byte - W := Src^; - inc(Src); - if W and $80 <> 0 then - begin - W := W and $3F; - if W and $20 <> 0 then - begin - // 2nd byte - C := Src^; - inc(Src); - if C and $C0 <> $80 then - // malformed trail byte or out of range char - Continue; - W := (W shl 6) or (C and $3F); - end; - // 2nd or 3rd byte - C := Src^; - inc(Src); - if C and $C0 <> $80 then - // malformed trail byte - Continue; - Dst^ := (W shl 6) or (C and $3F); - inc(Dst); - end else - begin - Dst^ := W; - inc(Dst); - end; - end; - Result := (integer(Dst) - integer(DStart)) div 2; -end; - -procedure sdStreamWrite(S: TStream; const AString: AnsiString); -var - L: integer; -begin - L := Length(AString); - if L > 0 then - begin - S.Write(AString[1], L); - end; -end; - -procedure sdStreamWriteStringRec(S: TStream; const AStringRec: TsdStringRec); -begin - S.Write(PAnsiChar(AStringRec.First)^, AStringRec.Count); -end; - -procedure sdStreamWriteRefString(S: TStream; ARefString: TsdRefString); -begin - if ARefString = nil then - exit; - S.Write(PAnsiChar(ARefString.FFirst)^, ARefString.FCharCount); -end; - -end. diff --git a/Variations/varAffine3D.pas b/Variations/varAffine3D.pas index 763a2c8..f106ffa 100644 --- a/Variations/varAffine3D.pas +++ b/Variations/varAffine3D.pas @@ -10,13 +10,13 @@ uses type TVariationAffine3D = class(TBaseVariation) private - affine3D_a00, affine3D_a01, affine3D_a02, - affine3D_a10, affine3D_a11, affine3D_a12, - affine3D_a20, affine3D_a21, affine3D_a22, - affine3D_bx, affine3D_by, affine3D_bz: double; - x0, y0, z0: double; + affine3D_a00, affine3D_a01, affine3D_a02, + affine3D_a10, affine3D_a11, affine3D_a12, + affine3D_a20, affine3D_a21, affine3D_a22, + affine3D_bx, affine3D_by, affine3D_bz: double; + x0, y0, z0: double; affine3D_mode: byte; - procedure CalcPre; + procedure CalcPre; procedure CalcPost; public constructor Create; @@ -53,13 +53,13 @@ end; procedure TVariationAffine3D.CalcPre; var x, y, z, dn: double; begin - x := affine3D_a00 * FTx^ - affine3D_a01 * FTy^ + affine3D_a02 * FTz^ + affine3D_bx; - y := -(affine3D_a10 * FTx^ - affine3D_a11 * FTy^ + affine3D_a12 * FTz^ + affine3D_by); + x := affine3D_a00 * FTx^ - affine3D_a01 * FTy^ + affine3D_a02 * FTz^ + affine3D_bx; + y := -(affine3D_a10 * FTx^ - affine3D_a11 * FTy^ + affine3D_a12 * FTz^ + affine3D_by); z := affine3D_a20 * FTx^ - affine3D_a21 * FTy^ + affine3D_a22 * FTz^ + affine3D_bz; FTx^ := VVAR * x; - FTy^ := VVAR * y; - FTz^ := VVAR * z; + FTy^ := VVAR * y; + FTz^ := VVAR * z; dn := hypot(x - x0, y - y0, z - z0); if (dn <> 0) then color^ := abs(cos(hypot(x - x0, y - y0) / dn)) @@ -70,13 +70,13 @@ procedure TVariationAffine3D.CalcFunction; var x, y, z, dn: double; begin - x := affine3D_a00 * FTx^ - affine3D_a01 * FTy^ + affine3D_a02 * FTz^ + affine3D_bx; - y := -(affine3D_a10 * FTx^ - affine3D_a11 * FTy^ + affine3D_a12 * FTz^ + affine3D_by); + x := affine3D_a00 * FTx^ - affine3D_a01 * FTy^ + affine3D_a02 * FTz^ + affine3D_bx; + y := -(affine3D_a10 * FTx^ - affine3D_a11 * FTy^ + affine3D_a12 * FTz^ + affine3D_by); z := affine3D_a20 * FTx^ - affine3D_a21 * FTy^ + affine3D_a22 * FTz^ + affine3D_bz; - FPx^ := FPx^ + VVAR * x; - FPy^ := FPy^ + VVAR * y; - FPz^ := FPz^ + VVAR * z; + FPx^ := FPx^ + VVAR * x; + FPy^ := FPy^ + VVAR * y; + FPz^ := FPz^ + VVAR * z; dn := hypot(x - x0, y - y0, z - z0); if (dn <> 0) then color^ := abs(cos(hypot(x - x0, y - y0) / dn)) @@ -87,13 +87,13 @@ procedure TVariationAffine3D.CalcPost; var x, y, z, dn: double; begin - x := affine3D_a00 * FPx^ - affine3D_a01 * FPy^ + affine3D_a02 * FPz^ + affine3D_bx; - y := -(affine3D_a10 * FPx^ - affine3D_a11 * FPy^ + affine3D_a12 * FPz^ + affine3D_by); + x := affine3D_a00 * FPx^ - affine3D_a01 * FPy^ + affine3D_a02 * FPz^ + affine3D_bx; + y := -(affine3D_a10 * FPx^ - affine3D_a11 * FPy^ + affine3D_a12 * FPz^ + affine3D_by); z := affine3D_a20 * FPx^ - affine3D_a21 * FPy^ + affine3D_a22 * FPz^ + affine3D_bz; - FPx^ := VVAR * x; - FPy^ := VVAR * y; - FPz^ := VVAR * z; + FPx^ := VVAR * x; + FPy^ := VVAR * y; + FPz^ := VVAR * z; dn := hypot(x - x0, y - y0, z - z0); if (dn <> 0) then color^ := abs(cos(hypot(x - x0, y - y0) / dn)) @@ -204,6 +204,7 @@ begin Result := True; end end; + function TVariationAffine3D.ResetVariable(const Name: string): boolean; begin Result := False; diff --git a/Variations/varCothSpiral.pas b/Variations/varCothSpiral.pas index 53154b7..59d82bc 100644 --- a/Variations/varCothSpiral.pas +++ b/Variations/varCothSpiral.pas @@ -40,7 +40,7 @@ procedure TVariationCothSpiral.CalcFunction; var t, aux, sn, cn, snh, cnh: double; begin - t := (random - 0.5) * 6.28318530717959; + t := (random - 0.5) * PI2; SinCos(ta * t, sn, cn); SinhCosh(t, snh, cnh); diff --git a/Variations/varCurl.pas b/Variations/varCurl.pas index 08321da..a6e75ff 100644 --- a/Variations/varCurl.pas +++ b/Variations/varCurl.pas @@ -35,8 +35,7 @@ const var_c1_name='curl_c1'; var_c2_name='curl_c2'; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varDisc2.pas b/Variations/varDisc2.pas index 18d47c9..e8d859b 100644 --- a/Variations/varDisc2.pas +++ b/Variations/varDisc2.pas @@ -7,15 +7,14 @@ interface uses BaseVariation, XFormMan; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} type TVariationDisc2 = class(TBaseVariation) private - rot, add, c, k, sinadd, cosadd: double; + rot, add, p, k, sinadd, cosadd: double; public constructor Create; @@ -49,7 +48,7 @@ end; procedure TVariationDisc2.Prepare; var t: double; begin - c := vvar / PI; + p := vvar / PI; k := rot * PI; SinCos(add, sinadd, cosadd); cosadd := cosadd - 1; @@ -73,7 +72,7 @@ var r, sinr, cosr: extended; begin SinCos(k * (FTx^ + FTy^), sinr, cosr); - r := c * arctan2(FTx^, FTy^); + r := p * arctan2(FTx^, FTy^); FPx^ := FPx^ + (sinr + cosadd) * r; FPy^ := FPy^ + (cosr + sinadd) * r; {$else} @@ -82,7 +81,7 @@ asm fld qword ptr [edx] fld qword ptr [edx + 8] fpatan - fmul qword ptr [eax + c] + fmul qword ptr [eax + p] fld qword ptr [edx] fadd qword ptr [edx + 8] fmul qword ptr [eax + k] diff --git a/Variations/varExponential.pas b/Variations/varExponential.pas index 1565456..ffd3b0e 100644 --- a/Variations/varExponential.pas +++ b/Variations/varExponential.pas @@ -6,8 +6,7 @@ interface uses BaseVariation, XFormMan; - {$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varGenericPlugin.pas b/Variations/varGenericPlugin.pas index ee2f2c0..7d6edcc 100644 --- a/Variations/varGenericPlugin.pas +++ b/Variations/varGenericPlugin.pas @@ -5,6 +5,7 @@ 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 @@ -40,9 +41,8 @@ interface uses BaseVariation, XFormMan, Settings, // Translation, - Classes, //TStrings/TStringList - SysUtils, //FindFirst/FindNext/FindClose - Forms; //MessageBox + Classes, //TFileStream + SysUtils; //FindFirst/FindNext/FindClose type TPluginVariationClass = class of TPluginVariation; @@ -108,10 +108,10 @@ type PluginData : TPluginData; end; -procedure InitializePlugins; +//procedure InitializePlugins; const CurrentPlatform = -{$ifdef Apo7X64} +{$ifdef CPUX64} $00000040 {$else} $00000020 @@ -122,7 +122,7 @@ const CurrentPlatform = implementation uses - Windows, //LoadLibrary + Windows, //LoadLibrary / MessageBox Global; { TPluginVariation } @@ -206,31 +206,31 @@ begin Result := ''; end; -/////////////////////////////////////////////////////////////////////////////// +{ //////////////////////////////////////////////////////////////////////////} function TPluginVariation.GetNrVariables: integer; begin Result := PluginData.PluginVarGetNrVariables; end; -/////////////////////////////////////////////////////////////////////////////// +{////////////////////////////////////////////////////////////////////////////} function TPluginVariation.GetVariableNameAt(const Index: integer): string; begin Result := String(PluginData.PluginVarGetVariableNameAt(Index)); end; -/////////////////////////////////////////////////////////////////////////////// +{////////////////////////////////////////////////////////////////////////////} function TPluginVariation.SetVariable(const Name: string; var value: double): boolean; begin Result := PluginData.PluginVarSetVariable(MyVariation,PAnsiChar(AnsiString(Name)),value); end; -/////////////////////////////////////////////////////////////////////////////// +{////////////////////////////////////////////////////////////////////////////} function TPluginVariation.GetVariable(const Name: string; var value: double): boolean; begin Result := PluginData.PluginVarGetVariable(MyVariation,PAnsiChar(AnsiString(Name)),value); end; -/////////////////////////////////////////////////////////////////////////////// +{ ////////////////////////////////////////////////////////////////////////} function TPluginVariation.ResetVariable(const Name: string) : boolean; var dummy: double; @@ -281,7 +281,7 @@ begin end; end; -/////////////////////////////////////////////////////////////////////////////// +{////////////////////////////////////////////////////////////////////////////} procedure InitializePlugins; var searchResult: TSearchRec; @@ -334,8 +334,7 @@ begin @PluginVarResetVariable := GetProcAddress(PluginHandle,'PluginVarResetVariable'); RegisterVariation(TVariationPluginLoader.Create(PluginData), @PluginVarInit3D <> nil, @PluginVarInitDC <> nil); - //RegisterVariationFile(ExtractFilePath(Application.ExeName) + 'Plugins\' + searchResult.Name, name); - RegisterVariationFile(PluginPath + searchResult.Name, name); // AV: fixed! + //RegisterVariationFile(PluginPath + searchResult.Name, name); // AV: fixed! end; end else begin errno := GetLastError; @@ -346,14 +345,20 @@ begin until (FindNext(searchResult) <> 0); SysUtils.FindClose(searchResult); //Since we use Windows unit (LoadLibrary) + // AV: now we can build the list of variation names + FillVarNamesList; + + // AV: replaced Application.MessageBox by a more faster one from Windows unit if msg <> '' then - Application.MessageBox( + MessageBox(0, PChar('There were problems with some of the plugins:' + #13#10#13#10 + msg), - 'Warning', MB_ICONWARNING or MB_OK); // TextByKey('common-loaderror1') + 'Apophysis AV Warning', MB_ICONWARNING or MB_OK); // TextByKey('common-loaderror1') end; end; -/////////////////////////////////////////////////////////////////////////////// +{ ////////////////////////////////////////////////////////////////////////// } +initialization + InitializePlugins; end. diff --git a/Variations/varHeart.pas b/Variations/varHeart.pas index 1022ee2..77f32d0 100644 --- a/Variations/varHeart.pas +++ b/Variations/varHeart.pas @@ -9,14 +9,22 @@ uses type TVariationHeart = class(TBaseVariation) private - + use3D: byte; + procedure Calc3D; public constructor Create; class function GetName: string; override; class function GetInstance: TBaseVariation; override; + function GetNrVariables: integer; override; + function GetVariableNameAt(const Index: integer): string; override; + + function SetVariable(const Name: string; var value: double): boolean; override; + function GetVariable(const Name: string; var value: double): boolean; override; + procedure CalcFunction; override; + procedure GetCalcFunction(var f: TCalcFunction); override; end; @@ -26,6 +34,12 @@ uses Math; //////////////////////// +procedure TVariationHeart.GetCalcFunction(var f: TCalcFunction); +begin + if use3D <> 0 then + f := Calc3D + else f := CalcFunction; +end; procedure TVariationHeart.CalcFunction; var @@ -39,9 +53,26 @@ begin FPy^ := FPy^ - r * cosr; end; +procedure TVariationHeart.Calc3D; +var + FAngle, r, sinr, cosr: double; +begin + FAngle := arctan2(FTx^, FTy^); + r := sqrt(sqr(FTx^) + sqr(FTy^)); + Sincos(r * FAngle, sinr, cosr); + r := r * vvar; + FPx^ := FPx^ + r * sinr; + FPy^ := FPy^ - r * cosr; + FAngle := arctan2(FTz^, FTy^); + r := sqrt(sqr(FTx^) + sqr(FTz^)); + cosr := cos(r * FAngle); + FPz^ := FPz^ - vvar * r * cosr; +end; + constructor TVariationHeart.Create; begin inherited Create; + use3D := 0; end; class function TVariationHeart.GetInstance: TBaseVariation; @@ -54,8 +85,43 @@ begin Result := 'heart'; end; +/////////////////////////////////////////////////////////////////////////////// +function TVariationHeart.GetVariableNameAt(const Index: integer): string; +begin + case Index of + 0: Result := 'heart_use3D'; + else + Result := ''; + end; +end; + +function TVariationHeart.GetNrVariables: integer; +begin + Result := 1; +end; +/////////////////////////////////////////////////////////////////////////////// +function TVariationHeart.SetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'heart_use3D' then begin + if (Value > 1) then Value := 1; + if (Value < 0) then Value := 0; + use3D := Round(Value); + Result := True; + end; +end; + +function TVariationHeart.GetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'heart_use3D' then begin + Value := use3D; + Result := True; + end; +end; + ////////////////////////////// initialization - RegisterVariation(TVariationClassLoader.Create(TVariationHeart), false, false); + RegisterVariation(TVariationClassLoader.Create(TVariationHeart), true, false); end. diff --git a/Variations/varJulia.pas b/Variations/varJulia.pas index 7a4feda..735c873 100644 --- a/Variations/varJulia.pas +++ b/Variations/varJulia.pas @@ -4,14 +4,12 @@ unit varJulia; interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} BaseVariation, XFormMan; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varJulia3Djf.pas b/Variations/varJulia3Djf.pas index 289b18e..6b666ae 100644 --- a/Variations/varJulia3Djf.pas +++ b/Variations/varJulia3Djf.pas @@ -26,8 +26,7 @@ unit varJulia3Djf; // original variation code by Joel Faber, modified & optimize interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} BaseVariation, XFormMan; @@ -36,8 +35,7 @@ const var_name = 'julia3D'; var_n_name='julia3D_power'; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varJulia3Dz.pas b/Variations/varJulia3Dz.pas index 86bb865..6038802 100644 --- a/Variations/varJulia3Dz.pas +++ b/Variations/varJulia3Dz.pas @@ -26,8 +26,7 @@ unit varJulia3Dz; interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} BaseVariation, XFormMan; @@ -36,8 +35,7 @@ const var_name = 'julia3Dz'; var_n_name='julia3Dz_power'; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varJuliaN.pas b/Variations/varJuliaN.pas index 7afa266..de00fda 100644 --- a/Variations/varJuliaN.pas +++ b/Variations/varJuliaN.pas @@ -3,8 +3,7 @@ unit varJuliaN; interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} BaseVariation, XFormMan; @@ -14,8 +13,7 @@ const var_n_name='julian_power'; var_c_name='julian_dist'; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varJuliaScope.pas b/Variations/varJuliaScope.pas index 0238c8c..5aba82c 100644 --- a/Variations/varJuliaScope.pas +++ b/Variations/varJuliaScope.pas @@ -26,8 +26,7 @@ unit varJuliaScope; interface uses -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} AsmRandom, {$endif} BaseVariation, XFormMan; @@ -37,8 +36,7 @@ const var_n_name='juliascope_power'; var_c_name='juliascope_dist'; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varNGon.pas b/Variations/varNGon.pas index 6efcebe..234e923 100644 --- a/Variations/varNGon.pas +++ b/Variations/varNGon.pas @@ -60,7 +60,7 @@ uses procedure TVariationNGon.Prepare; begin cpower := -0.5 * ngon_power; - csides := 2.0 * PI / ngon_sides; + csides := PI2 / ngon_sides; // AV: replaced 2.0 * PI by the const csidesinv := 1.0 / csides; end; @@ -68,9 +68,11 @@ procedure TVariationNGon.CalcFunction; var r_factor, theta, phi, amp: double; begin - - if (FTX^ = 0) and (FTY^ = 0) then r_factor := 0 - else r_factor := Power(FTx^ * FTx^ + FTy^ * FTy^, cpower); + // AV: this check for a single case just slow down overall calculations + // since these 2 conditions are evaluated in every point + { if (FTX^ = 0) and (FTY^ = 0) then + else } // <-- this will be true anyway + r_factor := Power(FTx^ * FTx^ + FTy^ * FTy^, cpower); theta := ArcTan2(FTy^, FTx^); @@ -78,11 +80,12 @@ begin if (phi > 0.5 * csides) then phi := phi - csides; + // AV: and yeah, if (r_factor = 0) then also (amp = 0) so we must not calc it amp := (ngon_corners * (1.0 / cos(phi) - 1.0) + ngon_circle) * VVAR * r_factor; FPx^ := FPx^ + amp * FTx^; FPy^ := FPy^ + amp * FTy^; - FPz^ := FPz^ + VVAR * FTz^; + FPz^ := FPz^ + VVAR * FTz^; // <-- AV: I don't like this since we have pre_zscale end; /////////////////////////////////////////////////////////////////////////////// diff --git a/Variations/varPDJ.pas b/Variations/varPDJ.pas index 5fe73e3..97b30ea 100644 --- a/Variations/varPDJ.pas +++ b/Variations/varPDJ.pas @@ -29,8 +29,7 @@ interface uses BaseVariation, XFormMan; -{$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varPopcorn2.pas b/Variations/varPopcorn2.pas index 346f0b5..8326997 100644 --- a/Variations/varPopcorn2.pas +++ b/Variations/varPopcorn2.pas @@ -46,11 +46,11 @@ begin else sn := 0; FPx^ := FPx^ + vvar * (FTx^ + p2x * sn); - SinCos(p2c * FTx^, sn, cn); + SinCos(p2c * FTx^, sn, cn); if cn <> 0 then // AV: safety tangent - sn := sin(sn / cn) + sn := sin(sn / cn) else - sn := 0; + sn := 0; FPy^ := FPy^ + vvar * (FTy^ + p2y * sn); end; diff --git a/Variations/varPostFalloff2.pas b/Variations/varPostFalloff2.pas index 948c31f..22a3ad5 100644 --- a/Variations/varPostFalloff2.pas +++ b/Variations/varPostFalloff2.pas @@ -87,6 +87,7 @@ begin else if blurtype = 2 then f := CalcFunctionGaussian else f := CalcFunction; end; + procedure TVariationPostFalloff2.CalcFunction; var in_x, in_y, in_z, d: double; @@ -104,6 +105,7 @@ begin FPz^ := VVAR * (in_z + mul_z * random * d); color^ := Abs(Frac(color^ + mul_c * random * d)); end; + procedure TVariationPostFalloff2.CalcFunctionRadial; var in_x, in_y, in_z, d, r_in: double; @@ -130,6 +132,7 @@ begin FPz^ := VVAR * (sins); color^ := Abs(Frac(color^ + mul_c * random * d)); end; + procedure TVariationPostFalloff2.CalcFunctionGaussian; var in_x, in_y, in_z, d: double; diff --git a/Variations/varPostMobius.pas b/Variations/varPostMobius.pas new file mode 100644 index 0000000..28c91f9 --- /dev/null +++ b/Variations/varPostMobius.pas @@ -0,0 +1,254 @@ +{ + 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 varPostMobius; + +interface + +uses + BaseVariation, XFormMan; + +type + TVariationPostMobius = class(TBaseVariation) + private + Re_A, Im_A, Re_B, Im_B, Re_C, Im_C, Re_D, Im_D: double; + mobius_invert : byte; + procedure CalcInvert; + public + constructor Create; + + class function GetName: string; override; + class function GetInstance: TBaseVariation; override; + + function GetNrVariables: integer; override; + function GetVariableNameAt(const Index: integer): string; override; + + function SetVariable(const Name: string; var value: double): boolean; override; + function GetVariable(const Name: string; var value: double): boolean; override; + function ResetVariable(const Name: string): boolean; override; + + procedure CalcFunction; override; + procedure GetCalcFunction(var f: TCalcFunction); override; + end; + +implementation + +uses + Math; + +/////////////////////////////////////////////////////////////////////////////// +procedure TVariationPostMobius.GetCalcFunction(var f: TCalcFunction); +begin // AV: this helps to increase the calc speed + if (mobius_invert <> 0) then + f := CalcInvert + else f := CalcFunction; +end; + +procedure TVariationPostMobius.CalcFunction; +const EPS = 1E-100; +var + uRe, uIm, vRe, vIm, vDenom : double; +begin + uRe := (Re_A) * FPX^ - (Im_A) * FPY^ + (Re_B); + uIm := (Re_A) * FPY^ + (Im_A) * FPX^ + (Im_B); + vRe := (Re_C) * FPX^ - (Im_C) * FPY^ + (Re_D); + vIm := (Re_C) * FPY^ + (Im_C) * FPX^ + (Im_D); + + vDenom := vRe * vRe + vIm * vIm; + if abs(vDenom) < EPS then vDenom := EPS; + + FPx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; + FPy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; +end; + +procedure TVariationPostMobius.CalcInvert; // inverse Mobius transformation +const EPS = 1E-100; +var + uRe, uIm, vRe, vIm, vDenom : double; +begin + uRe := (Re_D) * FPX^ - (Im_D) * FPY^ - (Re_B); + uIm := (Re_D) * FPY^ + (Im_D) * FPX^ - (Im_B); + vRe := -(Re_C) * FPX^ + (Im_C) * FPY^ + (Re_A); + vIm := -(Re_C) * FPY^ - (Im_C) * FPX^ + (Im_A); + + vDenom := vRe * vRe + vIm * vIm; + if abs(vDenom) < EPS then vDenom := EPS; + + FPx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; + FPy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; +end; + + +/////////////////////////////////////////////////////////////////////////////// +constructor TVariationPostMobius.Create; +begin + Re_A := 1; Im_A := 0; + Re_B := 0; Im_B := 0; + Re_C := 0; Im_C := 0; + Re_D := 1; Im_D := 0; + mobius_invert := 0; +end; + +/////////////////////////////////////////////////////////////////////////////// +class function TVariationPostMobius.GetInstance: TBaseVariation; +begin + Result := TVariationPostMobius.Create; +end; + +/////////////////////////////////////////////////////////////////////////////// +class function TVariationPostMobius.GetName: string; +begin + Result := 'post_mobius'; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPostMobius.GetVariableNameAt(const Index: integer): string; +begin + case Index of + 0: Result := 'post_mobius_Re_A'; + 1: Result := 'post_mobius_Im_A'; + 2: Result := 'post_mobius_Re_B'; + 3: Result := 'post_mobius_Im_B'; + 4: Result := 'post_mobius_Re_C'; + 5: Result := 'post_mobius_Im_C'; + 6: Result := 'post_mobius_Re_D'; + 7: Result := 'post_mobius_Im_D'; + 8: Result := 'post_mobius_invert'; + else + Result := ''; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPostMobius.SetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'post_mobius_Re_A' then begin + Re_A := Value; + Result := True; + end else if Name = 'post_mobius_Im_A' then begin + Im_A := Value; + Result := True; + end else if Name = 'post_mobius_Re_B' then begin + Re_B := Value; + Result := True; + end else if Name = 'post_mobius_Im_B' then begin + Im_B := Value; + Result := True; + end else if Name = 'post_mobius_Re_C' then begin + Re_C := Value; + Result := True; + end else if Name = 'post_mobius_Im_C' then begin + Im_C := Value; + Result := True; + end else if Name = 'post_mobius_Re_D' then begin + Re_D := Value; + Result := True; + end else if Name = 'post_mobius_Im_D' then begin + Im_D := Value; + Result := True; + end else if Name = 'post_mobius_invert' then begin + if (Value > 1) then Value := 1; + if (Value < 0) then Value := 0; + mobius_invert := Round(Value); + Result := True; + end +end; +function TVariationPostMobius.ResetVariable(const Name: string): boolean; +begin + Result := False; + if Name = 'post_mobius_Re_A' then begin + Re_A := 1; + Result := True; + end else if Name = 'post_mobius_Im_A' then begin + Im_A := 0; + Result := True; + end else if Name = 'post_mobius_Re_B' then begin + Re_B := 0; + Result := True; + end else if Name = 'post_mobius_Im_B' then begin + Im_B := 0; + Result := True; + end else if Name = 'post_mobius_Re_C' then begin + Re_C := 0; + Result := True; + end else if Name = 'post_mobius_Im_C' then begin + Im_C := 0; + Result := True; + end else if Name = 'post_mobius_Re_D' then begin + Re_D := 1; + Result := True; + end else if Name = 'post_mobius_Im_D' then begin + Im_D := 0; + Result := True; + end else if Name = 'post_mobius_invert' then begin + mobius_invert := 0; + Result := True; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPostMobius.GetNrVariables: integer; +begin + Result := 9 +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPostMobius.GetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'post_mobius_Re_A' then begin + Value := Re_A; + Result := True; + end else if Name = 'post_mobius_Im_A' then begin + Value := Im_A; + Result := True; + end else if Name = 'post_mobius_Re_B' then begin + Value := Re_B; + Result := True; + end else if Name = 'post_mobius_Im_B' then begin + Value := Im_B; + Result := True; + end else if Name = 'post_mobius_Re_C' then begin + Value := Re_C; + Result := True; + end else if Name = 'post_mobius_Im_C' then begin + Value := Im_C; + Result := True; + end else if Name = 'post_mobius_Re_D' then begin + Value := Re_D; + Result := True; + end else if Name = 'post_mobius_Im_D' then begin + Value := Im_D; + Result := True; + end else if Name = 'post_mobius_invert' then begin + Value := mobius_invert; + Result := True; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +initialization + RegisterVariation(TVariationClassLoader.Create(TVariationPostMobius), false, false); +end. \ No newline at end of file diff --git a/Variations/varPostSinusoidal.pas b/Variations/varPostSinusoidal.pas index bd3bcce..695229a 100644 --- a/Variations/varPostSinusoidal.pas +++ b/Variations/varPostSinusoidal.pas @@ -7,8 +7,7 @@ interface uses BaseVariation, XFormMan; - {$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varPower.pas b/Variations/varPower.pas index dc2aa40..14a0d90 100644 --- a/Variations/varPower.pas +++ b/Variations/varPower.pas @@ -1,4 +1,4 @@ -{ Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina } +{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina } unit varPower; @@ -9,14 +9,22 @@ uses type TVariationPower = class(TBaseVariation) private - + use3D: byte; + procedure Calc3D; public constructor Create; class function GetName: string; override; class function GetInstance: TBaseVariation; override; + function GetNrVariables: integer; override; + function GetVariableNameAt(const Index: integer): string; override; + + function SetVariable(const Name: string; var value: double): boolean; override; + function GetVariable(const Name: string; var value: double): boolean; override; + procedure CalcFunction; override; + procedure GetCalcFunction(var f: TCalcFunction); override; end; @@ -27,14 +35,35 @@ uses //////////////////////// +procedure TVariationPower.GetCalcFunction(var f: TCalcFunction); +begin + if use3D <> 0 then f := Calc3D // AV: added optional 3d-support + else f := CalcFunction; +end; + +procedure TVariationPower.Calc3D; // AV +var + r, FSinA, FCosA: double; +begin + r := sqrt(sqr(FTx^) + sqr(FTy^) + sqr(FTz^)) + 1E-300; + FSinA := FTx^ / r; + FCosA := FTy^ / r; + r := vvar * Math.Power(r, FSinA); + FPx^ := FPx^ + r * FCosA; + FPy^ := FPy^ + r * FSinA; + // transform the plane into 3d-shape + r := vvar * Math.Power(r, FCosA); + FPz^ := FPz^ + r * FCosA; //FSinA; +end; + procedure TVariationPower.CalcFunction; var - r, FLength, FSinA, FCosA: double; + r, FSinA, FCosA: double; begin - FLength := sqrt(sqr(FTx^) + sqr(FTy^)) + 1E-300; - FSinA := FTx^ / FLength; - FCosA := FTy^ / FLength; - r := vvar * Math.Power(FLength, FSinA); + r := sqrt(sqr(FTx^) + sqr(FTy^)) + 1E-300; + FSinA := FTx^ / r; + FCosA := FTy^ / r; + r := vvar * Math.Power(r, FSinA); FPx^ := FPx^ + r * FCosA; FPy^ := FPy^ + r * FSinA; end; @@ -42,6 +71,7 @@ end; constructor TVariationPower.Create; begin inherited Create; + use3D := 0; end; class function TVariationPower.GetInstance: TBaseVariation; @@ -54,8 +84,44 @@ begin Result := 'power'; end; +function TVariationPower.GetNrVariables: integer; +begin + Result := 1; +end; + +function TVariationPower.GetVariableNameAt(const Index: integer): string; +begin + case Index of + 0: Result := 'power_use3D'; + else + Result := ''; + end; +end; + +function TVariationPower.GetVariable(const Name: string; + var value: double): boolean; +begin + Result := False; + if Name = 'power_use3D' then begin + Value := use3D; + Result := True; + end; +end; + +function TVariationPower.SetVariable(const Name: string; + var value: double): boolean; +begin + Result := False; + if Name = 'power_use3D' then begin + if (Value > 1) then Value := 1; + if (Value < 0) then Value := 0; + use3D := Round(Value); + Result := True; + end; +end; + ////////////////////////////// initialization - RegisterVariation(TVariationClassLoader.Create(TVariationPower), false, false); + RegisterVariation(TVariationClassLoader.Create(TVariationPower), true, false); end. diff --git a/Variations/varPreMobius.pas b/Variations/varPreMobius.pas new file mode 100644 index 0000000..f63c144 --- /dev/null +++ b/Variations/varPreMobius.pas @@ -0,0 +1,254 @@ +{ + 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 varPreMobius; + +interface + +uses + BaseVariation, XFormMan; + +type + TVariationPreMobius = class(TBaseVariation) + private + Re_A, Im_A, Re_B, Im_B, Re_C, Im_C, Re_D, Im_D: double; + mobius_invert : byte; + procedure CalcInvert; + public + constructor Create; + + class function GetName: string; override; + class function GetInstance: TBaseVariation; override; + + function GetNrVariables: integer; override; + function GetVariableNameAt(const Index: integer): string; override; + + function SetVariable(const Name: string; var value: double): boolean; override; + function GetVariable(const Name: string; var value: double): boolean; override; + function ResetVariable(const Name: string): boolean; override; + + procedure CalcFunction; override; + procedure GetCalcFunction(var f: TCalcFunction); override; + end; + +implementation + +uses + Math; + +/////////////////////////////////////////////////////////////////////////////// +procedure TVariationPreMobius.GetCalcFunction(var f: TCalcFunction); +begin // AV: this helps to increase the calc speed + if (mobius_invert <> 0) then + f := CalcInvert + else f := CalcFunction; +end; + +procedure TVariationPreMobius.CalcFunction; +const EPS = 1E-100; +var + uRe, uIm, vRe, vIm, vDenom : double; +begin + uRe := (Re_A) * FTx^ - (Im_A) * FTy^ + (Re_B); + uIm := (Re_A) * FTy^ + (Im_A) * FTx^ + (Im_B); + vRe := (Re_C) * FTx^ - (Im_C) * FTy^ + (Re_D); + vIm := (Re_C) * FTy^ + (Im_C) * FTx^ + (Im_D); + + vDenom := vRe * vRe + vIm * vIm; + if abs(vDenom) < EPS then vDenom := EPS; + + FTx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; + FTy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; +end; + +procedure TVariationPreMobius.CalcInvert; // inverse Mobius transformation +const EPS = 1E-100; +var + uRe, uIm, vRe, vIm, vDenom : double; +begin + uRe := (Re_D) * FTX^ - (Im_D) * FTY^ - (Re_B); + uIm := (Re_D) * FTY^ + (Im_D) * FTx^ - (Im_B); + vRe := -(Re_C) * FTx^ + (Im_C) * FTy^ + (Re_A); + vIm := -(Re_C) * FTy^ - (Im_C) * FTx^ + (Im_A); + + vDenom := vRe * vRe + vIm * vIm; + if abs(vDenom) < EPS then vDenom := EPS; + + FTx^ := VVAR * (uRe*vRe + uIm*vIm) / vDenom; + FTy^ := VVAR * (uIm*vRe - uRe*vIm) / vDenom; +end; + + +/////////////////////////////////////////////////////////////////////////////// +constructor TVariationPreMobius.Create; +begin + Re_A := 1; Im_A := 0; + Re_B := 0; Im_B := 0; + Re_C := 0; Im_C := 0; + Re_D := 1; Im_D := 0; + mobius_invert := 0; +end; + +/////////////////////////////////////////////////////////////////////////////// +class function TVariationPreMobius.GetInstance: TBaseVariation; +begin + Result := TVariationPreMobius.Create; +end; + +/////////////////////////////////////////////////////////////////////////////// +class function TVariationPreMobius.GetName: string; +begin + Result := 'pre_mobius'; +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPreMobius.GetVariableNameAt(const Index: integer): string; +begin + case Index of + 0: Result := 'pre_mobius_Re_A'; + 1: Result := 'pre_mobius_Im_A'; + 2: Result := 'pre_mobius_Re_B'; + 3: Result := 'pre_mobius_Im_B'; + 4: Result := 'pre_mobius_Re_C'; + 5: Result := 'pre_mobius_Im_C'; + 6: Result := 'pre_mobius_Re_D'; + 7: Result := 'pre_mobius_Im_D'; + 8: Result := 'pre_mobius_invert'; + else + Result := ''; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPreMobius.SetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'pre_mobius_Re_A' then begin + Re_A := Value; + Result := True; + end else if Name = 'pre_mobius_Im_A' then begin + Im_A := Value; + Result := True; + end else if Name = 'pre_mobius_Re_B' then begin + Re_B := Value; + Result := True; + end else if Name = 'pre_mobius_Im_B' then begin + Im_B := Value; + Result := True; + end else if Name = 'pre_mobius_Re_C' then begin + Re_C := Value; + Result := True; + end else if Name = 'pre_mobius_Im_C' then begin + Im_C := Value; + Result := True; + end else if Name = 'pre_mobius_Re_D' then begin + Re_D := Value; + Result := True; + end else if Name = 'pre_mobius_Im_D' then begin + Im_D := Value; + Result := True; + end else if Name = 'pre_mobius_invert' then begin + if (Value > 1) then Value := 1; + if (Value < 0) then Value := 0; + mobius_invert := Round(Value); + Result := True; + end +end; +function TVariationPreMobius.ResetVariable(const Name: string): boolean; +begin + Result := False; + if Name = 'pre_mobius_Re_A' then begin + Re_A := 1; + Result := True; + end else if Name = 'pre_mobius_Im_A' then begin + Im_A := 0; + Result := True; + end else if Name = 'pre_mobius_Re_B' then begin + Re_B := 0; + Result := True; + end else if Name = 'pre_mobius_Im_B' then begin + Im_B := 0; + Result := True; + end else if Name = 'pre_mobius_Re_C' then begin + Re_C := 0; + Result := True; + end else if Name = 'pre_mobius_Im_C' then begin + Im_C := 0; + Result := True; + end else if Name = 'pre_mobius_Re_D' then begin + Re_D := 1; + Result := True; + end else if Name = 'pre_mobius_Im_D' then begin + Im_D := 0; + Result := True; + end else if Name = 'pre_mobius_invert' then begin + mobius_invert := 0; + Result := True; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPreMobius.GetNrVariables: integer; +begin + Result := 9 +end; + +/////////////////////////////////////////////////////////////////////////////// +function TVariationPreMobius.GetVariable(const Name: string; var value: double): boolean; +begin + Result := False; + if Name = 'pre_mobius_Re_A' then begin + Value := Re_A; + Result := True; + end else if Name = 'pre_mobius_Im_A' then begin + Value := Im_A; + Result := True; + end else if Name = 'pre_mobius_Re_B' then begin + Value := Re_B; + Result := True; + end else if Name = 'pre_mobius_Im_B' then begin + Value := Im_B; + Result := True; + end else if Name = 'pre_mobius_Re_C' then begin + Value := Re_C; + Result := True; + end else if Name = 'pre_mobius_Im_C' then begin + Value := Im_C; + Result := True; + end else if Name = 'pre_mobius_Re_D' then begin + Value := Re_D; + Result := True; + end else if Name = 'pre_mobius_Im_D' then begin + Value := Im_D; + Result := True; + end else if Name = 'pre_mobius_invert' then begin + Value := mobius_invert; + Result := True; + end +end; + +/////////////////////////////////////////////////////////////////////////////// +initialization + RegisterVariation(TVariationClassLoader.Create(TVariationPreMobius), false, false); +end. \ No newline at end of file diff --git a/Variations/varPreSinusoidal.pas b/Variations/varPreSinusoidal.pas index 03d7bc6..ce94f58 100644 --- a/Variations/varPreSinusoidal.pas +++ b/Variations/varPreSinusoidal.pas @@ -29,8 +29,7 @@ interface uses BaseVariation, XFormMan; - {$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varSinusoidal.pas b/Variations/varSinusoidal.pas index fdbcb1a..4e96db2 100644 --- a/Variations/varSinusoidal.pas +++ b/Variations/varSinusoidal.pas @@ -28,8 +28,7 @@ interface uses BaseVariation, XFormMan; - {$ifdef Apo7X64} -{$else} +{$ifdef CPUX86} {$define _ASM_} {$endif} diff --git a/Variations/varTanhSpiral.pas b/Variations/varTanhSpiral.pas index c7be793..3c0639e 100644 --- a/Variations/varTanhSpiral.pas +++ b/Variations/varTanhSpiral.pas @@ -40,7 +40,7 @@ procedure TVariationTanhSpiral.CalcFunction; var t, aux, sn, cn, snh, cnh: double; begin - t := (random - 0.5) * 6.28318530717959; + t := (random - 0.5) * PI2; SinCos(ta * t, sn, cn); SinhCosh(t, snh, cnh);