2022-03-08 12:25:51 -05:00
|
|
|
|
{
|
|
|
|
|
Apophysis Copyright (C) 2001-2004 Mark Townsend
|
|
|
|
|
Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov
|
|
|
|
|
Apophysis Copyright (C) 2007-2008 Piotr Borys, Peter Sdobnov
|
|
|
|
|
|
|
|
|
|
Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov
|
|
|
|
|
Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//{$D-,L-,O+,Q-,R-,Y-,S-}
|
|
|
|
|
|
|
|
|
|
unit Main;
|
|
|
|
|
|
|
|
|
|
//{$define VAR_STR}
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
uses
|
|
|
|
|
Windows, Forms, Dialogs, Menus, Controls, ComCtrls,
|
2022-06-23 06:22:32 -04:00
|
|
|
|
StdCtrls, Classes, Messages, ExtCtrls, ImgList, System.ImageList,
|
|
|
|
|
Vcl.Imaging.Jpeg, SyncObjs, SysUtils, Graphics, Math, Vcl.ToolWin,
|
|
|
|
|
ExtDlgs, AppEvnts, ShellAPI, Registry,
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Global, Xform, XFormMan, ControlPoint, CMap,
|
|
|
|
|
RenderThread, RenderingCommon, RenderingInterface,
|
2022-06-23 06:22:32 -04:00
|
|
|
|
LibXmlParser, LibXmlComps, Vcl.Imaging.PngImage,
|
|
|
|
|
StrUtils, LoadTracker, CommandLine, Translation,
|
|
|
|
|
RegularExpressionsCore, RegexHelper, Vcl.Themes, Vcl.Styles; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
const
|
2022-06-23 06:22:32 -04:00
|
|
|
|
mbHeight = 30; // AV: height (in items) of all styled submenus
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{$ifdef CPUX86}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
randFilename = 'ApophysisAV.rand';
|
|
|
|
|
undoFilename = 'ApophysisAV.undo';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ApophysisSVN = 'Apophysis AV (32 bit)'; // AV: the caption for all dialogs
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{$else}
|
|
|
|
|
randFilename = 'ApophysisAV_64.rand'; // AV
|
|
|
|
|
undoFilename = 'ApophysisAV_64.undo'; // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ApophysisSVN = 'Apophysis AV (64 bit)';
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{$endif}
|
|
|
|
|
templateFilename = 'ApophysisAV.temp';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//templatePath = '\templates';
|
|
|
|
|
// AV: hmm, we have a global variable with the same name...
|
|
|
|
|
// scriptPath = '\scripts';
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
TMouseMoveState = (msUsual, msZoomWindow, msZoomOutWindow, msZoomWindowMove,
|
2022-06-23 06:22:32 -04:00
|
|
|
|
msZoomOutWindowMove, msDrag, msDragMove, msRotate,
|
|
|
|
|
msRotateMove, msPitchYaw, msHeight);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
TThumbnailThread = class(TThread)
|
|
|
|
|
private
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FlameItems: TListItems;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
class var
|
|
|
|
|
FPreviewDensity: double; // AV
|
|
|
|
|
FThumbnailSize : integer; // AV: added F to avoid of name conflicts
|
|
|
|
|
public
|
|
|
|
|
constructor Create;
|
|
|
|
|
procedure Execute; override;
|
|
|
|
|
destructor Destroy; override;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
TMainForm = class(TForm)
|
|
|
|
|
Buttons: TImageList;
|
|
|
|
|
MainMenu: TMainMenu;
|
|
|
|
|
MainFile: TMenuItem;
|
|
|
|
|
mnuSaveUPR: TMenuItem;
|
|
|
|
|
N1: TMenuItem;
|
|
|
|
|
mnuRandomBatch: TMenuItem;
|
|
|
|
|
FileExitSep: TMenuItem;
|
|
|
|
|
mnuExit: TMenuItem;
|
|
|
|
|
MainEdit: TMenuItem;
|
|
|
|
|
mnuCopyUPR: TMenuItem;
|
|
|
|
|
mnuEditor: TMenuItem;
|
|
|
|
|
mnuRandom: TMenuItem;
|
|
|
|
|
mnuNormalWeights: TMenuItem;
|
|
|
|
|
mnuEqualize: TMenuItem;
|
|
|
|
|
mnuRWeights: TMenuItem;
|
|
|
|
|
mnuOptions: TMenuItem;
|
|
|
|
|
MainHelp: TMenuItem;
|
|
|
|
|
mnuHelpTopics: TMenuItem;
|
|
|
|
|
OpenDialog: TOpenDialog;
|
|
|
|
|
ListPopUp: TPopupMenu;
|
|
|
|
|
mnuItemDelete: TMenuItem;
|
|
|
|
|
mnuListRename: TMenuItem;
|
|
|
|
|
DisplayPopup: TPopupMenu;
|
|
|
|
|
mnuPopFullscreen: TMenuItem;
|
|
|
|
|
RedrawTimer: TTimer;
|
|
|
|
|
mnuVar: TMenuItem;
|
|
|
|
|
mnuVRandom: TMenuItem;
|
|
|
|
|
N3: TMenuItem;
|
|
|
|
|
mnuOpen: TMenuItem;
|
|
|
|
|
mnuSaveAs: TMenuItem;
|
|
|
|
|
N8: TMenuItem;
|
|
|
|
|
mnuGrad: TMenuItem;
|
|
|
|
|
mnuSmoothGradient: TMenuItem;
|
|
|
|
|
mnuView: TMenuItem;
|
|
|
|
|
mnuToolbar: TMenuItem;
|
|
|
|
|
mnuStatusBar: TMenuItem;
|
|
|
|
|
BackPanel: TPanel;
|
|
|
|
|
mnuFileContents: TMenuItem;
|
|
|
|
|
mnuUndo: TMenuItem;
|
|
|
|
|
mnuRedo: TMenuItem;
|
|
|
|
|
N5: TMenuItem;
|
|
|
|
|
SaveDialog: TSaveDialog;
|
|
|
|
|
MainFlame: TMenuItem;
|
|
|
|
|
N11: TMenuItem;
|
|
|
|
|
mnuAbout: TMenuItem;
|
|
|
|
|
mnuFullScreen: TMenuItem;
|
|
|
|
|
mnuRender: TMenuItem;
|
|
|
|
|
mnuMutate: TMenuItem;
|
|
|
|
|
mnuAdjust: TMenuItem;
|
|
|
|
|
mnuOpenGradient: TMenuItem;
|
|
|
|
|
mnuResetLocation: TMenuItem;
|
|
|
|
|
N4: TMenuItem;
|
|
|
|
|
N14: TMenuItem;
|
|
|
|
|
mnuSaveUndo: TMenuItem;
|
|
|
|
|
N2: TMenuItem;
|
|
|
|
|
mnuPopResetLocation: TMenuItem;
|
|
|
|
|
N6: TMenuItem;
|
|
|
|
|
mnuPopUndo: TMenuItem;
|
|
|
|
|
N16: TMenuItem;
|
|
|
|
|
mnuPopRedo: TMenuItem;
|
|
|
|
|
mnuCalculateColors: TMenuItem;
|
|
|
|
|
mnuRandomizeColorValues: TMenuItem;
|
|
|
|
|
N18: TMenuItem;
|
|
|
|
|
N19: TMenuItem;
|
|
|
|
|
mnuScript: TMenuItem;
|
|
|
|
|
mnuRun: TMenuItem;
|
|
|
|
|
mnuEditScript: TMenuItem;
|
|
|
|
|
N15: TMenuItem;
|
|
|
|
|
mnuStop: TMenuItem;
|
|
|
|
|
mnuOpenScript: TMenuItem;
|
|
|
|
|
mnuImportGimp: TMenuItem;
|
|
|
|
|
N9: TMenuItem;
|
|
|
|
|
N10: TMenuItem;
|
|
|
|
|
mnuManageFavorites: TMenuItem;
|
|
|
|
|
mnuImageSize: TMenuItem;
|
|
|
|
|
N13: TMenuItem;
|
|
|
|
|
ApplicationEvents: TApplicationEvents;
|
|
|
|
|
mnuPaste: TMenuItem;
|
|
|
|
|
mnuCopy: TMenuItem;
|
|
|
|
|
N20: TMenuItem;
|
|
|
|
|
mnuExportFLame: TMenuItem;
|
|
|
|
|
mnuFlamepdf: TMenuItem;
|
|
|
|
|
mnuSaveAllAs: TMenuItem;
|
|
|
|
|
View1: TMenuItem;
|
|
|
|
|
mnuRenderAll: TMenuItem;
|
|
|
|
|
mnuBuiltinVars: TMenuItem;
|
|
|
|
|
mnuPluginVars: TMenuItem;
|
|
|
|
|
UsedThumbnails: TImageList;
|
|
|
|
|
Splitter: TSplitter;
|
|
|
|
|
ListBackPanel: TPanel;
|
|
|
|
|
ListView1: TListView;
|
|
|
|
|
cbMain: TCoolBar;
|
|
|
|
|
ToolBar: TToolBar;
|
|
|
|
|
btNew: TToolButton;
|
|
|
|
|
btnOpen: TToolButton;
|
|
|
|
|
btnSave: TToolButton;
|
|
|
|
|
ToolButton10: TToolButton;
|
|
|
|
|
btnRender: TToolButton;
|
|
|
|
|
tbRenderAll: TToolButton;
|
|
|
|
|
ToolButton9: TToolButton;
|
|
|
|
|
btnViewList: TToolButton;
|
|
|
|
|
btnViewIcons: TToolButton;
|
|
|
|
|
ToolButton2: TToolButton;
|
|
|
|
|
btnUndo: TToolButton;
|
|
|
|
|
btnRedo: TToolButton;
|
|
|
|
|
ToolButton1: TToolButton;
|
|
|
|
|
btnReset: TToolButton;
|
|
|
|
|
btnFullScreen: TToolButton;
|
|
|
|
|
ToolButton3: TToolButton;
|
|
|
|
|
tbQualityBox: TComboBoxEx;
|
|
|
|
|
New1: TMenuItem;
|
|
|
|
|
ColorDialog: TColorDialog;
|
|
|
|
|
mnuResetUI: TMenuItem;
|
|
|
|
|
ToolButton4: TToolButton;
|
|
|
|
|
tbEditor: TToolButton;
|
|
|
|
|
tbAdjust: TToolButton;
|
|
|
|
|
tbPalette: TToolButton;
|
|
|
|
|
tbMutate: TToolButton;
|
|
|
|
|
tbImageSize: TToolButton;
|
|
|
|
|
tbMessages: TToolButton;
|
|
|
|
|
tbOptions: TToolButton;
|
|
|
|
|
ToolButton15: TToolButton;
|
|
|
|
|
tbShowAlpha: TToolButton;
|
|
|
|
|
ToolButton16: TToolButton;
|
|
|
|
|
tbEditScript: TToolButton;
|
|
|
|
|
btnRunScript: TToolButton;
|
|
|
|
|
btnStopScript: TToolButton;
|
|
|
|
|
ToolButton18: TToolButton;
|
|
|
|
|
tbDrag: TToolButton;
|
|
|
|
|
tbRotate: TToolButton;
|
|
|
|
|
tbZoomIn: TToolButton;
|
|
|
|
|
tbZoomOut: TToolButton;
|
|
|
|
|
AutoSaveTimer: TTimer;
|
|
|
|
|
Restorelastautosave1: TMenuItem;
|
|
|
|
|
tbGuides: TToolButton;
|
|
|
|
|
mnuTurnFlameToScript: TMenuItem;
|
|
|
|
|
N12: TMenuItem;
|
|
|
|
|
mnuReportFlame: TMenuItem;
|
|
|
|
|
mnuMessages: TMenuItem;
|
|
|
|
|
BottomDock: TPanel;
|
|
|
|
|
StatusBar: TStatusBar;
|
|
|
|
|
Image: TImage;
|
|
|
|
|
pnlLSPFrame: TPanel;
|
|
|
|
|
LoadSaveProgress: TProgressBar;
|
|
|
|
|
mnuExportChaotica: TMenuItem;
|
|
|
|
|
mnuResumeRender: TMenuItem;
|
|
|
|
|
mnuManual: TMenuItem;
|
|
|
|
|
tbCurves: TToolButton;
|
|
|
|
|
mnuCurves: TMenuItem;
|
|
|
|
|
N17: TMenuItem;
|
|
|
|
|
mnuTrace: TMenuItem;
|
|
|
|
|
CalculateWeights: TMenuItem;
|
|
|
|
|
FavouriteScripts1: TMenuItem;
|
|
|
|
|
Directory1: TMenuItem;
|
|
|
|
|
Randomizecolorspeed1: TMenuItem;
|
|
|
|
|
Calculatecolorspeed1: TMenuItem;
|
|
|
|
|
Changecolordistribution1: TMenuItem;
|
|
|
|
|
Changeweightdistribution1: TMenuItem;
|
|
|
|
|
ResetColorSpeed: TMenuItem;
|
|
|
|
|
mnuApoStyle: TMenuItem; // AV
|
|
|
|
|
N7: TMenuItem;
|
|
|
|
|
N22: TMenuItem;
|
|
|
|
|
AddSymmetry: TMenuItem;
|
|
|
|
|
BilateralSym: TMenuItem;
|
|
|
|
|
RotationalSym: TMenuItem;
|
|
|
|
|
DihedralSym: TMenuItem;
|
|
|
|
|
rot2: TMenuItem;
|
|
|
|
|
rot3: TMenuItem;
|
|
|
|
|
rot4: TMenuItem;
|
|
|
|
|
rot5: TMenuItem;
|
|
|
|
|
rot6: TMenuItem;
|
|
|
|
|
rot8: TMenuItem;
|
|
|
|
|
dih2: TMenuItem;
|
|
|
|
|
dih3: TMenuItem;
|
|
|
|
|
dih4: TMenuItem;
|
|
|
|
|
dih5: TMenuItem;
|
|
|
|
|
dih6: TMenuItem;
|
|
|
|
|
dih8: TMenuItem;
|
|
|
|
|
AddTile: TMenuItem; // AV
|
|
|
|
|
Square1: TMenuItem;
|
|
|
|
|
Rhombic1: TMenuItem;
|
|
|
|
|
Hexagonal1: TMenuItem;
|
|
|
|
|
ImportFromPNG: TMenuItem;
|
|
|
|
|
ToolButton23: TToolButton;
|
|
|
|
|
mnuScreenShot: TMenuItem;
|
|
|
|
|
N23: TMenuItem;
|
|
|
|
|
rot7: TMenuItem;
|
|
|
|
|
dih7: TMenuItem;
|
|
|
|
|
AddTemplate: TMenuItem;
|
|
|
|
|
N21: TMenuItem;
|
|
|
|
|
ResetColorValues: TMenuItem;
|
|
|
|
|
mnuExportBitmap: TMenuItem;
|
|
|
|
|
N24: TMenuItem;
|
|
|
|
|
mnuUnflatten: TMenuItem; // AV
|
|
|
|
|
mnuFlatten: TMenuItem;
|
|
|
|
|
N25: TMenuItem;
|
|
|
|
|
SortFlames: TMenuItem;
|
|
|
|
|
N26: TMenuItem;
|
|
|
|
|
mnuLowQuality: TMenuItem;
|
|
|
|
|
mnuMediumQuality: TMenuItem;
|
|
|
|
|
mnuHighQuality: TMenuItem;
|
|
|
|
|
mnuRefreshThumb: TMenuItem;
|
|
|
|
|
EnumerateFlames: TMenuItem;
|
|
|
|
|
DownloadPlugins: TMenuItem;
|
|
|
|
|
N27: TMenuItem;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
mnuRefreshAllThumbs: TMenuItem;
|
|
|
|
|
mnuAnimator: TMenuItem;
|
|
|
|
|
tbAnimate: TToolButton; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure mnuManualClick(Sender: TObject);
|
|
|
|
|
procedure mnuReportFlameClick(Sender: TObject);
|
|
|
|
|
procedure mnuTurnFlameToScriptClick(Sender: TObject);
|
|
|
|
|
procedure tbzoomoutwindowClick(Sender: TObject);
|
|
|
|
|
procedure mnuExitClick(Sender: TObject);
|
|
|
|
|
procedure mnuSaveUPRClick(Sender: TObject);
|
|
|
|
|
procedure ListViewChange(Sender: TObject; Item: TListItem;
|
|
|
|
|
Change: TItemChange);
|
|
|
|
|
procedure FormCreate(Sender: TObject);
|
|
|
|
|
procedure mnuRandomClick(Sender: TObject);
|
|
|
|
|
procedure mnuEqualizeClick(Sender: TObject);
|
|
|
|
|
procedure mnuEditorClick(Sender: TObject);
|
|
|
|
|
procedure mnuRWeightsClick(Sender: TObject);
|
|
|
|
|
procedure mnuRandomBatchClick(Sender: TObject);
|
|
|
|
|
procedure FormKeyPress(Sender: TObject; var Key: Char);
|
|
|
|
|
procedure FormKeyUpDown(Sender: TObject; var Key: Word;
|
|
|
|
|
Shift: TShiftState);
|
|
|
|
|
procedure mnuOptionsClick(Sender: TObject);
|
|
|
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
|
|
|
procedure mnuHelpTopicsClick(Sender: TObject);
|
|
|
|
|
procedure mnuNormalWeightsClick(Sender: TObject);
|
|
|
|
|
procedure FormDestroy(Sender: TObject);
|
|
|
|
|
procedure mnuCopyUPRClick(Sender: TObject);
|
|
|
|
|
procedure mnuItemDeleteClick(Sender: TObject);
|
|
|
|
|
procedure ListViewEdited(Sender: TObject; Item: TListItem;
|
|
|
|
|
var S: string);
|
|
|
|
|
procedure mnuListRenameClick(Sender: TObject);
|
|
|
|
|
procedure BackPanelResize(Sender: TObject);
|
|
|
|
|
procedure RedrawTimerTimer(Sender: TObject);
|
|
|
|
|
procedure FormShow(Sender: TObject);
|
|
|
|
|
procedure ShowStyledWindows(Sender: TObject);
|
|
|
|
|
procedure mnuVRandomClick(Sender: TObject);
|
|
|
|
|
procedure mnuSaveAsClick(Sender: TObject);
|
|
|
|
|
procedure mnuOpenClick(Sender: TObject);
|
|
|
|
|
procedure mnuGradClick(Sender: TObject);
|
|
|
|
|
procedure mnuSmoothGradientClick(Sender: TObject);
|
|
|
|
|
procedure mnuToolbarClick(Sender: TObject);
|
|
|
|
|
procedure mnuStatusBarClick(Sender: TObject);
|
|
|
|
|
procedure mnuFileContentsClick(Sender: TObject);
|
|
|
|
|
procedure mnuUndoClick(Sender: TObject);
|
|
|
|
|
procedure mnuRedoClick(Sender: TObject);
|
|
|
|
|
procedure Undo;
|
|
|
|
|
procedure Redo;
|
|
|
|
|
procedure mnuSaveUndoClick(Sender: TObject); // AV: restored and works
|
|
|
|
|
procedure mnuExportBitmapClick(Sender: TObject); // AV: to fast save params in PNG
|
|
|
|
|
procedure mnuFullScreenClick(Sender: TObject);
|
|
|
|
|
procedure mnuRenderClick(Sender: TObject);
|
|
|
|
|
procedure mnuMutateClick(Sender: TObject);
|
|
|
|
|
procedure mnuAdjustClick(Sender: TObject);
|
|
|
|
|
procedure mnuResetLocationClick(Sender: TObject);
|
|
|
|
|
procedure mnuAboutClick(Sender: TObject);
|
|
|
|
|
procedure mnuOpenGradientClick(Sender: TObject);
|
|
|
|
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
|
|
|
procedure FormActivate(Sender: TObject);
|
|
|
|
|
procedure FormDeactivate(Sender: TObject);
|
|
|
|
|
procedure mnuCalculateColorsClick(Sender: TObject);
|
|
|
|
|
procedure mnuRandomizeColorValuesClick(Sender: TObject);
|
|
|
|
|
procedure mnuEditScriptClick(Sender: TObject);
|
|
|
|
|
procedure mnuRunClick(Sender: TObject);
|
|
|
|
|
procedure mnuOpenScriptClick(Sender: TObject);
|
|
|
|
|
procedure mnuStopClick(Sender: TObject);
|
|
|
|
|
// procedure mnuImportGimpClick(Sender: TObject); // AV: rudiment from Apo 2.02
|
|
|
|
|
procedure mnuManageFavoritesClick(Sender: TObject);
|
|
|
|
|
procedure mnuImageSizeClick(Sender: TObject);
|
|
|
|
|
procedure ApplicationEventsActivate(Sender: TObject);
|
|
|
|
|
procedure mnuPasteClick(Sender: TObject);
|
|
|
|
|
procedure mnuCopyClick(Sender: TObject);
|
|
|
|
|
procedure mnuExportFlameClick(Sender: TObject);
|
|
|
|
|
procedure mnuExportChaoticaClick(Sender: TObject);
|
|
|
|
|
|
|
|
|
|
procedure ListXmlScannerStartTag(Sender: TObject; TagName: string;
|
|
|
|
|
Attributes: TAttrList);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure XmlScannerComment(Sender: TObject; Comment: string); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure XMLScannerStartTag(Sender: TObject; TagName: string;
|
|
|
|
|
Attributes: TAttrList);
|
|
|
|
|
procedure XMLScannerEmptyTag(Sender: TObject; TagName: string;
|
|
|
|
|
Attributes: TAttrList);
|
|
|
|
|
procedure mnuFlamepdfClick(Sender: TObject);
|
|
|
|
|
procedure ImageMouseDown(Sender: TObject; Button: TMouseButton;
|
|
|
|
|
Shift: TShiftState; X, Y: Integer);
|
|
|
|
|
procedure ImageMouseMove(Sender: TObject; Shift: TShiftState; X,
|
|
|
|
|
Y: Integer);
|
|
|
|
|
procedure ImageMouseUp(Sender: TObject; Button: TMouseButton;
|
|
|
|
|
Shift: TShiftState; X, Y: Integer);
|
|
|
|
|
procedure tbzoomwindowClick(Sender: TObject);
|
|
|
|
|
procedure tbDragClick(Sender: TObject);
|
|
|
|
|
procedure tbRotateClick(Sender: TObject);
|
|
|
|
|
procedure mnuSaveAllAsClick(Sender: TObject);
|
|
|
|
|
procedure tbQualityBoxKeyPress(Sender: TObject; var Key: Char);
|
|
|
|
|
procedure tbQualityBoxSet(Sender: TObject);
|
|
|
|
|
procedure ImageDblClick(Sender: TObject);
|
|
|
|
|
procedure tbShowAlphaClick(Sender: TObject);
|
|
|
|
|
procedure tbShowTraceClick(Sender: TObject);
|
|
|
|
|
procedure XmlScannerContent(Sender: TObject; Content: String);
|
|
|
|
|
procedure mnuRenderAllClick(Sender: TObject);
|
|
|
|
|
procedure btnViewIconsClick(Sender: TObject);
|
|
|
|
|
procedure btnViewListClick(Sender: TObject);
|
|
|
|
|
procedure XmlScannerEndTag(Sender: TObject; TagName: String);
|
|
|
|
|
procedure tbMessagesClick(Sender: TObject);
|
|
|
|
|
procedure btNewClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure ToolBarResize(Sender: TObject);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure mnuResetUIClick(Sender: TObject);
|
|
|
|
|
procedure AutoSaveTimerTimer(Sender: TObject);
|
|
|
|
|
procedure Restorelastautosave1Click(Sender: TObject);
|
|
|
|
|
procedure tbGuidesClick(Sender: TObject);
|
|
|
|
|
procedure tbCurvesClick(Sender: TObject);
|
|
|
|
|
procedure mnuTraceClick(Sender: TObject);
|
|
|
|
|
procedure CalculateWeightsClick(Sender: TObject);
|
|
|
|
|
procedure Randomizecolorspeed1Click(Sender: TObject);
|
|
|
|
|
procedure Calculatecolorspeed1Click(Sender: TObject);
|
|
|
|
|
procedure ResetColorSpeedClick(Sender: TObject);
|
|
|
|
|
procedure AddSymmetryClick(Sender: TObject); //AV
|
|
|
|
|
procedure AddTileClick(Sender: TObject); // AV
|
|
|
|
|
procedure ImportFromPNGClick(Sender: TObject); // AV
|
|
|
|
|
procedure mnuScreenShotClick(Sender: TObject); // AV
|
|
|
|
|
procedure ExtSysMenu(var Msg: TMessage); message WM_SysCommand; // AV
|
|
|
|
|
procedure AddTemplateClick(Sender: TObject);
|
|
|
|
|
procedure ResetColorValuesClick(Sender: TObject);
|
|
|
|
|
procedure mnuUnflattenClick(Sender: TObject);
|
|
|
|
|
procedure mnuFlattenClick(Sender: TObject);
|
|
|
|
|
procedure SortFlamesClick(Sender: TObject);
|
|
|
|
|
procedure ListViewColumnClick(Sender: TObject; Column: TListColumn);
|
|
|
|
|
procedure mnuThumbnailQualityClick(Sender: TObject);
|
|
|
|
|
procedure ListPopUpPopup(Sender: TObject);
|
|
|
|
|
procedure mnuRefreshThumbClick(Sender: TObject);
|
|
|
|
|
procedure EnumerateFlamesClick(Sender: TObject);
|
|
|
|
|
procedure ListViewDblClick(Sender: TObject);
|
|
|
|
|
procedure DownloadPluginsClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure mnuAnimatorClick(Sender: TObject);
|
|
|
|
|
procedure ListViewSelectItem(Sender: TObject; Item: TListItem;
|
|
|
|
|
Selected: Boolean);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
private
|
|
|
|
|
SubstSource: TStringList;
|
|
|
|
|
SubstTarget: TStringList;
|
|
|
|
|
|
|
|
|
|
Renderer: TRenderThread;
|
|
|
|
|
|
|
|
|
|
FMouseMoveState: TMouseMoveState;
|
|
|
|
|
FSelectRect, FClickRect: TRect;
|
|
|
|
|
DrawSelection: boolean;
|
|
|
|
|
FRotateAngle: double;
|
|
|
|
|
FClickAngle: double;
|
|
|
|
|
FViewImage: TPngObject;
|
|
|
|
|
FViewPos, FViewOldPos: TSPoint;
|
|
|
|
|
FViewScale: double;
|
|
|
|
|
// FClickPitch, FNewPitch: double;
|
|
|
|
|
// FClickYaw, FNewYaw: double;
|
|
|
|
|
FShiftState: TShiftState;
|
|
|
|
|
|
|
|
|
|
// For parsing:
|
|
|
|
|
FinalXformLoaded: boolean;
|
|
|
|
|
ActiveXformSet: integer;
|
|
|
|
|
XMLPaletteFormat: string;
|
|
|
|
|
XMLPaletteCount: integer;
|
|
|
|
|
|
|
|
|
|
camDragMode, camDragged, camMM: boolean;
|
|
|
|
|
camDragPos, camDragOld: TPoint;
|
|
|
|
|
camDragValueX, camDragValueY: double;
|
|
|
|
|
|
|
|
|
|
oldApo: boolean; // AV: to check relict variations
|
|
|
|
|
defKB: HKL; // AV: for non-English users :)
|
|
|
|
|
|
|
|
|
|
procedure CreateSubstMap;
|
|
|
|
|
procedure InsertStrings;
|
|
|
|
|
procedure DrawImageView;
|
|
|
|
|
procedure DrawZoomWindow;
|
|
|
|
|
procedure DrawRotatelines(Angle: double);
|
|
|
|
|
// procedure DrawPitchYawLines(YawAngle: double; PitchAngle:double);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure SetAutoSaveTimer; // AV
|
|
|
|
|
procedure RunThumbnailThread; inline;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure FillVariantMenu;
|
|
|
|
|
procedure VariantMenuClick(Sender: TObject);
|
|
|
|
|
|
|
|
|
|
procedure FavoriteClick(Sender: TObject);
|
|
|
|
|
procedure ScriptItemClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure StopScripter; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// AV: for Apo GUI themes
|
|
|
|
|
procedure CreateStyleList;
|
|
|
|
|
procedure StyleItemClick(Sender: TObject);
|
|
|
|
|
|
|
|
|
|
procedure HandleThreadCompletion(var Message: TMessage);
|
|
|
|
|
message WM_THREAD_COMPLETE;
|
|
|
|
|
procedure HandleThreadTermination(var Message: TMessage);
|
|
|
|
|
message WM_THREAD_TERMINATE;
|
|
|
|
|
|
|
|
|
|
public
|
|
|
|
|
{ Public declarations }
|
|
|
|
|
UndoIndex, UndoMax: integer;
|
|
|
|
|
Center: array[0..1] of double;
|
|
|
|
|
StartTime: TDateTime;
|
|
|
|
|
ParseLoadingBatch : boolean;
|
|
|
|
|
SurpressHandleMissingPlugins : boolean;
|
|
|
|
|
|
|
|
|
|
VarMenus: array of TMenuItem;
|
|
|
|
|
|
|
|
|
|
ListXmlScanner : TEasyXmlScanner;
|
|
|
|
|
XmlScanner : TXmlScanner;
|
|
|
|
|
|
|
|
|
|
function ReadWithSubst(Attributes: TAttrList; attrname: string): string;
|
|
|
|
|
// AV: added 3-rd parameter to be able to discard multiple updates
|
|
|
|
|
procedure LoadXMLFlame(filename, name: string; upd: boolean = true);
|
|
|
|
|
procedure DisableFavorites;
|
|
|
|
|
procedure EnableFavorites;
|
|
|
|
|
procedure ParseXML(var cp1: TControlPoint; const params: string; const ignoreErrors : boolean);
|
|
|
|
|
function SaveFlame(cp1: TControlPoint; title, filename: string): boolean;
|
|
|
|
|
function SaveXMLFlame(const cp1: TControlPoint; title, filename: string): boolean;
|
|
|
|
|
procedure DisplayHint(Sender: TObject);
|
|
|
|
|
procedure OnProgress(prog: double);
|
|
|
|
|
procedure ResizeImage;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// procedure DrawPreview;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure DrawFlame;
|
|
|
|
|
procedure UpdateUndo;
|
|
|
|
|
procedure LoadUndoFlame(index: integer; filename: string);
|
|
|
|
|
procedure SmoothPalette;
|
|
|
|
|
procedure Smoothize(const oldpal: TColorMap; const a, b: byte);
|
|
|
|
|
procedure RandomizeCP(var cp1: TControlPoint; alg: integer = 0);
|
|
|
|
|
function UPRString(cp1: TControlPoint; Entry: string): string;
|
|
|
|
|
function SaveGradient(Gradient, Title, FileName: string): boolean;
|
|
|
|
|
function GradientFromPalette(const pal: TColorMap; const title: string): string;
|
|
|
|
|
procedure StopThread;
|
|
|
|
|
procedure UpdateWindows;
|
|
|
|
|
procedure ResetLocation;
|
|
|
|
|
procedure RandomBatch;
|
|
|
|
|
procedure GetScripts;
|
|
|
|
|
function ApplicationOnHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean;
|
|
|
|
|
function SystemErrorMessage: string;
|
|
|
|
|
function SystemErrorMessage2(errno: cardinal): string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// function RetrieveXML(cp : TControlPoint): string; // AV: we can call it directly
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure ApplyThemedColors;
|
|
|
|
|
|
|
|
|
|
// AV: for reading / writing embedded parameters
|
|
|
|
|
procedure PasteFlameXML(flameXML: string);
|
|
|
|
|
procedure ImportThumbnailPNG(Filename: string);
|
|
|
|
|
function LoadXMLFlameTextPNG(FileName: string): string;
|
|
|
|
|
|
|
|
|
|
// AV: for updating the list with flame previews
|
|
|
|
|
procedure SetThumbnailProperties;
|
|
|
|
|
procedure RefreshThumbnail;
|
|
|
|
|
procedure UpdateThumbnails;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure AddFlameToList(const title: string = '');
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure ListXML(FileName: string; sel: integer; selname: string = ''); // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function GradientString(c: TColorMap): string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure RotateCMapHue(var cp: TControlPoint); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
function FlameInClipboard: boolean; // AV
|
|
|
|
|
function RemoveExt(filename: string): string; // AV
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
function WinShellExecute(const Operation, AssociatedFile: string): Boolean; // AV
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// AV: for making window screenshots
|
|
|
|
|
procedure GetFormScreenShot(const AFileName: string);
|
|
|
|
|
procedure SaveScreenShot(const AFormName: string);
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
|
MainForm: TMainForm;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
pname, ptime: string;
|
|
|
|
|
// pversion: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
nxform: integer;
|
|
|
|
|
|
|
|
|
|
MainCp: TControlPoint;
|
|
|
|
|
ParseCp: TControlPoint;
|
|
|
|
|
MemCp: TControlPoint;
|
|
|
|
|
ThumbnailSize: integer;
|
|
|
|
|
GeneratingThumbs: boolean; // AV
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AppVersionString: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
uses
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ClipBrd, Editor, Options, Settings, Template, MissingPlugin, Chaotica,
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FullScreen, FormRender, Mutate, Adjust, Browser, Save, About, CmapData,
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ScriptForm, FormFavorites, FormExport, RndFlame, Tracer, Types, SplashForm,
|
|
|
|
|
Animate;
|
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
TbBreakWidth = 810; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
{$R *.DFM}
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure AssignBitmapProperly(var Bitmap: TBitmap; Source: TBitmap);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
Bitmap.Dormant;
|
|
|
|
|
Bitmap.FreeImage;
|
|
|
|
|
Bitmap.Width := 0;
|
|
|
|
|
Bitmap.Assign(Source);
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure FreeBitmapProperly(var Bitmap: TBitmap);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
try
|
|
|
|
|
Bitmap.Dormant;
|
|
|
|
|
Bitmap.FreeImage;
|
|
|
|
|
finally
|
|
|
|
|
Bitmap.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{//////////////// Screenshot utils ////////////////////////}
|
|
|
|
|
|
|
|
|
|
procedure GetFormScreenShot(const AFileName: string); // AV
|
|
|
|
|
var
|
|
|
|
|
ScreenShot: TBitmap;
|
|
|
|
|
WindowRect: TRect;
|
|
|
|
|
begin
|
|
|
|
|
ScreenShot := TBitmap.Create;
|
|
|
|
|
try
|
|
|
|
|
ScreenShot.PixelFormat := pf32bit;
|
|
|
|
|
try
|
|
|
|
|
WindowRect := Screen.ActiveForm.BoundsRect;
|
|
|
|
|
ScreenShot.Width := WindowRect.Width;
|
|
|
|
|
ScreenShot.Height := WindowRect.Height;
|
|
|
|
|
BitBlt(ScreenShot.Canvas.Handle, 0, 0, WindowRect.Width, WindowRect.Height,
|
|
|
|
|
GetWindowDC(Screen.ActiveForm.Handle), 0, 0, SRCCOPY);
|
|
|
|
|
except
|
|
|
|
|
ScreenShot := nil;
|
|
|
|
|
end;
|
|
|
|
|
if ScreenShot <> nil then
|
|
|
|
|
ScreenShot.SaveToFile(AFileName);
|
|
|
|
|
finally
|
|
|
|
|
ScreenShot.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure SaveScreenShot(const AFormName: string); // AV
|
|
|
|
|
var
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
if not DirectoryExists(ScreenShotPath) then
|
|
|
|
|
begin
|
|
|
|
|
CreateDir(AppPath + 'ScreenShots\');
|
|
|
|
|
ScreenShotPath := AppPath + 'ScreenShots\';
|
|
|
|
|
end;
|
|
|
|
|
s := ScreenShotPath + AFormName + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now) + '.bmp';
|
|
|
|
|
try
|
|
|
|
|
GetFormScreenShot(s);
|
|
|
|
|
Application.MessageBox(PChar(Format(TextByKey('common-screenshot-saved'),
|
2022-06-23 06:22:32 -04:00
|
|
|
|
[ExtractFileName(s), ExtractFilePath(s)])),
|
|
|
|
|
ApophysisSVN, MB_ICONINFORMATION);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
except
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Application.MessageBox(PChar(TextByKey('common-screenshot-error')),
|
|
|
|
|
ApophysisSVN, MB_ICONERROR);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{//////////////////////////////////////////////////////////////////////////////}
|
|
|
|
|
|
|
|
|
|
function FlameInClipboard: boolean;
|
|
|
|
|
var
|
|
|
|
|
flamestr: string;
|
|
|
|
|
isstart, isend: integer;
|
|
|
|
|
begin
|
|
|
|
|
{ returns true if a flame in clipboard - can be tricked }
|
|
|
|
|
result := false;
|
|
|
|
|
if Clipboard.HasFormat(CF_TEXT) then
|
|
|
|
|
begin
|
|
|
|
|
flamestr := Clipboard.AsText;
|
|
|
|
|
isstart := Pos('<flame', flamestr);
|
|
|
|
|
isend := Pos('</flame>', flamestr);
|
|
|
|
|
if (isstart > 0) and (isend > 0) and (isstart < isend) then
|
|
|
|
|
Result := true;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ ************************************* Help ********************************* }
|
|
|
|
|
|
|
|
|
|
procedure ShowHelp(Pt: TPoint; ContextId: Integer);
|
|
|
|
|
//var
|
|
|
|
|
//Popup: THHPopup;
|
|
|
|
|
begin
|
|
|
|
|
(* -X- context help not longer supported
|
|
|
|
|
FillChar(Popup, SizeOf(Popup), 0);
|
|
|
|
|
Popup.cbStruct := SizeOf(Popup);
|
|
|
|
|
Popup.hinst := 0;
|
|
|
|
|
Popup.idString := ContextId;
|
|
|
|
|
Popup.pszText := nil;
|
|
|
|
|
GetCursorPos(Pt);
|
|
|
|
|
Popup.pt := Pt;
|
|
|
|
|
Popup.clrForeGround := TColorRef(-1);
|
|
|
|
|
Popup.clrBackground := TColorRef(-1);
|
|
|
|
|
Popup.rcMargins := Rect(-1, -1, -1, -1);
|
|
|
|
|
Popup.pszFont := '';
|
|
|
|
|
HtmlHelp(0, PChar(AppPath + 'Apophysis7x.chm::/Popups.txt'), HH_DISPLAY_TEXT_POPUP, DWORD(@Popup));
|
|
|
|
|
*)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ExtSysMenu(var Msg: TMessage);
|
|
|
|
|
begin
|
|
|
|
|
if Msg.WParam = $C0 then mnuScreenShot.Click;
|
|
|
|
|
inherited;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.InsertStrings;
|
|
|
|
|
begin
|
|
|
|
|
mnuCopy.Caption := TextByKey('common-copy');
|
|
|
|
|
mnuPaste.Caption := TextByKey('common-paste');
|
|
|
|
|
mnuCopy.Hint := TextByKey('main-menu-edit-copy');
|
|
|
|
|
mnuPaste.Hint := TextByKey('main-menu-edit-paste');
|
|
|
|
|
mnuItemDelete.Caption := TextByKey('common-delete');
|
|
|
|
|
mnuListRename.Caption := TextByKey('common-rename');
|
|
|
|
|
mnuItemDelete.Hint := TextByKey('main-menu-deletehint'); // AV
|
|
|
|
|
mnuListRename.Hint := TextByKey('main-menu-renamehint'); // AV
|
|
|
|
|
mnuRefreshThumb.Caption := TextByKey('main-menu-updatethumb');
|
|
|
|
|
mnuRefreshAllThumbs.Caption := TextByKey('main-menu-updateallthumbs');
|
|
|
|
|
mnuLowQuality.Caption := TextByKey('common-lowquality'); // AV
|
|
|
|
|
mnuMediumQuality.Caption := TextByKey('common-mediumquality'); // AV
|
|
|
|
|
mnuHighQuality.Caption := TextByKey('common-highquality'); // AV
|
|
|
|
|
mnuUndo.Caption := TextByKey('common-undo');
|
|
|
|
|
mnuPopUndo.Caption := TextByKey('common-undo');
|
|
|
|
|
btnUndo.Hint := TextByKey('main-toolbar-undo');
|
|
|
|
|
mnuUndo.Hint := TextByKey('main-toolbar-undo');
|
|
|
|
|
mnuRedo.Caption := TextByKey('common-redo');
|
|
|
|
|
mnuPopRedo.Caption := TextByKey('common-redo');
|
|
|
|
|
btnRedo.Hint := TextByKey('main-toolbar-redo');
|
|
|
|
|
mnuRedo.Hint := TextByKey('main-toolbar-redo');
|
|
|
|
|
MainFile.Caption := TextByKey('main-menu-file-title');
|
|
|
|
|
New1.Caption := TextByKey('main-menu-file-new');
|
|
|
|
|
New1.Hint := TextByKey('main-toolbar-new');
|
|
|
|
|
mnuTrace.Caption := TextByKey('main-menu-options-tracelog');
|
|
|
|
|
btNew.Hint := TextByKey('main-toolbar-new');
|
|
|
|
|
mnuOpen.Caption := TextByKey('main-menu-file-open');
|
|
|
|
|
btnOpen.Hint := TextByKey('main-toolbar-open');
|
|
|
|
|
mnuOpen.Hint := TextByKey('main-toolbar-open');
|
|
|
|
|
ImportFromPNG.Caption := TextByKey('main-menu-file-loadpng');
|
|
|
|
|
ImportFromPNG.Hint := TextByKey('main-menu-file-loadpnghint');
|
|
|
|
|
mnuScreenShot.Caption := TextByKey('main-menu-screenshot');
|
|
|
|
|
RestoreLastAutosave1.Caption := TextByKey('main-menu-file-restoreautosave');
|
|
|
|
|
RestoreLastAutosave1.Hint := TextByKey('main-menu-file-autosavehint');
|
|
|
|
|
mnuSaveAs.Caption := TextByKey('main-menu-file-saveparams');
|
|
|
|
|
mnuSaveAs.Hint := TextByKey('main-toolbar-saveparams');
|
|
|
|
|
btnSave.Hint := TextByKey('main-toolbar-saveparams');
|
|
|
|
|
mnuSaveAllAs.Caption := TextByKey('main-menu-file-saveallparams');
|
|
|
|
|
mnuSaveAllAs.Hint := TextByKey('main-menu-file-saveallhint');
|
|
|
|
|
mnuSmoothGradient.Caption := TextByKey('main-menu-file-smoothpalette');
|
|
|
|
|
mnuSmoothGradient.Hint := TextByKey('main-menu-file-smoothpalettehint');
|
|
|
|
|
mnuOpenGradient.Caption := TextByKey('main-menu-file-gradientbrowser');
|
|
|
|
|
mnuOpenGradient.Hint := TextByKey('main-menu-file-gradientbrowserhint');
|
|
|
|
|
mnuSaveUPR.Caption := TextByKey('main-menu-file-exportupr');
|
|
|
|
|
mnuExportFlame.Caption := TextByKey('main-menu-file-exportflame');
|
|
|
|
|
mnuExportChaotica.Caption := TextByKey('main-menu-file-exportchaotica');
|
|
|
|
|
mnuRandomBatch.Caption := TextByKey('main-menu-file-randombatch');
|
|
|
|
|
mnuExit.Caption := TextByKey('main-menu-file-exit');
|
|
|
|
|
mnuExit.Hint := TextByKey('main-menu-file-exithint');
|
|
|
|
|
mnuSaveUPR.Hint := TextByKey('main-menu-file-exportuprhint');
|
|
|
|
|
mnuExportFlame.Hint := TextByKey('main-menu-file-exportflamehint');
|
|
|
|
|
mnuExportChaotica.Hint := TextByKey('main-menu-file-exportchaoticahint');
|
|
|
|
|
mnuExportBitmap.Caption := TextByKey('main-menu-saveimage'); // AV
|
|
|
|
|
mnuRandomBatch.Hint := TextByKey('main-menu-file-randombatchhint');
|
|
|
|
|
MainEdit.Caption := TextByKey('main-menu-edit-title');
|
|
|
|
|
mnuSaveUndo.Caption := TextByKey('main-menu-edit-saveundo');
|
|
|
|
|
mnuCopyUPR.Caption := TextByKey('main-menu-edit-copyasupr');
|
|
|
|
|
mnuCopyUPR.Hint := TextByKey('main-menu-edit-copyuprhint');
|
|
|
|
|
View1.Caption := TextByKey('main-menu-view-title');
|
|
|
|
|
mnuFullScreen.Caption := TextByKey('main-menu-view-fullscreen');
|
|
|
|
|
mnuPopFullscreen.Caption := TextByKey('main-menu-view-fullscreen');
|
|
|
|
|
btnFullScreen.Hint := TextByKey('main-toolbar-fullscreen');
|
|
|
|
|
mnuFullScreen.Hint := TextByKey('main-toolbar-fullscreen');
|
|
|
|
|
mnuEditor.Caption := TextByKey('main-menu-view-editor');
|
|
|
|
|
mnuEditor.Hint := TextByKey('main-toolbar-editor');
|
|
|
|
|
tbEditor.Hint := TextByKey('main-toolbar-editor');
|
|
|
|
|
mnuAdjust.Caption := TextByKey('main-menu-view-adjustment');
|
|
|
|
|
mnuAdjust.Hint := TextByKey('main-toolbar-adjustment');
|
|
|
|
|
tbAdjust.Hint := TextByKey('main-toolbar-adjustment');
|
|
|
|
|
mnuGrad.Caption := TextByKey('main-menu-view-gradient');
|
|
|
|
|
mnuGrad.Hint := TextByKey('main-toolbar-gradient');
|
|
|
|
|
tbPalette.Hint := TextByKey('main-toolbar-gradient');
|
|
|
|
|
mnuMutate.Hint := TextByKey('main-toolbar-mutation');
|
|
|
|
|
mnuMutate.Caption := TextByKey('main-menu-view-mutation');
|
|
|
|
|
tbMutate.Hint := TextByKey('main-toolbar-mutation');
|
|
|
|
|
mnuImageSize.Caption := TextByKey('main-menu-view-imagesize');
|
|
|
|
|
mnuImageSize.Hint := TextByKey('main-toolbar-imagesize');
|
|
|
|
|
tbImageSize.Hint := TextByKey('main-toolbar-imagesize');
|
|
|
|
|
mnuMessages.Caption := TextByKey('main-menu-view-messages');
|
|
|
|
|
mnuMessages.Hint := TextByKey('main-toolbar-messages');
|
|
|
|
|
tbMessages.Hint := TextByKey('main-toolbar-messages');
|
|
|
|
|
tbCurves.Hint := TextByKey('main-toolbar-curves');
|
|
|
|
|
mnuCurves.Hint := TextByKey('main-toolbar-curves');
|
|
|
|
|
mnuCurves.Caption := TextByKey('main-menu-view-curves');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
tbAnimate.Hint := TextByKey('main-toolbar-animator');
|
|
|
|
|
mnuAnimator.Caption := TextByKey('main-menu-view-animator'); // AV
|
|
|
|
|
mnuAnimator.Hint := GetLongHint(tbAnimate.Hint); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainFlame.Caption := TextByKey('main-menu-flame-title');
|
|
|
|
|
mnuResetLocation.Caption := TextByKey('main-menu-flame-reset');
|
|
|
|
|
mnuPopResetLocation.Caption := TextByKey('main-menu-flame-reset');
|
|
|
|
|
mnuResetLocation.Hint := TextByKey('main-toolbar-reset');
|
|
|
|
|
btnReset.Hint := TextByKey('main-toolbar-reset');
|
|
|
|
|
mnuRandom.Caption := TextByKey('main-menu-flame-randomize');
|
|
|
|
|
mnuRandom.Hint := TextByKey('main-menu-flame-randomizehint');
|
|
|
|
|
mnuRWeights.Caption := TextByKey('main-menu-flame-randomweights');
|
|
|
|
|
mnuRWeights.Hint := TextByKey('main-menu-flame-randomweightshint');
|
|
|
|
|
mnuEqualize.Caption := TextByKey('main-menu-flame-equalweights');
|
|
|
|
|
mnuEqualize.Hint := TextByKey('main-menu-flame-equalweightshint');
|
|
|
|
|
CalculateWeights.Caption := TextByKey('main-menu-flame-calculateweights');
|
|
|
|
|
CalculateWeights.Hint := TextByKey('main-menu-flame-calculateweightshint');
|
|
|
|
|
mnuNormalWeights.Caption := TextByKey('main-menu-flame-normweights');
|
|
|
|
|
mnuNormalWeights.Hint := TextByKey('main-menu-flame-normweightshint');
|
|
|
|
|
mnuCalculateColors.Caption := TextByKey('main-menu-flame-calculatecolors');
|
|
|
|
|
mnuRandomizeColorValues.Caption := TextByKey('main-menu-flame-randomizecolors');
|
|
|
|
|
Calculatecolorspeed1.Caption := TextByKey('main-menu-flame-calculatecolorspeed');
|
|
|
|
|
Randomizecolorspeed1.Caption := TextByKey('main-menu-flame-randomizecolorspeed');
|
|
|
|
|
ResetColorSpeed.Caption := TextByKey('main-menu-flame-resetcolorspeed');
|
|
|
|
|
ResetColorValues.Caption := TextByKey('main-menu-flame-resetcolors');
|
|
|
|
|
ResetColorValues.Hint := TextByKey('main-menu-flame-resetcolorshint');
|
|
|
|
|
mnuCalculateColors.Hint := TextByKey('main-menu-flame-calccolorshint');
|
|
|
|
|
mnuRandomizeColorValues.Hint := TextByKey('main-menu-flame-randcolorshint');
|
|
|
|
|
Calculatecolorspeed1.Hint := TextByKey('main-menu-flame-calccolorspeedhint');
|
|
|
|
|
Randomizecolorspeed1.Hint := TextByKey('main-menu-flame-randcolorspeedhint');
|
|
|
|
|
Resetcolorspeed.Hint := TextByKey('main-menu-flame-resetcolorspeedhint');
|
|
|
|
|
mnuFlatten.Caption := TextByKey('main-menu-flame-flatten');
|
|
|
|
|
mnuFlatten.Hint := TextByKey('main-menu-flame-flattenhint');
|
|
|
|
|
mnuUnflatten.Caption := TextByKey('main-menu-flame-unflatten');
|
|
|
|
|
mnuUnflatten.Hint := TextByKey('main-menu-flame-unflattenhint');
|
|
|
|
|
mnuRender.Caption := TextByKey('main-menu-flame-rendertodisk');
|
|
|
|
|
mnuRender.Hint := TextByKey('main-toolbar-render');
|
|
|
|
|
btnRender.Hint := TextByKey('main-toolbar-render');
|
|
|
|
|
mnuRenderAll.Caption := TextByKey('main-menu-flame-renderallflames');
|
|
|
|
|
mnuRenderAll.Hint := TextByKey('main-toolbar-renderall');
|
|
|
|
|
tbRenderAll.Hint := TextByKey('main-toolbar-renderall');
|
|
|
|
|
mnuReportFlame.Caption := TextByKey('main-menu-flame-generatereport');
|
|
|
|
|
mnuReportFlame.Hint := TextByKey('main-menu-flame-reporthint');
|
|
|
|
|
AddTemplate.Caption := TextByKey('main-menu-flame-template');
|
|
|
|
|
AddTemplate.Hint := TextByKey('main-menu-flame-templatehint');
|
|
|
|
|
mnuVar.Caption := TextByKey('main-menu-variation-title');
|
|
|
|
|
mnuVRandom.Caption := TextByKey('main-menu-variation-random');
|
|
|
|
|
mnuBuiltinVars.Caption := TextByKey('main-menu-variation-builtin');
|
|
|
|
|
mnuPluginVars.Caption := TextByKey('main-menu-variation-plugins');
|
|
|
|
|
mnuVRandom.Hint := TextByKey('main-menu-variation-randomhint');
|
|
|
|
|
mnuBuiltinVars.Hint := TextByKey('main-menu-variation-builtinhint');
|
|
|
|
|
mnuPluginVars.Hint := TextByKey('main-menu-variation-pluginshint');
|
|
|
|
|
mnuScript.Caption := TextByKey('main-menu-script-title');
|
|
|
|
|
mnuRun.Caption := TextByKey('main-menu-script-run');
|
|
|
|
|
mnuRun.Hint := TextByKey('main-toolbar-runscript');
|
|
|
|
|
btnRunScript.Hint := TextByKey('main-toolbar-runscript');
|
|
|
|
|
mnuStop.Caption := TextByKey('main-menu-script-stop');
|
|
|
|
|
mnuStop.Hint := TextByKey('main-toolbar-stopscript');
|
|
|
|
|
btnStopScript.Hint := TextByKey('main-toolbar-stopscript');
|
|
|
|
|
mnuOpenScript.Caption := TextByKey('main-menu-script-open');
|
|
|
|
|
mnuOpenScript.Hint := TextByKey('main-menu-script-openhint');
|
|
|
|
|
mnuEditScript.Caption := TextByKey('main-menu-script-edit');
|
|
|
|
|
mnuEditScript.Hint := TextByKey('main-toolbar-editscript');
|
|
|
|
|
tbEditScript.Hint := TextByKey('main-toolbar-editscript');
|
|
|
|
|
mnuManageFavorites.Caption := TextByKey('main-menu-script-managefaves');
|
|
|
|
|
mnuTurnFlameToScript.Caption := TextByKey('main-menu-script-flametoscript');
|
|
|
|
|
mnuManageFavorites.Hint := TextByKey('main-menu-script-managefaveshint');
|
|
|
|
|
mnuTurnFlameToScript.Hint := TextByKey('main-menu-script-flametoscripthint');
|
|
|
|
|
FavouriteScripts1.Caption := TextByKey('favscripts-title');
|
|
|
|
|
FavouriteScripts1.Hint := TextByKey('favscripts-hint');
|
|
|
|
|
mnuView.Caption := TextByKey('main-menu-options-title');
|
|
|
|
|
Directory1.Caption := IfThen(FavouriteScripts1.Enabled,
|
|
|
|
|
TextByKey('main-menu-script-more'), TextByKey('main-menu-script-directory'));
|
|
|
|
|
Directory1.Hint := TextByKey('main-menu-script-directoryhint');
|
|
|
|
|
mnuToolbar.Caption := TextByKey('main-menu-options-togglemaintoolbar');
|
|
|
|
|
mnuStatusBar.Caption := TextByKey('main-menu-options-togglestatusbar');
|
|
|
|
|
mnuFileContents.Caption := TextByKey('main-menu-options-togglefilelist');
|
|
|
|
|
mnuResetUI.Caption := TextByKey('main-menu-options-resetfilelistwidth');
|
|
|
|
|
mnuResetUI.Hint := TextByKey('main-menu-options-resetwidthhint');
|
|
|
|
|
SortFlames.Caption := TextByKey('main-menu-options-sortflames');
|
|
|
|
|
EnumerateFlames.Caption := TextByKey('main-menu-options-enumflames');
|
|
|
|
|
mnuTrace.Hint := TextByKey('main-menu-options-traceloghint');
|
|
|
|
|
mnuOptions.Caption := TextByKey('main-menu-options-showoptions');
|
|
|
|
|
mnuOptions.Hint := TextByKey('main-toolbar-options');
|
|
|
|
|
tbOptions.Hint := TextByKey('main-toolbar-options');
|
|
|
|
|
MainHelp.Caption := TextByKey('main-menu-help-title');
|
|
|
|
|
mnuHelpTopics.Caption := TextByKey('main-menu-help-contents');
|
|
|
|
|
mnuFlamePDF.Caption := TextByKey('main-menu-help-aboutalgorithm');
|
|
|
|
|
mnuAbout.Caption := TextByKey('main-menu-help-aboutapophysis');
|
|
|
|
|
mnuHelpTopics.Hint := TextByKey('main-menu-help-contentshint');
|
|
|
|
|
mnuFlamePDF.Hint := TextByKey('main-menu-help-aboutalgorithmhint');
|
|
|
|
|
mnuAbout.Hint := TextByKey('main-menu-help-aboutapophysishint');
|
|
|
|
|
btnViewList.Hint := TextByKey('main-toolbar-listviewmode-classic');
|
|
|
|
|
btnViewIcons.Hint := TextByKey('main-toolbar-listviewmode-icons');
|
|
|
|
|
tbShowAlpha.Hint := TextByKey('main-toolbar-togglealpha');
|
|
|
|
|
tbGuides.Hint := TextByKey('main-toolbar-toggleguides');
|
|
|
|
|
tbQualityBox.Hint := TextByKey('main-toolbar-quality');
|
|
|
|
|
tbDrag.Hint := TextByKey('main-toolbar-modemove');
|
|
|
|
|
tbRotate.Hint := TextByKey('main-toolbar-moderotate');
|
|
|
|
|
tbZoomIn.Hint := TextByKey('main-toolbar-modezoomin');
|
|
|
|
|
tbZoomOut.Hint := TextByKey('main-toolbar-modezoomout');
|
|
|
|
|
ListView1.Columns[0].Caption := TextByKey('save-name');
|
|
|
|
|
mnuResumeRender.Caption := TextByKey('main-menu-flame-resumeunfinished');
|
|
|
|
|
mnuApoStyle.Caption := TextByKey('main-menu-options-apouistyle');
|
|
|
|
|
mnuApoStyle.Hint := TextByKey('main-menu-options-apouistylehint');
|
|
|
|
|
mnuManual.Caption := TextByKey('main-menu-help-ifstheory');
|
|
|
|
|
mnuManual.Hint := TextByKey('main-menu-help-ifstheoryhint'); // AV
|
|
|
|
|
DownloadPlugins.Caption := TextByKey('main-menu-help-pluginlink'); // AV
|
|
|
|
|
Changeweightdistribution1.Caption := TextByKey('main-menu-flame-changeweights');
|
|
|
|
|
Changecolordistribution1.Caption := TextByKey('main-menu-flame-changecolors');
|
|
|
|
|
Hexagonal1.Caption := TextByKey('main-menu-flame-hextile');
|
|
|
|
|
Rhombic1.Caption := TextByKey('main-menu-flame-rhombustile');
|
|
|
|
|
Square1.Caption := TextByKey('main-menu-flame-squaretile');
|
|
|
|
|
AddTile.Caption := TextByKey('main-menu-flame-addtile');
|
|
|
|
|
AddSymmetry.Caption := TextByKey('main-menu-flame-addsymmetry');
|
|
|
|
|
BilateralSym.Caption := TextByKey('options-tab-random-type-bilateral');
|
|
|
|
|
RotationalSym.Caption := TextByKey('options-tab-random-type-rotational') + TextByKey('main-menu-flame-symorder');
|
|
|
|
|
DihedralSym.Caption := TextByKey('options-tab-random-type-dihedral') + TextByKey('main-menu-flame-symorder');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.ApplicationOnHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean;
|
|
|
|
|
var
|
|
|
|
|
Pos: TPoint;
|
|
|
|
|
begin
|
|
|
|
|
Pos.x := 0;
|
|
|
|
|
Pos.y := 0;
|
|
|
|
|
|
|
|
|
|
CallHelp := False;
|
|
|
|
|
Result := True;
|
|
|
|
|
case Command of
|
|
|
|
|
HELP_SETPOPUP_POS: Pos := SmallPointToPoint(TSmallPoint(Data));
|
|
|
|
|
HELP_CONTEXTPOPUP: ShowHelp(Pos, Data);
|
|
|
|
|
else Result := False;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ApplyThemedColors; // AV
|
|
|
|
|
var
|
|
|
|
|
AStyle: TCustomStyleServices;
|
|
|
|
|
MenuC1, MenuC2: TColor;
|
|
|
|
|
mb: TMenuBreak;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
AStyle := TStyleManager.ActiveStyle;
|
|
|
|
|
CurrentStyle := AStyle.Name;
|
|
|
|
|
|
|
|
|
|
BrightColor := AStyle.GetSystemColor(clHighlight);
|
|
|
|
|
WinColor := AStyle.GetSystemColor(clWindow);
|
|
|
|
|
TextColor := AStyle.GetSystemColor(clWindowText);
|
|
|
|
|
MidColor := MiddleColor(BrightColor, WinColor);
|
|
|
|
|
|
|
|
|
|
AStyle.GetElementColor(AStyle.GetElementDetails(tmPopupItemNormal),
|
|
|
|
|
ecTextColor, MenuC1);
|
|
|
|
|
AStyle.GetElementColor(AStyle.GetElementDetails(tmMenuBarItemNormal),
|
|
|
|
|
ecTextColor, MenuC2);
|
|
|
|
|
|
|
|
|
|
IsLightMenu := (MenuC1 > $00BEBEBE);
|
|
|
|
|
if IsLightMenu then
|
|
|
|
|
mnuEditor.ImageIndex := 75
|
|
|
|
|
else
|
|
|
|
|
mnuEditor.ImageIndex := 19;
|
|
|
|
|
|
|
|
|
|
if CurrentStyle <> 'Obsidian' then
|
|
|
|
|
IsLightMenu := IsLightMenu or (MenuC2 > $00BEBEBE);
|
|
|
|
|
if IsLightMenu then
|
|
|
|
|
tbEditor.ImageIndex := 75
|
|
|
|
|
else
|
|
|
|
|
tbEditor.ImageIndex := 19;
|
|
|
|
|
|
|
|
|
|
IsDarkTheme := (CurrentStyle = 'TabletDark') or (CurrentStyle = 'Auric')
|
|
|
|
|
or (CurrentStyle = 'Cobalt XEMedia') or (CurrentStyle = 'Onyx Blue')
|
|
|
|
|
or (CurrentStyle = 'Ruby Graphite') or (CurrentStyle = 'Golden Graphite');
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (CurrentStyle = 'Windows') then mb := mbNone
|
|
|
|
|
else mb := mbBreak;
|
|
|
|
|
i := 0;
|
|
|
|
|
while i < mnuBuiltinVars.Count do
|
|
|
|
|
begin
|
|
|
|
|
mnuBuiltinVars[i].Break := mb;
|
|
|
|
|
inc(i, mbHeight);
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
i := 0;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
while i < mnuPluginVars.Count do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
mnuPluginVars[i].Break := mb;
|
|
|
|
|
inc(i, mbHeight);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ **************************************************************************** }
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.StopThread;
|
|
|
|
|
begin
|
|
|
|
|
RedrawTimer.Enabled := False;
|
|
|
|
|
if Assigned(Renderer) then begin
|
|
|
|
|
assert(Renderer.Suspended = false);
|
|
|
|
|
Renderer.Terminate;
|
|
|
|
|
Renderer.WaitFor;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
// AV: how old are they? Maybe since Apo 1.0? :)
|
|
|
|
|
|
|
|
|
|
procedure EqualizeVars(const x: integer);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
MainCp.xform[x].SetVariation(i, 1.0 / NRVAR);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure NormalVars(const x: integer);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
td: double;
|
|
|
|
|
begin
|
|
|
|
|
td := 0.0;
|
|
|
|
|
for i := 0 to 6 do
|
|
|
|
|
td := td + Maincp.xform[x].GetVariation(i);
|
|
|
|
|
if (td < 0.001) then
|
|
|
|
|
EqualizeVars(x)
|
|
|
|
|
else
|
|
|
|
|
for i := 0 to 6 do
|
|
|
|
|
MainCp.xform[x].SetVariation(i, MainCp.xform[x].GetVariation(i) / td);
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
|
|
|
|
// AV: commented out since we have the same methods in RndFlame unit!
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure RandomVariation(cp: TControlPoint);
|
|
|
|
|
{ Randomise variation parameters }
|
|
|
|
|
var
|
|
|
|
|
a, b, i, j: integer;
|
|
|
|
|
begin
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
for i := 0 to cp.NumXForms - 1 do
|
|
|
|
|
begin
|
|
|
|
|
for j := 0 to NRVAR - 1 do
|
|
|
|
|
cp.xform[i].SetVariation(j, 0);
|
|
|
|
|
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);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
cp.xform[i].SetVariation(a, random);
|
|
|
|
|
cp.xform[i].SetVariation(b, 1 - cp.xform[i].GetVariation(a));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure SetVariation(cp: TControlPoint);
|
|
|
|
|
{ Set the current Variation }
|
|
|
|
|
var
|
|
|
|
|
i, j: integer;
|
|
|
|
|
begin
|
|
|
|
|
if Variation = vRandom then
|
|
|
|
|
begin
|
|
|
|
|
RandomVariation(cp);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
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);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
function FindFlameXML(const FlameStr: string; const Title: string) : Integer;
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
FlameStart: string;
|
|
|
|
|
begin
|
|
|
|
|
Result := 0;
|
|
|
|
|
FlameStart := '<flame ';
|
|
|
|
|
if Title <> '' then
|
|
|
|
|
FlameStart := '<flame name="' + Title + '"';
|
|
|
|
|
if FlameStr <> '' then
|
|
|
|
|
begin
|
|
|
|
|
i := Pos(FlameStart, Lowercase(FlameStr));
|
|
|
|
|
while i > 0 do
|
|
|
|
|
if PosEx('</flame', Lowercase(FlameStr), i+1) > i then
|
|
|
|
|
begin
|
|
|
|
|
Result := i;
|
|
|
|
|
break;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.RandomizeColorSpeed1Click(Sender: TObject);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
maincp.xform[i].symmetry := 2 * random - 1;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.RandomizeCP(var cp1: TControlPoint; alg: integer = 0);
|
|
|
|
|
var
|
|
|
|
|
sourceCP: TControlPoint;
|
|
|
|
|
begin
|
|
|
|
|
if assigned(MainCP) then
|
|
|
|
|
sourceCP := MainCP.Clone
|
|
|
|
|
else
|
|
|
|
|
SourceCP := nil;
|
|
|
|
|
|
|
|
|
|
if assigned(cp1) then begin
|
|
|
|
|
cp1.Free;
|
|
|
|
|
cp1 := nil;
|
|
|
|
|
end;
|
|
|
|
|
cp1 := RandomFlame(sourceCP, alg);
|
|
|
|
|
|
|
|
|
|
if assigned(sourceCP) then
|
|
|
|
|
sourceCP.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.GradientFromPalette(const pal: TColorMap; const title: string): string;
|
|
|
|
|
var
|
|
|
|
|
c, i, j: integer;
|
|
|
|
|
strings: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
strings.add('gradient:');
|
|
|
|
|
strings.add(' title="' + CleanUPRTitle(title) + '" smooth=no');
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
j := round(i * (399 / 255));
|
|
|
|
|
c := pal[i][2] shl 16 + pal[i][1] shl 8 + pal[i][0];
|
|
|
|
|
strings.Add(' index=' + IntToStr(j) + ' color=' + intToStr(c));
|
|
|
|
|
end;
|
|
|
|
|
result := strings.text;
|
|
|
|
|
finally
|
|
|
|
|
strings.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.OnProgress(prog: double);
|
|
|
|
|
var
|
|
|
|
|
Elapsed, Remaining: TDateTime;
|
|
|
|
|
IntProg: Integer;
|
|
|
|
|
begin
|
|
|
|
|
IntProg := (round(prog * 100));
|
|
|
|
|
LoadSaveProgress.Position := IntProg;
|
|
|
|
|
if (IntProg = 100) then LoadSaveProgress.Position := 0;
|
|
|
|
|
Elapsed := Now - StartTime;
|
|
|
|
|
StatusBar.Panels[1].Text := Format(TextByKey('render-status-elapsed') + ' %2.2d:%2.2d:%2.2d.%2.2d',
|
|
|
|
|
[Trunc(Elapsed * 24),
|
|
|
|
|
Trunc((Elapsed * 24 - Trunc(Elapsed * 24)) * 60),
|
|
|
|
|
Trunc((Elapsed * 24 * 60 - Trunc(Elapsed * 24 * 60)) * 60),
|
|
|
|
|
Trunc((Elapsed * 24 * 60 * 60 - Trunc(Elapsed * 24 * 60 * 60)) * 100)]);
|
|
|
|
|
if prog > 0 then
|
|
|
|
|
Remaining := Elapsed/prog - Elapsed
|
|
|
|
|
else
|
|
|
|
|
Remaining := 0;
|
|
|
|
|
|
|
|
|
|
StatusBar.Panels[2].Text := Format(TextByKey('render-status-remaining') + ' %2.2d:%2.2d:%2.2d.%2.2d',
|
|
|
|
|
[Trunc(Remaining * 24),
|
|
|
|
|
Trunc((Remaining * 24 - Trunc(Remaining * 24)) * 60),
|
|
|
|
|
Trunc((Remaining * 24 * 60 - Trunc(Remaining * 24 * 60)) * 60),
|
|
|
|
|
Trunc((Remaining * 24 * 60 * 60 - Trunc(Remaining * 24 * 60 * 60)) * 100)]);
|
|
|
|
|
StatusBar.Panels[3].Text := MainCp.name;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.UpdateUndo;
|
|
|
|
|
begin
|
|
|
|
|
MainCp.FillUsedPlugins;
|
|
|
|
|
SaveFlame(MainCp, Format('%.4d-', [UndoIndex]) + MainCp.name,
|
|
|
|
|
AppPath + undoFilename);
|
|
|
|
|
Inc(UndoIndex);
|
|
|
|
|
UndoMax := UndoIndex; //Inc(UndoMax);
|
|
|
|
|
mnuSaveUndo.Enabled := true;
|
|
|
|
|
mnuUndo.Enabled := True;
|
|
|
|
|
mnuPopUndo.Enabled := True;
|
|
|
|
|
mnuRedo.Enabled := false;
|
|
|
|
|
mnuPopRedo.Enabled := false;
|
|
|
|
|
btnUndo.enabled := true;
|
|
|
|
|
btnRedo.Enabled := false;
|
|
|
|
|
EditForm.mnuUndo.Enabled := True;
|
|
|
|
|
EditForm.mnuRedo.Enabled := false;
|
|
|
|
|
EditForm.tbUndo.enabled := true;
|
|
|
|
|
EditForm.tbRedo.enabled := false;
|
|
|
|
|
AdjustForm.btnUndo.enabled := true;
|
|
|
|
|
AdjustForm.btnRedo.enabled := false;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function GradientEntries(gFilename: string): string;
|
|
|
|
|
var
|
|
|
|
|
i, p: integer;
|
|
|
|
|
Title: string;
|
|
|
|
|
FileStrings: TStringList;
|
|
|
|
|
NewStrings: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
FileStrings := TStringList.Create;
|
|
|
|
|
NewStrings := TStringList.Create;
|
|
|
|
|
NewStrings.Text := '';
|
|
|
|
|
FileStrings.LoadFromFile(gFilename);
|
|
|
|
|
try
|
|
|
|
|
if (Pos('{', FileStrings.Text) <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to FileStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('{', FileStrings[i]);
|
|
|
|
|
if (p <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
Title := Trim(Copy(FileStrings[i], 1, p - 1));
|
|
|
|
|
if (Title <> '') and (LowerCase(Title) <> 'comment') then
|
|
|
|
|
begin { Otherwise bad format }
|
|
|
|
|
NewStrings.Add(Title);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
GradientEntries := NewStrings.Text;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
FileStrings.Free;
|
|
|
|
|
NewStrings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
function GradTitle(str: string): string;
|
|
|
|
|
var
|
|
|
|
|
p: integer;
|
|
|
|
|
begin
|
|
|
|
|
p := pos('{', str);
|
|
|
|
|
GradTitle := Trim(copy(str, 1, p - 1));
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{ ********************************* File ************************************* }
|
|
|
|
|
|
|
|
|
|
function EntryExists(En, Fl: string): boolean;
|
|
|
|
|
{ Searches for existing identifier in parameter files }
|
|
|
|
|
var
|
|
|
|
|
FStrings: TStringList;
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
|
|
|
|
if FileExists(Fl) then
|
|
|
|
|
begin
|
|
|
|
|
FStrings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
FStrings.LoadFromFile(Fl);
|
|
|
|
|
for i := 0 to FStrings.Count - 1 do
|
|
|
|
|
if Pos(LowerCase(En) + ' {', Lowercase(FStrings[i])) <> 0 then
|
|
|
|
|
Result := True;
|
|
|
|
|
finally
|
|
|
|
|
FStrings.Free;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
Result := False;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
function CleanXMLName(ident: string): string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 1 to Length(ident) do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ident[i] = '*' then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ident[i] := '_'
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else if ident[i] = '"' then
|
|
|
|
|
ident[i] := #39;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
Result := ident;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
function CleanIdentifier(ident: string): string;
|
|
|
|
|
{ Strips unwanted characters from an identifier}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 1 to Length(ident) do
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (ident[i] = #32) or (ident[i] = '}') or (ident[i] = '{') then
|
|
|
|
|
ident[i] := '_';
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Result := ident;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function CleanUPRTitle(ident: string): string;
|
|
|
|
|
{ Strips braces but leave spaces }
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
for i := 1 to Length(ident) do
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (ident[i] = '}') or (ident[i] = '{') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ident[i] := '_';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Result := ident;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function DeleteEntry(Entry, FileName: string): boolean;
|
|
|
|
|
{ Deletes an entry from a multi-entry file }
|
|
|
|
|
var
|
|
|
|
|
Strings: TStringList;
|
|
|
|
|
p, i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
i := 0;
|
|
|
|
|
Strings.LoadFromFile(FileName);
|
|
|
|
|
while Pos(Entry + ' ', Trim(Strings[i])) <> 1 do
|
|
|
|
|
begin
|
|
|
|
|
inc(i);
|
|
|
|
|
end;
|
|
|
|
|
repeat
|
|
|
|
|
p := Pos('}', Strings[i]);
|
|
|
|
|
Strings.Delete(i);
|
|
|
|
|
until p <> 0;
|
|
|
|
|
if (i < Strings.Count) and (Trim(Strings[i]) = '') then Strings.Delete(i);
|
|
|
|
|
Strings.SaveToFile(FileName);
|
|
|
|
|
finally
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function SaveUPR(Entry, FileName: string): boolean;
|
|
|
|
|
{ Saves UF parameter to end of file }
|
|
|
|
|
var
|
|
|
|
|
UPRFile: TextFile;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
|
|
|
|
try
|
|
|
|
|
AssignFile(UPRFile, FileName);
|
|
|
|
|
if FileExists(FileName) then
|
|
|
|
|
begin
|
|
|
|
|
if EntryExists(Entry, FileName) then DeleteEntry(Entry, FileName);
|
|
|
|
|
Append(UPRFile);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
ReWrite(UPRFile);
|
|
|
|
|
WriteLn(UPRFile, MainForm.UPRString(MainCp, Entry));
|
|
|
|
|
CloseFile(UPRFile);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
except on EInOutError do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(* // AV: outdated, for affine coefs only
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function IFSToString(cp: TControlPoint; Title: string): string;
|
|
|
|
|
{ Creates a string containing a formated IFS parameter set }
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
a, b, c, d, e, f, p: double;
|
|
|
|
|
Strings: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Strings.Add(CleanIdentifier(Title) + ' {');
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
begin
|
|
|
|
|
a := cp.xform[i].c[0][0];
|
|
|
|
|
b := cp.xform[i].c[0][1];
|
|
|
|
|
c := cp.xform[i].c[1][0];
|
|
|
|
|
d := cp.xform[i].c[1][1];
|
|
|
|
|
e := cp.xform[i].c[2][0];
|
|
|
|
|
f := cp.xform[i].c[2][1];
|
|
|
|
|
p := cp.xform[i].density;
|
|
|
|
|
Strings.Add(Format('%.6g %.6g %.6g %.6g %.6g %.6g %.6g',
|
|
|
|
|
[a, b, c, d, e, f, p]));
|
|
|
|
|
end;
|
|
|
|
|
Strings.Add('}');
|
|
|
|
|
IFSToString := Strings.Text;
|
|
|
|
|
finally
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure RotateCMapHue(var cp: TControlPoint); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: byte;
|
|
|
|
|
h, s, v: real;
|
|
|
|
|
hue: double;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
hue := cp.hue_rotation;
|
|
|
|
|
if (hue > 0) and (hue < 1) then // has visual effect
|
|
|
|
|
for i := 0 to 255 do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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]);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.SaveFlame(cp1: TControlPoint; title, filename: string): boolean;
|
|
|
|
|
{ Saves Flame parameters to end of file }
|
|
|
|
|
var
|
|
|
|
|
IFile: TextFile;
|
|
|
|
|
sl: TStringList;
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
|
|
|
|
try
|
|
|
|
|
AssignFile(IFile, filename);
|
|
|
|
|
if FileExists(filename) then
|
|
|
|
|
begin
|
|
|
|
|
if EntryExists(title, filename) then DeleteEntry(title, fileName);
|
|
|
|
|
Append(IFile);
|
|
|
|
|
end
|
|
|
|
|
else ReWrite(IFile);
|
|
|
|
|
|
|
|
|
|
sl := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
cp1.SaveToStringList(sl);
|
|
|
|
|
WriteLn(IFile, title + ' {');
|
|
|
|
|
write(IFile, sl.Text);
|
|
|
|
|
WriteLn(IFile, 'palette:');
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
WriteLn(IFile, IntToStr(cp1.cmap[i][0]) + ' ' +
|
|
|
|
|
IntToStr(cp1.cmap[i][1]) + ' ' +
|
|
|
|
|
IntToStr(cp1.cmap[i][2]))
|
|
|
|
|
end;
|
|
|
|
|
WriteLn(IFile, ' }');
|
|
|
|
|
finally
|
|
|
|
|
sl.free
|
|
|
|
|
end;
|
|
|
|
|
WriteLn(IFile, ' ');
|
|
|
|
|
CloseFile(IFile);
|
|
|
|
|
|
|
|
|
|
except on EInOutError do
|
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function ColorToXmlCompact(cp1: TControlPoint): string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Result := ' <palette count="256" format="RGB">';
|
|
|
|
|
for i := 0 to 255 do begin
|
|
|
|
|
if ((i and 7) = 0) then Result := Result + #13#10 + ' ';
|
|
|
|
|
Result := Result + IntToHex(cp1.cmap[i, 0],2)
|
|
|
|
|
+ IntToHex(cp1.cmap[i, 1],2)
|
|
|
|
|
+ IntToHex(cp1.cmap[i, 2],2);
|
|
|
|
|
end;
|
|
|
|
|
Result := Result + #13#10 + ' </palette>';
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
function ColorToXml(cp1: TControlPoint): string;
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Result := '';
|
|
|
|
|
for i := 0 to 255 do begin
|
|
|
|
|
Result := Result + ' <color index="' + IntToStr(i) +
|
|
|
|
|
'" rgb="' + IntToStr(cp1.cmap[i, 0]) + ' ' +
|
|
|
|
|
IntToStr(cp1.cmap[i, 1]) + ' ' +
|
|
|
|
|
IntToStr(cp1.cmap[i, 2]) + '"/>' + #13#10;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//************ AV: working with embedded PNG-parameters ***********************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.ImportFromPNGClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
OpenDialog.Title := TextByKey('common-open-apoimage');
|
|
|
|
|
OpenDialog.Filter := TextByKey('common-filter-png') + ' |*.png';
|
|
|
|
|
OpenDialog.InitialDir := ParamFolder;
|
|
|
|
|
OpenDialog.FileName := '';
|
|
|
|
|
if OpenDialog.Execute then
|
|
|
|
|
ImportThumbnailPNG(OpenDialog.FileName);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ImportThumbnailPNG(FileName: string);
|
|
|
|
|
var
|
|
|
|
|
flameXML: string;
|
|
|
|
|
begin
|
|
|
|
|
flameXML := MainForm.LoadXMLFlameTextPNG(FileName);
|
|
|
|
|
if flameXML <> '' then
|
|
|
|
|
begin
|
|
|
|
|
try
|
|
|
|
|
PasteFlameXML(flameXML);
|
|
|
|
|
except
|
|
|
|
|
Application.MessageBox(PChar(Format(TextByKey('common-openpngerror1'),
|
2022-06-23 06:22:32 -04:00
|
|
|
|
[ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.LoadXMLFlameTextPNG(FileName: string): string;
|
|
|
|
|
var
|
|
|
|
|
PngObject: TPNGObject;
|
|
|
|
|
ChunkList: TPngList;
|
|
|
|
|
TextChunk: TChunkTEXT;
|
|
|
|
|
flameXML: string;
|
|
|
|
|
begin
|
|
|
|
|
Result := '';
|
|
|
|
|
PngObject := TPngObject.Create;
|
|
|
|
|
try
|
|
|
|
|
PngObject.LoadFromFile(FileName);
|
|
|
|
|
ChunkList := PngObject.Chunks;
|
|
|
|
|
if ChunkList <> nil then
|
|
|
|
|
begin
|
|
|
|
|
TextChunk := ChunkList.FindChunk(TChunkTEXT) as TChunkTEXT;
|
|
|
|
|
// iterate through text chunks until 'ApoFlame' keyword is found
|
|
|
|
|
while TextChunk <> nil do
|
|
|
|
|
begin
|
|
|
|
|
if TextChunk.Keyword = 'ApoFlame' then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
flameXML := string(TextChunk.Text);
|
|
|
|
|
if FindFlameXML(flameXML, '') > 0 then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
PngObject.Free; // AV: free the memory if search is succeed
|
|
|
|
|
Exit(flameXML); // AV: XML-flame is found
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
break;
|
|
|
|
|
end else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ChunkList.RemoveChunk(TextChunk); // AV: text is not an XML-flame
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: XML-parameters are not found
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Application.MessageBox(PChar(Format(TextByKey('common-openpngerror2'),
|
2022-06-23 06:22:32 -04:00
|
|
|
|
[ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
except // AV: error in reading parameters
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Application.MessageBox(PChar(Format(TextByKey('common-openpngerror3'),
|
2022-06-23 06:22:32 -04:00
|
|
|
|
[ExtractFileName(FileName)])), ApophysisSVN, MB_ICONWARNING or MB_OK);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
PngObject.Free; // AV: free the memory if search is failed
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//*************************************************************************//
|
|
|
|
|
(*
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function GetThumbnailBase64(const cp1: TControlPoint) : string;
|
|
|
|
|
var
|
|
|
|
|
st: TMemoryStream;
|
|
|
|
|
tempcp : TControlPoint;
|
|
|
|
|
render : TRenderer;
|
|
|
|
|
buffer : array of byte;
|
|
|
|
|
base64 : string;
|
|
|
|
|
size : integer;
|
|
|
|
|
bmp : TJPegImage;
|
|
|
|
|
w, h, r: double;
|
|
|
|
|
begin
|
|
|
|
|
w := cp1.Width;
|
|
|
|
|
h := cp1.Height;
|
|
|
|
|
r := w / h;
|
|
|
|
|
if (w < h) then
|
|
|
|
|
begin
|
|
|
|
|
w := r * ThumbnailSize;
|
|
|
|
|
h := ThumbnailSize;
|
|
|
|
|
end else if (w > h) then
|
|
|
|
|
begin
|
|
|
|
|
h := ThumbnailSize / r;
|
|
|
|
|
w := ThumbnailSize;
|
|
|
|
|
end else
|
|
|
|
|
begin
|
|
|
|
|
w := ThumbnailSize;
|
|
|
|
|
h := ThumbnailSize;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
render := TRenderer.Create;
|
|
|
|
|
tempcp := TControlPoint.create;
|
|
|
|
|
tempcp.Copy(cp1);
|
|
|
|
|
|
|
|
|
|
tempcp.AdjustScale(round(w), round(h));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// tempcp.Width := round(w);
|
|
|
|
|
// tempcp.Height := round(h);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
tempcp.spatial_oversample := defOversample;
|
|
|
|
|
tempcp.spatial_filter_radius := defFilterRadius;
|
|
|
|
|
tempcp.sample_density := 10;
|
|
|
|
|
|
|
|
|
|
render.SetCP(tempcp);
|
|
|
|
|
render.Render;
|
|
|
|
|
|
|
|
|
|
st := TMemoryStream.Create;
|
|
|
|
|
bmp := TJpegImage.Create;
|
|
|
|
|
bmp.Assign(render.GetImage);
|
|
|
|
|
bmp.SaveToStream(st);
|
|
|
|
|
size := st.Size;
|
|
|
|
|
SetLength(buffer, size);
|
|
|
|
|
st.Seek(0, soBeginning);
|
|
|
|
|
|
|
|
|
|
st.ReadBuffer(buffer[0], length(buffer));
|
|
|
|
|
base64 := B64Encode(TBinArray(buffer), length(buffer));
|
|
|
|
|
|
|
|
|
|
tempcp.Free;
|
|
|
|
|
render.Free;
|
|
|
|
|
st.Free;
|
|
|
|
|
bmp.Free;
|
|
|
|
|
|
|
|
|
|
result := base64;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: added default parameter values to get rid of duplicated code
|
|
|
|
|
function FlameToXML(const cp1: TControlPoint; exporting: boolean = false; title: string = ''): string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
t, i: integer;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList: TStringList;
|
|
|
|
|
x, y: double;
|
|
|
|
|
parameters: string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
curves, str, cpName: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
FileList := TStringList.create;
|
|
|
|
|
x := cp1.center[0];
|
|
|
|
|
y := cp1.center[1];
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if title = '' then // AV
|
|
|
|
|
cpName := CleanXMLName(cp1.name)
|
|
|
|
|
else
|
|
|
|
|
cpName := CleanXMLName(title);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
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 // AV
|
|
|
|
|
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 exporting then parameters := parameters +
|
|
|
|
|
format('temporal_samples="%d" ', [cp1.jitters]);
|
|
|
|
|
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]);
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Add('<flame name="' + cpName + '" ' + parameters + '>');
|
|
|
|
|
|
|
|
|
|
if cp1.comment <> '' then FileList.Add('<!--' + cp1.comment + '-->'); // AV
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{ 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;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
|
|
|
|
// AV: too bugged... and not extremely useful thing
|
|
|
|
|
if (embedthumb and EmbedThumbnails) then begin
|
2022-03-08 12:25:51 -05:00
|
|
|
|
xdata := GetThumbnailBase64(cp1);
|
|
|
|
|
buf := '';
|
|
|
|
|
for i := 1 to length(xdata) do begin
|
|
|
|
|
buf := buf + xdata[i];
|
|
|
|
|
if (length(buf) = 150) then begin
|
|
|
|
|
FileList.Add(' <xdata content="' + buf + '" />');
|
|
|
|
|
buf := '';
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
if (Length(buf) > 0) then FileList.Add(' <xdata content="' + buf + '" />');
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
{ Write palette data }
|
|
|
|
|
if exporting or OldPaletteFormat then
|
|
|
|
|
FileList.Add(ColorToXml(cp1))
|
|
|
|
|
else
|
|
|
|
|
FileList.Add(ColorToXmlCompact(cp1));
|
|
|
|
|
|
|
|
|
|
FileList.Add('</flame>');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Result := FileList.text;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
finally
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Free;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function RemoveExt(filename: string): string;
|
|
|
|
|
var
|
|
|
|
|
ext: string;
|
|
|
|
|
p: integer;
|
|
|
|
|
begin
|
|
|
|
|
filename := ExtractFileName(filename);
|
|
|
|
|
ext := ExtractFileExt(filename);
|
|
|
|
|
p := Pos(ext, filename);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Result := Copy(filename, 1, p - 1); // AV: 1 <-- 0
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function XMLEntryExists(title, filename: string): boolean;
|
|
|
|
|
var
|
|
|
|
|
FileList: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
Result := false;
|
|
|
|
|
if FileExists(filename) then
|
|
|
|
|
begin
|
|
|
|
|
FileList := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
FileList.LoadFromFile(filename);
|
|
|
|
|
if pos('<flame name="' + title + '"', FileList.Text) <> 0 then Result := true;
|
|
|
|
|
finally
|
|
|
|
|
FileList.Free;
|
|
|
|
|
end
|
|
|
|
|
end else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Result := false;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure DeleteXMLEntry(title, filename: string);
|
|
|
|
|
var
|
|
|
|
|
Strings: TStringList;
|
|
|
|
|
p, i: integer;
|
|
|
|
|
begin
|
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
i := 0;
|
|
|
|
|
Strings.LoadFromFile(FileName);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{ 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('<flame name="' + title + '"', Trim(Strings[i])) = 0 do // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
inc(i);
|
|
|
|
|
|
|
|
|
|
p := 0;
|
|
|
|
|
while p = 0 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('</flame>', Strings[i]);
|
|
|
|
|
Strings.Delete(i);
|
|
|
|
|
end;
|
|
|
|
|
Strings.SaveToFile(FileName);
|
|
|
|
|
finally
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function TMainForm.SaveXMLFlame(const cp1: TControlPoint; title, filename: string): boolean;
|
|
|
|
|
{ Saves Flame parameters to end of file }
|
|
|
|
|
var
|
|
|
|
|
Tag: string;
|
|
|
|
|
FileList: TStringList;
|
|
|
|
|
i, p: integer;
|
|
|
|
|
bakname: string;
|
|
|
|
|
begin
|
|
|
|
|
Tag := RemoveExt(filename);
|
|
|
|
|
Result := True;
|
|
|
|
|
try
|
|
|
|
|
if FileExists(filename) then
|
|
|
|
|
begin
|
|
|
|
|
bakname := ChangeFileExt(filename, '.bak');
|
|
|
|
|
if FileExists(bakname) then DeleteFile(bakname);
|
|
|
|
|
RenameFile(filename, bakname);
|
|
|
|
|
|
|
|
|
|
FileList := TStringList.create;
|
|
|
|
|
try
|
|
|
|
|
FileList.LoadFromFile(bakname);
|
|
|
|
|
|
|
|
|
|
if Pos('<flame name="' + title + '"', FileList.Text) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
i := 0;
|
|
|
|
|
while Pos('<flame name="' + title + '"', Trim(FileList[i])) = 0 do
|
|
|
|
|
inc(i);
|
|
|
|
|
|
|
|
|
|
p := 0;
|
|
|
|
|
while p = 0 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('</flame>', FileList[i]);
|
|
|
|
|
FileList.Delete(i);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// fix first line
|
|
|
|
|
if (FileList.Count > 0) then begin
|
|
|
|
|
//FileList[0] := '<flames name="' + Tag + '">';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: fix fixed :-) Apo 2.09 uses capital F in this tag
|
|
|
|
|
if (pos('<flames name', LowerCase(FileList[0])) <> 0) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList[0] := '<flames name="' + Tag + '">'
|
|
|
|
|
else // single-flame support
|
|
|
|
|
FileList.Insert(0, '<flames name="' + Tag + '">');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
end
|
|
|
|
|
else // AV: if the existing file is empty
|
|
|
|
|
FileList.Add('<flames name="' + Tag + '">'); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if FileList.Count > 2 then
|
|
|
|
|
begin
|
|
|
|
|
// AV fix last line :-)
|
|
|
|
|
if (pos('</flames>', FileList[FileList.Count - 1]) = 0) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Add('</flames>');
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if pos('<flame ', FileList.text) <> 0 then
|
|
|
|
|
repeat
|
|
|
|
|
FileList.Delete(FileList.Count - 1);
|
|
|
|
|
until (Pos('</flame>', FileList[FileList.count - 1]) <> 0)
|
|
|
|
|
else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
repeat // AV: now condition will be true anyway
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList.Delete(FileList.Count - 1);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
until (Pos('</flames>', FileList[FileList.count - 1]) <> 0) or
|
|
|
|
|
(Pos('<' + Tag + '>', FileList[FileList.count - 1]) <> 0);
|
|
|
|
|
end else if (FileList.count > 1) then // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList.Delete(FileList.Count - 1);
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Add(Trim(FlameToXML(cp1, false, title)));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList.Add('</flames>');
|
|
|
|
|
FileList.SaveToFile(filename);
|
|
|
|
|
|
|
|
|
|
finally
|
|
|
|
|
if FileExists(bakname) and not FileExists(filename) then
|
|
|
|
|
RenameFile(bakname, filename);
|
|
|
|
|
|
|
|
|
|
FileList.Free;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
// New file ... easy
|
|
|
|
|
FileList := TStringList.Create;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Add('<flames name="' + Tag + '">');
|
|
|
|
|
FileList.Add(FlameToXML(cp1, false, title));
|
|
|
|
|
FileList.Add('</flames>');
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList.SaveToFile(filename, TEncoding.UTF8);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Free;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
except // AV: fixed multi-updating of the flame
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Result := False; // AV: first assign the value, then exit
|
2022-06-23 06:22:32 -04:00
|
|
|
|
raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.SaveGradient(Gradient, Title, FileName: string): boolean;
|
|
|
|
|
{ Saves gradient parameters to end of file }
|
|
|
|
|
var
|
|
|
|
|
IFile: TextFile;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
|
|
|
|
try
|
|
|
|
|
AssignFile(IFile, FileName);
|
|
|
|
|
if FileExists(FileName) then
|
|
|
|
|
begin
|
|
|
|
|
if EntryExists(Title, FileName) then DeleteEntry(Title, FileName);
|
|
|
|
|
Append(IFile);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
ReWrite(IFile);
|
|
|
|
|
Write(IFile, Gradient);
|
|
|
|
|
WriteLn(IFile, ' ');
|
|
|
|
|
CloseFile(IFile);
|
|
|
|
|
except on EInOutError do
|
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
|
|
|
|
raise Exception.CreateFmt(TextByKey('common-genericsavefailure'), [FileName]); // AV
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function RenameIFS(OldIdent: string; var NewIdent: string): boolean;
|
|
|
|
|
{ Renames an IFS parameter set in a file }
|
|
|
|
|
var
|
|
|
|
|
Strings: TStringList;
|
|
|
|
|
p, i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
NewIdent := CleanIdentifier(NewIdent);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
try
|
|
|
|
|
i := 0;
|
|
|
|
|
Strings.LoadFromFile(OpenFile);
|
|
|
|
|
if Pos(OldIdent + ' ', Trim(Strings.Text)) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
while Pos(OldIdent + ' ', Trim(Strings[i])) <> 1 do
|
|
|
|
|
begin
|
|
|
|
|
inc(i);
|
|
|
|
|
end;
|
|
|
|
|
p := Pos('{', Strings[i]);
|
|
|
|
|
s := Copy(Strings[i], p, Length(Strings[i]) - p + 1);
|
|
|
|
|
Strings[i] := NewIdent + ' ' + s;
|
|
|
|
|
Strings.SaveToFile(OpenFile);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
Result := False;
|
|
|
|
|
except on Exception do Result := False;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function RenameXML(OldIdent: string; var NewIdent: string): boolean;
|
|
|
|
|
{ Renames an XML parameter set in a file }
|
|
|
|
|
var
|
|
|
|
|
Strings: TStringList;
|
|
|
|
|
i: integer;
|
|
|
|
|
bakname: string;
|
|
|
|
|
begin
|
|
|
|
|
Result := True;
|
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
try
|
|
|
|
|
i := 0;
|
|
|
|
|
Strings.LoadFromFile(OpenFile);
|
|
|
|
|
if Pos('name="' + OldIdent + '"', Strings.Text) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
while Pos('name="' + OldIdent + '"', Strings[i]) = 0 do
|
|
|
|
|
begin
|
|
|
|
|
inc(i);
|
|
|
|
|
end;
|
|
|
|
|
Strings[i] := StringReplace(Strings[i], OldIdent, NewIdent, []);
|
|
|
|
|
|
|
|
|
|
bakname := ChangeFileExt(OpenFile, '.bak');
|
|
|
|
|
if FileExists(bakname) then DeleteFile(bakname);
|
|
|
|
|
RenameFile(OpenFile, bakname);
|
|
|
|
|
|
|
|
|
|
Strings.SaveToFile(OpenFile);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
Result := False;
|
|
|
|
|
except on Exception do
|
|
|
|
|
Result := False;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
procedure ListIFS(FileName: string; sel: integer);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{ AV: List identifiers in Undo file }
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
|
|
|
|
i, p: integer;
|
|
|
|
|
Title: string;
|
|
|
|
|
ListItem: TListItem;
|
|
|
|
|
FStrings: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
MainForm.ParseLoadingBatch := true;
|
|
|
|
|
FStrings := TStringList.Create;
|
|
|
|
|
FStrings.LoadFromFile(FileName);
|
|
|
|
|
try
|
|
|
|
|
MainForm.ListView1.Items.BeginUpdate;
|
|
|
|
|
MainForm.ListView1.Items.Clear;
|
|
|
|
|
if (Pos('{', FStrings.Text) <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to FStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('{', FStrings[i]);
|
|
|
|
|
// AV: why do we use 2-nd condition? A rudiment from 3D-hack?
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (p <> 0) {and (Pos('(3D)', FStrings[i]) = 0)} then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
Title := Trim(Copy(FStrings[i], 1, p - 1));
|
|
|
|
|
if Title <> '' then
|
|
|
|
|
begin { Otherwise bad format }
|
|
|
|
|
if ((i mod 5) = 0) then
|
|
|
|
|
MainForm.LoadSaveProgress.Position :=
|
|
|
|
|
round(100 * i / FStrings.Count); // AV
|
|
|
|
|
ListItem := MainForm.ListView1.Items.Add;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ListItem.Caption := Title;
|
|
|
|
|
// AV: hack - remember the creation order in an unused field
|
|
|
|
|
ListItem.OverlayIndex := MainForm.ListView1.Items.Count;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
MainForm.LoadSaveProgress.Position := 0; // AV
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ClassicListMode then // AV: thumbs are useless
|
|
|
|
|
GeneratingThumbs := False
|
|
|
|
|
else // AV: added thumbnails support for Undo list
|
|
|
|
|
MainForm.RunThumbnailThread;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
with MainForm.ListView1 do
|
|
|
|
|
if Items.Count > 0 then // AV
|
|
|
|
|
case sel of
|
|
|
|
|
0: Selected := Items[Items.Count - 1];
|
|
|
|
|
1: Selected := Items[0];
|
|
|
|
|
end;
|
|
|
|
|
finally
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MainForm.ListView1.Items.EndUpdate;
|
|
|
|
|
FStrings.Free;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
MainForm.ParseLoadingBatch := false; // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
if AnimateForm.Visible then AnimateForm.UpdateControls; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure ListFlames(FileName: string; sel: integer);
|
|
|
|
|
{ List identifiers in file }
|
|
|
|
|
var
|
|
|
|
|
i, p: integer;
|
|
|
|
|
Title: string;
|
|
|
|
|
ListItem: TListItem;
|
|
|
|
|
FStrings: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
FStrings := TStringList.Create;
|
|
|
|
|
FStrings.LoadFromFile(FileName);
|
|
|
|
|
try
|
|
|
|
|
MainForm.ListView1.Items.BeginUpdate;
|
|
|
|
|
MainForm.ListView1.Items.Clear;
|
|
|
|
|
if (Pos('{', FStrings.Text) <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to FStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('{', FStrings[i]);
|
|
|
|
|
if (p <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
Title := Trim(Copy(FStrings[i], 1, p - 1));
|
|
|
|
|
if Title <> '' then
|
|
|
|
|
begin { Otherwise bad format }
|
|
|
|
|
ListItem := MainForm.ListView1.Items.Add;
|
|
|
|
|
Listitem.Caption := Trim(Copy(FStrings[i], 1, p - 1));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
MainForm.ListView1.Items.EndUpdate;
|
|
|
|
|
if sel = 1 then MainForm.ListView1.Selected := MainForm.ListView1.Items[0];
|
|
|
|
|
finally
|
|
|
|
|
FStrings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
{ ****************************** Display ************************************ }
|
|
|
|
|
|
|
|
|
|
procedure Trace1(const str: string);
|
|
|
|
|
begin
|
|
|
|
|
if TraceLevel >= 1 then
|
|
|
|
|
TraceForm.MainTrace.Lines.Add('. ' + str);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure Trace2(const str: string);
|
|
|
|
|
begin
|
|
|
|
|
if TraceLevel >= 2 then
|
|
|
|
|
TraceForm.MainTrace.Lines.Add('. . ' + str);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.HandleThreadCompletion(var Message: TMessage);
|
|
|
|
|
var
|
|
|
|
|
oldscale: double;
|
|
|
|
|
begin
|
|
|
|
|
Trace2(MsgComplete + IntToStr(message.LParam));
|
|
|
|
|
if not Assigned(Renderer) then begin
|
|
|
|
|
Trace2(MsgNotAssigned);
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
if Renderer.ThreadID <> message.LParam then begin
|
|
|
|
|
Trace2(MsgAnotherRunning);
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
Image.Cursor := crDefault;
|
|
|
|
|
|
|
|
|
|
if assigned(FViewImage) then begin
|
|
|
|
|
oldscale := FViewImage.Width / Image.Width;
|
|
|
|
|
FViewImage.Free;
|
|
|
|
|
end
|
|
|
|
|
else oldscale := FViewScale;
|
|
|
|
|
|
|
|
|
|
FViewImage := Renderer.GetTransparentImage;
|
|
|
|
|
|
|
|
|
|
if (FViewImage <> nil) and (FViewImage.Width > 0) then begin
|
|
|
|
|
FViewScale := FViewImage.Width / Image.Width;
|
|
|
|
|
|
|
|
|
|
FViewPos.X := FViewScale/oldscale * (FViewPos.X - FViewOldPos.X);
|
|
|
|
|
FViewPos.Y := FViewScale/oldscale * (FViewPos.Y - FViewOldPos.Y);
|
|
|
|
|
|
|
|
|
|
DrawImageView;
|
|
|
|
|
{
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msZoomWindowMove: FMouseMoveState := msZoomWindow;
|
|
|
|
|
msZoomOutWindowMove: FMouseMoveState := msZoomOutWindow;
|
|
|
|
|
// msDragMove: FMouseMoveState := msDrag;
|
|
|
|
|
msRotateMove: FMouseMoveState := msRotate;
|
|
|
|
|
end;
|
|
|
|
|
}
|
|
|
|
|
if FMouseMoveState in [msZoomWindowMove, msZoomOutWindowMove, msRotateMove] then
|
|
|
|
|
DrawSelection := false;
|
|
|
|
|
|
|
|
|
|
Trace1(TimeToStr(Now) + ' : Render complete');
|
|
|
|
|
Renderer.ShowSmallStats;
|
|
|
|
|
end
|
|
|
|
|
else Trace2('WARNING: No image rendered!');
|
|
|
|
|
|
|
|
|
|
Renderer.WaitFor;
|
|
|
|
|
Trace2('Destroying RenderThread #' + IntToStr(Renderer.ThreadID));
|
|
|
|
|
Renderer.Free;
|
|
|
|
|
Renderer := nil;
|
|
|
|
|
Trace1('');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.HandleThreadTermination(var Message: TMessage);
|
|
|
|
|
begin
|
|
|
|
|
Trace2(MsgTerminated + IntToStr(message.LParam));
|
|
|
|
|
if not Assigned(Renderer) then begin
|
|
|
|
|
Trace2(MsgNotAssigned);
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
if Renderer.ThreadID <> message.LParam then begin
|
|
|
|
|
Trace2(MsgAnotherRunning);
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
Image.Cursor := crDefault;
|
|
|
|
|
Trace2(' Render aborted');
|
|
|
|
|
|
|
|
|
|
Trace2('Destroying RenderThread #' + IntToStr(Renderer.ThreadID));
|
|
|
|
|
Renderer.Free;
|
|
|
|
|
Renderer := nil;
|
|
|
|
|
Trace1('');
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.DrawPreview;
|
|
|
|
|
var
|
|
|
|
|
cp : TControlPoint;
|
|
|
|
|
Render : TRenderer;
|
|
|
|
|
BM: TBitmap;
|
|
|
|
|
begin
|
|
|
|
|
Render := TRenderer.Create;
|
|
|
|
|
bm := TBitmap.Create;
|
|
|
|
|
|
|
|
|
|
cp := MainCP.Clone;
|
|
|
|
|
|
|
|
|
|
cp.sample_density := 1;
|
|
|
|
|
cp.spatial_oversample := 1;
|
|
|
|
|
cp.spatial_filter_radius := 1;
|
|
|
|
|
|
|
|
|
|
//Render.NrThreads := NrTreads;
|
|
|
|
|
Render.SetCP(cp);
|
|
|
|
|
Render.Render;
|
|
|
|
|
BM.Assign(Render.GetImage);
|
|
|
|
|
Image.Picture.Graphic := bm;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.DrawFlame;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
const
|
|
|
|
|
{$ifdef CPUX86}
|
|
|
|
|
bs = 16;
|
|
|
|
|
{$else}
|
|
|
|
|
bs = 32;
|
|
|
|
|
{$endif}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
|
|
|
|
GlobalMemoryInfo: TMemoryStatus; // holds the global memory status information
|
|
|
|
|
RenderCP: TControlPoint;
|
|
|
|
|
Mem, ApproxMem: cardinal;
|
|
|
|
|
begin
|
|
|
|
|
RedrawTimer.Enabled := False;
|
|
|
|
|
if Assigned(Renderer) then begin
|
|
|
|
|
assert(Renderer.Suspended = false);
|
|
|
|
|
|
|
|
|
|
Trace2('Killing previous RenderThread #' + inttostr(Renderer.ThreadID));
|
|
|
|
|
Renderer.Terminate;
|
|
|
|
|
Renderer.WaitFor;
|
|
|
|
|
Trace2('Destroying RenderThread #' + IntToStr(Renderer.ThreadID));
|
|
|
|
|
|
|
|
|
|
Renderer.Free;
|
|
|
|
|
Renderer := nil;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if not Assigned(Renderer) then
|
|
|
|
|
begin
|
|
|
|
|
if EditForm.Visible and ((MainCP.Width / MainCP.Height) <> (EditForm.cp.Width / EditForm.cp.Height))
|
|
|
|
|
then EditForm.UpdateDisplay(true); // preview only?
|
|
|
|
|
if AdjustForm.Visible then AdjustForm.UpdateDisplay(true); // preview only!
|
|
|
|
|
|
|
|
|
|
RenderCP := MainCP.Clone;
|
|
|
|
|
RenderCp.AdjustScale(Image.width, Image.height);
|
|
|
|
|
|
|
|
|
|
RenderCP.sample_density := defSampleDensity;
|
|
|
|
|
// oversample and filter are just slowing us down here...
|
|
|
|
|
RenderCP.spatial_oversample := 1; // defOversample;
|
|
|
|
|
RenderCP.spatial_filter_radius := 0.001; {?} //defFilterRadius;
|
|
|
|
|
RenderCP.Transparency := true; // always generate transparency here
|
|
|
|
|
|
|
|
|
|
GlobalMemoryInfo.dwLength := SizeOf(GlobalMemoryInfo);
|
|
|
|
|
GlobalMemoryStatus(GlobalMemoryInfo);
|
|
|
|
|
Mem := GlobalMemoryInfo.dwAvailPhys;
|
|
|
|
|
|
|
|
|
|
// if Output.Lines.Count >= 1000 then Output.Lines.Clear;
|
|
|
|
|
Trace1('--- Previewing "' + RenderCP.name + '" ---');
|
|
|
|
|
Trace1(Format(' Available memory: %f Mb', [Mem / (1024*1024)]));
|
|
|
|
|
ApproxMem := int64(RenderCp.Width) * int64(RenderCp.Height) {* sqr(Oversample)}
|
|
|
|
|
* (bs + 4 + 4); // +4 for temp image(s)...?
|
|
|
|
|
assert(MainPreviewScale <> 0);
|
|
|
|
|
if ApproxMem * sqr(MainPreviewScale) < Mem then begin
|
|
|
|
|
if ExtendMainPreview then begin
|
|
|
|
|
RenderCP.sample_density := RenderCP.sample_density / sqr(MainPreviewScale);
|
|
|
|
|
RenderCP.Width := round(RenderCp.Width * MainPreviewScale);
|
|
|
|
|
RenderCP.Height := round(RenderCp.Height * MainPreviewScale);
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else Trace1('WARNING: Not enough memory for extended preview!');
|
|
|
|
|
if ApproxMem > Mem then
|
|
|
|
|
Trace1('OUTRAGEOUS: Not enough memory even for normal preview! :-(');
|
|
|
|
|
Trace1(Format(' Size: %dx%d, Quality: %f',
|
|
|
|
|
[RenderCP.Width, RenderCP.Height, RenderCP.sample_density]));
|
|
|
|
|
FViewOldPos.x := FViewPos.x;
|
|
|
|
|
FViewOldPos.y := FViewPos.y;
|
|
|
|
|
StartTime := Now;
|
|
|
|
|
try
|
|
|
|
|
Renderer := TRenderThread.Create;
|
|
|
|
|
Renderer.TargetHandle := MainForm.Handle;
|
|
|
|
|
if TraceLevel > 0 then Renderer.Output := TraceForm.MainTrace.Lines;
|
|
|
|
|
Renderer.OnProgress := OnProgress;
|
|
|
|
|
Renderer.SetCP(RenderCP);
|
|
|
|
|
// Renderer.NrThreads := NrTreads;
|
|
|
|
|
|
|
|
|
|
Trace2('Starting RenderThread #' + inttostr(Renderer.ThreadID));
|
|
|
|
|
Renderer.Resume;
|
|
|
|
|
|
|
|
|
|
Image.Cursor := crAppStart;
|
|
|
|
|
except
|
|
|
|
|
Trace1('ERROR: Cannot start renderer!');
|
|
|
|
|
end;
|
|
|
|
|
RenderCP.Free;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.RandomBatch;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{ Write a series of random flames to a file }
|
2022-03-08 12:25:51 -05:00
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
F: TextFile;
|
|
|
|
|
b, RandFile: string;
|
|
|
|
|
begin
|
|
|
|
|
b := IntToStr(BatchSize);
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RandFile := AppPath + randFilename;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AssignFile(F, RandFile);
|
|
|
|
|
OpenFile := RandFile;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ReWrite(F);
|
|
|
|
|
WriteLn(F, '<flames name="Random Batch">'); // AV: fixed '<random_batch>');
|
|
|
|
|
for i := 0 to BatchSize - 1 do
|
|
|
|
|
begin
|
|
|
|
|
inc(RandomIndex);
|
|
|
|
|
Statusbar.SimpleText := Format(TextByKey('main-status-batchgenerate'), [(i+1), b]);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
if randGradient = 0 then cmap_index := random(NRCMAPS);
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
RandomizeCP(MainCp);
|
|
|
|
|
MainCp.CalcBoundbox;
|
|
|
|
|
MainCp.name := RandomPrefix + RandomDate + '-' + IntToStr(RandomIndex);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Write(F, FlameToXML(MainCp));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
Write(F, '</flames>'); // AV: fixed '</random_batch>');
|
|
|
|
|
CloseFile(F);
|
|
|
|
|
except
|
|
|
|
|
on EInOutError do
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Application.MessageBox(PChar(TextByKey('main-status-batcherror')),
|
|
|
|
|
ApophysisSVN, 16);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainCp.name := '';
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ ******************************** Menu ************************************ }
|
|
|
|
|
|
|
|
|
|
function LoadXMLFlameText(filename, name: string) : string;
|
|
|
|
|
var
|
|
|
|
|
i, p: integer;
|
|
|
|
|
FileStrings: TStringList;
|
|
|
|
|
ParamStrings: TStringList;
|
|
|
|
|
Tokens: TStringList;
|
|
|
|
|
time: integer;
|
|
|
|
|
begin
|
|
|
|
|
time := -1;
|
|
|
|
|
FileStrings := TStringList.Create;
|
|
|
|
|
ParamStrings := TStringList.Create;
|
|
|
|
|
Result := '';
|
|
|
|
|
|
|
|
|
|
if pos('*untitled', name) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
Tokens := TStringList.Create;
|
|
|
|
|
GetTokens(name, tokens);
|
|
|
|
|
time := StrToInt(tokens[1]);
|
|
|
|
|
Tokens.free;
|
|
|
|
|
end;
|
|
|
|
|
try
|
|
|
|
|
{ if UpperCase(ExtractFileExt(filename)) = '.PNG' then
|
|
|
|
|
FileStrings.Text := MainForm.LoadXMLFlameTextPNG(filename)
|
|
|
|
|
else }
|
|
|
|
|
FileStrings.LoadFromFile(filename);
|
|
|
|
|
|
|
|
|
|
for i := 0 to FileStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
pname := '';
|
|
|
|
|
ptime := '';
|
|
|
|
|
p := Pos('<flame ', LowerCase(FileStrings[i]));
|
|
|
|
|
if (p <> 0) then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FileStrings[i])));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainForm.ListXMLScanner.Execute;
|
|
|
|
|
if pname <> '' then
|
|
|
|
|
begin
|
|
|
|
|
if (Trim(pname) = Trim(name)) then
|
|
|
|
|
begin
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
Break;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if ptime <> '' then
|
|
|
|
|
begin
|
|
|
|
|
if StrToInt(ptime) = time then
|
|
|
|
|
begin
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
Break;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
repeat
|
|
|
|
|
inc(i);
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
until pos('</flame>', Lowercase(FileStrings[i])) <> 0;
|
|
|
|
|
|
|
|
|
|
Result := ParamStrings.Text;
|
|
|
|
|
|
|
|
|
|
finally
|
|
|
|
|
FileStrings.free;
|
|
|
|
|
ParamStrings.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function ScanVariations(name:string):boolean;
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i,count: integer;
|
|
|
|
|
vname: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
count := NrVar;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i:=0 to count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
vname := VarNames(i);
|
|
|
|
|
if (vname = name) then
|
|
|
|
|
begin
|
|
|
|
|
Result := true;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to MainForm.SubstSource.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
vname := MainForm.SubstSource[i];
|
|
|
|
|
if (vname = name) then
|
|
|
|
|
begin
|
|
|
|
|
Result := true;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
Result := false;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function ScanVariables(name:string):boolean;
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i, count: integer;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
count := GetNrVariableNames;
|
|
|
|
|
for i :=0 to count - 1 do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
if (GetVariableNameAt(i) = name) then
|
|
|
|
|
begin
|
|
|
|
|
Result := true;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
for i := 0 to MainForm.SubstSource.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
if (MainForm.SubstSource[i] = name) then
|
|
|
|
|
begin
|
|
|
|
|
Result := true;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
Result := false;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuOpenClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
fn: string;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
StopScripter; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
OpenDialog.Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*.xml|'
|
|
|
|
|
+ TextByKey('common-filter-templatefiles') + ' |*.template;*.temp|'
|
|
|
|
|
+ TextByKey('common-filter-undofiles') + '|*.undo;*.apo|'
|
|
|
|
|
+ TextByKey('common-filter-allfiles') + '|*.*';
|
|
|
|
|
OpenDialog.InitialDir := ParamFolder;
|
|
|
|
|
OpenDialog.FileName := '';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
OpenDialog.Title := ''; // AV
|
|
|
|
|
// AV: turn back classic dialog since OpenSaveFileDialog looks ugly then themed
|
|
|
|
|
if OpenDialog.Execute then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
fn := OpenDialog.FileName; // AV
|
|
|
|
|
LastOpenFile := fn;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Maincp.name := '';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParamFolder := ExtractFilePath(fn);
|
|
|
|
|
OpenFile := fn;
|
|
|
|
|
if APP_BUILD = '' then
|
|
|
|
|
MainForm.Caption := AppVersionString + ' - ' + OpenFile
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + OpenFile;
|
|
|
|
|
|
|
|
|
|
fn := UpperCase(ExtractFileExt(fn));
|
|
|
|
|
if (fn = '.UNDO') or (fn = '.APO') then
|
|
|
|
|
begin
|
|
|
|
|
OpenFileType := ftApo; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ListIFS(OpenDialog.FileName, 1);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
OpenFileType := ftXML;
|
|
|
|
|
ListXML(OpenDialog.FileName, 1);
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(*
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.mnuNextClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
with ListView1 do
|
|
|
|
|
if Items.Count <> 0 then
|
|
|
|
|
Selected := Items[(Selected.Index + 1) mod Items.Count];
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuPreviousClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
with ListView1 do
|
|
|
|
|
if Items.Count <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
i := Selected.Index - 1;
|
|
|
|
|
if i < 0 then i := Items.Count - 1;
|
|
|
|
|
Selected := Items[i];
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
*)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuListRenameClick(Sender: TObject);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ListView1.Selected <> nil then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ListView1.Items[ListView1.Selected.Index].EditCaption;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuCopyUPRClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
Clipboard.SetTextBuf(PChar(UPRString(MainCp, Maincp.name)));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuItemDeleteClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
c: boolean;
|
|
|
|
|
begin
|
|
|
|
|
if ListView1.SelCount <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
if ConfirmDelete then
|
|
|
|
|
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])
|
2022-06-23 06:22:32 -04:00
|
|
|
|
+ #32 + TextByKey('common-deletecurrent')), ApophysisSVN, 36) = IDYES
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
|
|
|
|
c := Application.MessageBox(
|
2022-06-23 06:22:32 -04:00
|
|
|
|
PChar(Format(TextByKey('common-confirmdelete'), [ListView1.Selected.Caption])),
|
|
|
|
|
ApophysisSVN, 36) = IDYES
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
c := True;
|
|
|
|
|
if c then
|
|
|
|
|
if ListView1.Focused and (ListView1.SelCount <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
if OpenFileType = ftXML then
|
|
|
|
|
DeleteXMLEntry(ListView1.Selected.Caption, OpenFile)
|
|
|
|
|
else
|
|
|
|
|
DeleteEntry(ListView1.Selected.Caption, OpenFile);
|
|
|
|
|
{
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: do not change the sequence in order to display all icons properly
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (ListView1.Selected.Index >= 0) and (ListView1.Selected.Index < UsedThumbnails.Count)
|
|
|
|
|
and (not ClassicListMode) then
|
|
|
|
|
UsedThumbnails.Delete(ListView1.Selected.Index);
|
|
|
|
|
}
|
|
|
|
|
ListView1.Items.Delete(ListView1.Selected.Index);
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
ListView1.Selected := ListView1.ItemFocused;
|
|
|
|
|
// AV: re-adjust the displayed numbers...
|
|
|
|
|
if EnumerateFlames.Checked then EnumerateFlamesClick(EnumerateFlames);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
if AnimateForm.Visible then AnimateForm.UpdateControls; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
(*
|
|
|
|
|
// AV: I set ListView1.IconOptions.AutoArrange := True;
|
|
|
|
|
// for auto-updating the flame list without redrawing the thumbs.
|
|
|
|
|
// An alternative (but slow) way to do the same thing:
|
|
|
|
|
|
|
|
|
|
if ListView1.Items.Count > 0 then // refresh the list
|
|
|
|
|
begin
|
|
|
|
|
i := ListView1.ItemFocused.Index; // AV
|
|
|
|
|
if OpenFileType = ftXML then
|
|
|
|
|
UpdateThumbnails // AV
|
|
|
|
|
else
|
|
|
|
|
ListIFS(OpenFile, 2); // AV: for undo files
|
|
|
|
|
// AV: now scroll to the nearest item
|
|
|
|
|
i := min(i, ListView1.Items.Count - 1);
|
|
|
|
|
ListView1.Selected := ListView1.Items[i];
|
|
|
|
|
ListView1.Items[i].MakeVisible(true);
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuOptionsClick(Sender: TObject);
|
|
|
|
|
var isSmallThumb: boolean;
|
|
|
|
|
begin
|
|
|
|
|
isSmallThumb := UseSmallThumbnails; // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: update flame ONLY if settings were changed
|
|
|
|
|
if OptionsForm.ShowModal = mrOK then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ConfirmResetUndo then
|
|
|
|
|
ListView1.OnSelectItem := ListViewSelectItem
|
|
|
|
|
else
|
|
|
|
|
ListView1.OnSelectItem := nil;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
DrawImageView;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRefreshThumbClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if (ListView1.Selected = nil) or ParseLoadingBatch then exit;
|
|
|
|
|
RefreshThumbnail; // current only
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuNormalWeightsClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
// TODO: ...something <-- AV: something's done :)
|
|
|
|
|
MainCp.NormalizeProbabilities;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRWeightsClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
maincp.xform[i].density := random;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRandomBatchClick(Sender: TObject);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// StopScripter;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
RandomBatch;
|
|
|
|
|
OpenFile := AppPath + randFilename;
|
|
|
|
|
OpenFileType := ftXML;
|
|
|
|
|
MainForm.Caption := AppVersionString + ' - ' + TextByKey('main-common-randombatch');
|
|
|
|
|
ListXML(OpenFile, 1);
|
|
|
|
|
ListView1.SetFocus; // AV
|
|
|
|
|
if batchsize = 1 then DrawFlame;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function GradientString(c: TColorMap): string;
|
|
|
|
|
var
|
|
|
|
|
strings: TStringList;
|
|
|
|
|
i, j, cl: integer;
|
|
|
|
|
begin
|
|
|
|
|
strings := TStringList.Create;
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
j := round(i * (399 / 255));
|
|
|
|
|
cl := (c[i][2] shl 16) + (c[i][1] shl 8) + (c[i][0]);
|
|
|
|
|
strings.Add(' index=' + IntToStr(j) + ' color=' + intToStr(cl));
|
|
|
|
|
end;
|
|
|
|
|
Result := Strings.Text;
|
|
|
|
|
strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.UPRString(cp1: TControlPoint; Entry: string): string;
|
|
|
|
|
{ Returns a string containing an Ultra Fractal parameter set for copying
|
|
|
|
|
or saving to file }
|
|
|
|
|
var
|
|
|
|
|
IterDensity, m, i, j: integer;
|
|
|
|
|
scale, a, b, c, d, e, f, p, v: double;
|
|
|
|
|
GradStrings, Strings: TStringList;
|
|
|
|
|
rept, cby, smap, sol: string;
|
|
|
|
|
uprcenter: array[0..1] of double; // camera center
|
|
|
|
|
Backcolor: longint;
|
|
|
|
|
xf_str: string;
|
|
|
|
|
begin
|
|
|
|
|
cp1.Prepare;
|
|
|
|
|
uprcenter[0] := cp1.Center[0];
|
|
|
|
|
uprcenter[1] := cp1.Center[1];
|
|
|
|
|
cp1.Width := UPRWidth;
|
|
|
|
|
cp1.Height := UPRHeight;
|
|
|
|
|
scale := power(2, cp1.zoom) * CalcUPRMagn(cp1);
|
|
|
|
|
cp1.center[0] := uprCenter[0];
|
|
|
|
|
cp1.center[1] := uprCenter[1];
|
|
|
|
|
smap := 'no';
|
|
|
|
|
sol := 'no';
|
|
|
|
|
rept := '';
|
|
|
|
|
cby := 'Hit Frequency';
|
|
|
|
|
Strings := TStringList.Create;
|
|
|
|
|
GradStrings := TStringList.Create;
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Strings.Add(CleanIdentifier(Entry) + ' {');
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Strings.Add('fractal:');
|
|
|
|
|
Strings.Add(' title="' + CleanUPRTitle(Entry) +
|
|
|
|
|
'" width=' + IntToStr(UPRWidth) + ' height=' + IntToStr(UPRHeight) + ' layers=1');
|
|
|
|
|
Strings.Add('layer:');
|
|
|
|
|
Strings.Add(' method=linear caption="Background" opacity=100 mergemode=normal');
|
|
|
|
|
Strings.Add('mapping:');
|
|
|
|
|
Strings.Add(' center=' + floatToStr(cp1.center[0]) + '/' + floatToStr(-cp1.center[1]) +
|
|
|
|
|
' magn=' + FloatToStr(scale));
|
|
|
|
|
Strings.Add('formula:');
|
|
|
|
|
Strings.Add(' maxiter=1 filename="' + UPRFormulaFile + '" entry="' + UPRFormulaIdent + '"');
|
|
|
|
|
Strings.Add('inside:');
|
|
|
|
|
Strings.Add(' transfer=none');
|
|
|
|
|
Strings.Add('outside:');
|
|
|
|
|
Strings.Add(' transfer=linear repeat=no ' + 'filename="' + UPRColoringFile + '" entry="'
|
|
|
|
|
+ UPRColoringIdent + '"');
|
|
|
|
|
if (UPRAdjustDensity) and (scale > 1) then
|
|
|
|
|
IterDensity := Trunc(UPRSampleDensity * scale * scale)
|
|
|
|
|
else
|
|
|
|
|
IterDensity := UPRSampleDensity;
|
|
|
|
|
Strings.Add(' p_iter_density=' + IntToStr(IterDensity) + ' p_spat_filt_rad=' +
|
|
|
|
|
Format('%.3g', [UPRFilterRadius]) + ' p_oversample=' + IntToStr(UPROversample));
|
|
|
|
|
backcolor := 255 shl 24 + cp1.background[0] shl 16 + cp1.background[1] shl 8 + cp1.background[2];
|
|
|
|
|
Strings.Add(' p_bk_color=' + IntToStr(Backcolor) + ' p_contrast=' + FloatToStr(cp1.Contrast) +
|
|
|
|
|
' p_brightness=' + FloatToStr(cp1.Brightness) + ' p_gamma=' + FloatToStr(cp1.Gamma));
|
|
|
|
|
Strings.Add(' p_white_level=200 p_xforms=' + inttostr(Transforms));
|
|
|
|
|
for m := 0 to Transforms do
|
|
|
|
|
begin
|
|
|
|
|
a := cp1.xform[m].c[0][0];
|
|
|
|
|
c := cp1.xform[m].c[0][1];
|
|
|
|
|
b := cp1.xform[m].c[1][0];
|
|
|
|
|
d := cp1.xform[m].c[1][1];
|
|
|
|
|
e := cp1.xform[m].c[2][0];
|
|
|
|
|
f := cp1.xform[m].c[2][1];
|
|
|
|
|
p := cp1.xform[m].Density;
|
|
|
|
|
if m < Transforms then xf_str := 'p_xf' + inttostr(m)
|
|
|
|
|
else begin
|
|
|
|
|
if cp1.HasFinalXForm = false then break;
|
|
|
|
|
xf_str := 'p_finalxf';
|
|
|
|
|
end;
|
|
|
|
|
Strings.Add(' ' + xf_str + '_p=' + Format('%.6g ', [p]));
|
|
|
|
|
Strings.Add(' ' + xf_str + '_c=' + floatTostr(cp1.xform[m].color));
|
|
|
|
|
Strings.Add(' ' + xf_str + '_sym=' + floatTostr(cp1.xform[m].symmetry));
|
|
|
|
|
Strings.Add(' ' + xf_str + '_cfa=' + Format('%.6g ', [a]) +
|
|
|
|
|
xf_str + '_cfb=' + Format('%.6g ', [b]) +
|
|
|
|
|
xf_str + '_cfc=' + Format('%.6g ', [c]) +
|
|
|
|
|
xf_str + '_cfd=' + Format('%.6g ', [d]));
|
|
|
|
|
Strings.Add(' ' + xf_str + '_cfe=' + Format('%.6g ', [e]) +
|
|
|
|
|
' ' + xf_str + '_cff=' + Format('%.6g ', [f]));
|
|
|
|
|
for i := 0 to NRVAR-1 do
|
|
|
|
|
if cp1.xform[m].GetVariation(i) <> 0 then begin
|
|
|
|
|
Strings.Add(' ' + xf_str + '_var_' + VarNames(i) + '=' +
|
|
|
|
|
floatToStr(cp1.xform[m].GetVariation(i)));
|
|
|
|
|
for j:= 0 to GetNrVariableNames - 1 do begin
|
|
|
|
|
{$ifndef VAR_STR}
|
|
|
|
|
cp1.xform[m].GetVariable(GetVariableNameAt(j), v);
|
|
|
|
|
Strings.Add(' ' + xf_str + '_par_' + GetVariableNameAt(j) + '=' + floatToStr(v));
|
|
|
|
|
{$else}
|
|
|
|
|
Strings.Add(' ' + xf_str + '_par_' +
|
|
|
|
|
GetVariableNameAt(j) + '=' + cp1.xform[m].GetVariableStr(GetVariableNameAt(j)));
|
|
|
|
|
{$endif}
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
Strings.Add('gradient:');
|
|
|
|
|
Strings.Add(GradientString(cp1.cmap));
|
|
|
|
|
Strings.Add('}');
|
|
|
|
|
UPRString := Strings.Text;
|
|
|
|
|
finally
|
|
|
|
|
GradStrings.Free;
|
|
|
|
|
Strings.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRandomClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandomizeCP(MainCp);
|
|
|
|
|
inc(RandomIndex);
|
|
|
|
|
MainCp.name := RandomPrefix + RandomDate + '-' +
|
|
|
|
|
IntToStr(RandomIndex);
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
|
|
|
|
|
if AdjustForm.visible then AdjustForm.UpdateDisplay;
|
|
|
|
|
|
|
|
|
|
StatusBar.Panels[3].text := maincp.name;
|
|
|
|
|
ResetLocation;
|
|
|
|
|
RedrawTimer.Enabled := true;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuEqualizeClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
maincp.xform[i].density := 0.5;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuEditorClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
EditForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuExitClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
Close;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuSaveUPRClick(Sender: TObject);
|
|
|
|
|
{ Write a UPR to a file }
|
|
|
|
|
begin
|
|
|
|
|
SaveForm.SaveType := stExportUPR;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SaveForm.Filename := UPRPath;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveForm.Title := maincp.name;
|
|
|
|
|
if SaveForm.ShowModal = mrOK then
|
|
|
|
|
begin
|
|
|
|
|
UPRPath := SaveForm.FileName;
|
|
|
|
|
SaveUPR(SaveForm.Title, SaveForm.Filename);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.mnuSaveAsClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{ Save fractal parameters to a file }
|
|
|
|
|
var
|
|
|
|
|
saved: boolean; // AV
|
|
|
|
|
ext: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
SaveForm.SaveType := stSaveParameters;
|
|
|
|
|
SaveForm.Filename := SavePath;
|
|
|
|
|
SaveForm.Title := maincp.name;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SaveForm.Comment := maincp.comment; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if SaveForm.ShowModal = mrOK then
|
|
|
|
|
begin
|
|
|
|
|
maincp.name := SaveForm.Title;
|
|
|
|
|
SavePath := SaveForm.Filename;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
maincp.comment := SaveForm.Comment;
|
|
|
|
|
ext := LowerCase(ExtractFileExt(SavePath));
|
|
|
|
|
if ext = '' then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SavePath := SavePath + '.flame';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (ext = '.undo') or (ext = '.apo') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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
|
|
|
|
|
// AV: fixed re-saving error with OpenDialog.FileName!
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AddFlameToList; // AV: show the new item
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuSaveAllAsClick(Sender: TObject);
|
|
|
|
|
{ Save all parameters to a file }
|
|
|
|
|
var
|
|
|
|
|
i, current: integer;
|
|
|
|
|
currentXML : string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
cp: TControlPoint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveForm.SaveType := stSaveAllParameters;
|
|
|
|
|
SaveForm.Filename := SavePath;
|
|
|
|
|
if SaveForm.ShowModal = mrOK then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SavePath := SaveForm.Filename;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if ExtractFileExt(SavePath) = '' then
|
|
|
|
|
SavePath := SavePath + '.flame';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
// 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));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
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
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParseXML(maincp, currentXML, true); // AV: fixed - was PChar instead String
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveXMLFlame(maincp, maincp.name, SavePath);
|
|
|
|
|
end else begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: cancel useless multiple preview updated
|
|
|
|
|
LoadXMLFlame(OpenFile, ListView1.Items[i].Caption, false);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveXMLFlame(maincp, maincp.name, SavePath);
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
LoadSaveProgress.Position :=
|
|
|
|
|
round(100 * i / (ListView1.Items.Count - 1)); // AV: display progress
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
LoadSaveProgress.Position := 0; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// AV: we don't need to do this because it resets the Undo history!
|
|
|
|
|
{
|
|
|
|
|
ListXML(SavePath, 2);
|
|
|
|
|
if (current < 0) then current := 0;
|
|
|
|
|
ListView1.Selected := ListView1.Items[current];
|
|
|
|
|
LoadXMLFlame(SavePath, ListView1.Selected.caption);
|
|
|
|
|
}
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.DisplayHint(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
T: TComponent;
|
|
|
|
|
begin
|
|
|
|
|
T := MainForm.FindComponent('StatusBar');
|
|
|
|
|
if T <> nil then
|
|
|
|
|
if Application.Hint = '' then
|
|
|
|
|
begin
|
|
|
|
|
TStatusBar(T).SimpleText := '';
|
|
|
|
|
TStatusBar(T).SimplePanel := False;
|
|
|
|
|
TStatusBar(T).Refresh;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
// AV: fixed - someone forgot to change this property
|
|
|
|
|
TStatusBar(T).SimplePanel := True;
|
|
|
|
|
TStatusBar(T).SimpleText := Application.Hint;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.DownloadPluginsClick(Sender: TObject);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AboutForm.lblPluginsClick(Sender);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure TMainForm.StopScripter;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
try
|
|
|
|
|
with ScriptEditor do begin
|
|
|
|
|
if btnPause.Down then btnPause.Click;
|
|
|
|
|
Stopped := True;
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
except
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// Beep;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuScreenShotClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
SaveScreenShot('Apophysis Main Window');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ ********************************* Form ************************************ }
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FavoriteClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
i := TMenuItem(Sender).Tag;
|
|
|
|
|
Script := favorites[i];
|
|
|
|
|
if FileExists(Script) then
|
|
|
|
|
begin
|
|
|
|
|
ScriptEditor.Editor.Lines.LoadFromFile(Script);
|
|
|
|
|
s := ExtractFileName(Script);
|
|
|
|
|
s := Copy(s, 0, length(s) - Length(ExtractFileExt(s)));
|
|
|
|
|
mnuRun.Caption := Format(TextByKey('main-menu-script-run2'), [s]);
|
|
|
|
|
btnRunScript.Hint := Format(TextByKey('main-menu-script-run2'), [s]);
|
|
|
|
|
ScriptEditor.Caption := s;
|
|
|
|
|
ScriptEditor.RunScript;
|
|
|
|
|
end else
|
|
|
|
|
TMenuItem(Sender).Enabled := False;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ScriptItemClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
s := AppPath + 'Scripts\' + TMenuItem(Sender).Caption;
|
|
|
|
|
// AV: fixed Apo7X bug that didn't recognize the new extension
|
|
|
|
|
if TMenuItem(Sender).Tag = 1 then
|
|
|
|
|
s := s + '.aposcript'
|
|
|
|
|
else
|
|
|
|
|
s := s + '.asc';
|
|
|
|
|
if FileExists(s) then
|
|
|
|
|
begin
|
|
|
|
|
Script := s;
|
|
|
|
|
ScriptEditor.Editor.Lines.LoadFromFile(Script);
|
|
|
|
|
s := ExtractFileName(Script);
|
|
|
|
|
s := RemoveExt(s);
|
|
|
|
|
mnuRun.Caption := Format(TextByKey('main-menu-script-run2'), [s]);
|
|
|
|
|
btnRunScript.Hint := Format(TextByKey('main-menu-script-run2'), [s]);
|
|
|
|
|
ScriptEditor.Caption := s;
|
|
|
|
|
ScriptEditor.RunScript;
|
|
|
|
|
end else // if the script was removed or renamed
|
|
|
|
|
TMenuItem(Sender).Visible := False;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.GetScripts;
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
NewItem, MenuItem: TMenuItem;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
searchResult: TSearchRec;
|
|
|
|
|
i: integer;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s, path: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
sl: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
sl := TStringList.Create;
|
|
|
|
|
if FileExists(AppPath + scriptFavsFilename) then
|
|
|
|
|
begin
|
|
|
|
|
Favorites.LoadFromFile(AppPath + scriptFavsFilename);
|
|
|
|
|
if Trim(Favorites.Text) <> '' then
|
|
|
|
|
begin
|
|
|
|
|
if Favorites.count <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
FavouriteScripts1.Enabled := True;
|
|
|
|
|
FavouriteScripts1.Clear; // AV: refresh the menu everytime it updates
|
|
|
|
|
for i := 0 to Favorites.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
if FileExists(Favorites[i]) then
|
|
|
|
|
begin
|
|
|
|
|
NewItem := TMenuItem.Create(FavouriteScripts1); // (Self);
|
|
|
|
|
if i < 12 then
|
|
|
|
|
NewItem.ShortCut := TextToShortCut('Ctrl+F' + IntToStr(i + 1));
|
|
|
|
|
NewItem.Tag := i;
|
|
|
|
|
s := ExtractFileName(Favorites[i]);
|
|
|
|
|
sl.Add(s);
|
|
|
|
|
s := RemoveExt(s);
|
|
|
|
|
|
|
|
|
|
MenuItem := Directory1.Find(s); // check the default folder
|
|
|
|
|
if (MenuItem <> nil) then
|
|
|
|
|
begin
|
|
|
|
|
path := LowerCase(ExtractFilePath(Favorites[i]));
|
|
|
|
|
if (path = LowerCase(AppPath + 'scripts\')) then
|
|
|
|
|
MenuItem.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
NewItem.Caption := s;
|
|
|
|
|
NewItem.Hint := Format(TextByKey('main-menu-script-run3'), [s]);
|
|
|
|
|
NewItem.OnClick := FavoriteClick;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//OnClick := FavoriteClick; // AV: MainForm.OnClick - why?!
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FavouriteScripts1.Add(NewItem);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
Directory1.Caption := TextByKey('main-menu-script-more');
|
|
|
|
|
end
|
|
|
|
|
else begin // disable unused items
|
|
|
|
|
FavouriteScripts1.Enabled := False;
|
|
|
|
|
Directory1.Caption := TextByKey('main-menu-script-directory');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// Try to find regular files matching *.asc in the scripts dir
|
|
|
|
|
path := AppPath + 'Scripts\*.asc';
|
|
|
|
|
if FindFirst(path, faAnyFile, searchResult) = 0 then
|
|
|
|
|
begin
|
|
|
|
|
Directory1.Enabled := True;
|
|
|
|
|
repeat
|
2022-06-23 06:22:32 -04:00
|
|
|
|
NewItem := TMenuItem.Create(Directory1); // (Self);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
s := searchResult.Name;
|
|
|
|
|
if (sl.IndexOf(s) < 0) then
|
|
|
|
|
begin
|
|
|
|
|
s := RemoveExt(s);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
until (FindNext(searchResult) <> 0);
|
|
|
|
|
FindClose(searchResult);
|
|
|
|
|
end;
|
|
|
|
|
// AV: the same procedure for new extensions
|
|
|
|
|
path := AppPath + 'Scripts\*.aposcript';
|
|
|
|
|
if FindFirst(path, faAnyFile, searchResult) = 0 then
|
|
|
|
|
begin
|
|
|
|
|
Directory1.Enabled := True;
|
|
|
|
|
repeat
|
2022-06-23 06:22:32 -04:00
|
|
|
|
NewItem := TMenuItem.Create(Directory1); // (Self);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
s := searchResult.Name;
|
|
|
|
|
if (sl.IndexOf(s) < 0) then
|
|
|
|
|
begin
|
|
|
|
|
s := RemoveExt(s);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
until (FindNext(searchResult) <> 0);
|
|
|
|
|
FindClose(searchResult);
|
|
|
|
|
end;
|
|
|
|
|
if (Directory1.Count = 0) then Directory1.Enabled := False; // AV
|
|
|
|
|
sl.Free;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormCreate(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
dte: string;
|
|
|
|
|
Registry: TRegistry;
|
|
|
|
|
apoUI: string;
|
|
|
|
|
Layouts: array[0..7] of THandle;
|
|
|
|
|
lnum, i: byte;
|
|
|
|
|
ExtSM: HMenu;
|
|
|
|
|
extStyle: TSearchRec;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AppVersionString := APP_NAME + ' ' + APP_VERSION;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
SubstSource := TStringList.Create;
|
|
|
|
|
SubstTarget := TStringList.Create;
|
|
|
|
|
|
|
|
|
|
CreateSubstMap;
|
|
|
|
|
|
|
|
|
|
ListXmlScanner := TEasyXmlScanner.Create(nil);
|
|
|
|
|
XmlScanner := TXmlScanner.Create(nil);
|
|
|
|
|
|
|
|
|
|
MainForm.ListXmlScanner.Normalize := False;
|
|
|
|
|
MainForm.ListXmlScanner.OnStartTag := ListXmlScannerStartTag;
|
|
|
|
|
|
|
|
|
|
MainForm.XmlScanner.Normalize := False;
|
|
|
|
|
MainForm.XmlScanner.OnContent := XmlScannerContent;
|
|
|
|
|
MainForm.XmlScanner.OnEmptyTag := XMLScannerEmptyTag;
|
|
|
|
|
MainForm.XmlScanner.OnEndTag := XmlScannerEndTag;
|
|
|
|
|
MainForm.XmlScanner.OnStartTag := XMLScannerStartTag;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MainForm.XmlScanner.OnComment := XmlScannerComment; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
AppPath := ExtractFilePath(Application.ExeName); // AV: moved here
|
|
|
|
|
ReadSettings;
|
|
|
|
|
|
|
|
|
|
//SaveSettings;
|
|
|
|
|
LoadLanguage(LanguageFile);
|
|
|
|
|
InsertStrings;
|
|
|
|
|
|
|
|
|
|
AvailableLanguages := TStringList.Create;
|
|
|
|
|
AvailableLanguages.Add('');
|
|
|
|
|
ListLanguages;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-loadingplugins'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MissingPluginList := TStringList.Create; // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
C_SyncDllPlugins; // for Chaotica export
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if (NXFORMS > 100) then
|
|
|
|
|
AppVersionString := AppVersionString + ' (' + TextByKey('main-common-title-t500') + ')'
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else if (NXFORMS < 100) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
AppVersionString := AppVersionString + ' (' + TextByKey('main-common-title-lite') + ')';
|
|
|
|
|
|
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-loadingui'));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: prevent reloading of the splash window after style changing
|
|
|
|
|
SplashWindow.OnShow := nil;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
{ //*************** GUI Style Stuff *****************************// }
|
|
|
|
|
|
|
|
|
|
// AV: trying to load externals GUI styles
|
|
|
|
|
apoUI := AppPath + 'Styles\';
|
|
|
|
|
if FindFirst(apoUI + '*.vsf', faAnyFile, extStyle) = 0 then
|
|
|
|
|
begin
|
|
|
|
|
repeat
|
|
|
|
|
if TStyleManager.IsValidStyle(apoUI + extStyle.Name) then
|
|
|
|
|
TStyleManager.LoadFromFile(apoUI + extStyle.Name);
|
|
|
|
|
until (FindNext(extStyle) <> 0);
|
|
|
|
|
FindClose(extStyle);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ AV: Read Apophysis style name from registry }
|
|
|
|
|
Registry := TRegistry.Create;
|
|
|
|
|
try
|
|
|
|
|
Registry.RootKey := HKEY_CURRENT_USER;
|
|
|
|
|
if Registry.OpenKey('\Software\' + APP_NAME + '\Defaults', False) then
|
|
|
|
|
if Registry.ValueExists('UIStyle') then begin
|
|
|
|
|
apoUI := Registry.ReadString('UIStyle');
|
|
|
|
|
TStyleManager.TrySetStyle(apoUI, false);
|
|
|
|
|
end;
|
|
|
|
|
Registry.CloseKey;
|
|
|
|
|
finally
|
|
|
|
|
Registry.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
CreateStyleList; // create Apo GUI style menu...
|
|
|
|
|
ApplyThemedColors; // AV
|
|
|
|
|
|
|
|
|
|
{ //******************************************************************// }
|
|
|
|
|
|
|
|
|
|
Screen.Cursors[crEditArrow] := LoadCursor(HInstance, 'ARROW_WHITE');
|
|
|
|
|
Screen.Cursors[crEditMove] := LoadCursor(HInstance, 'MOVE_WB');
|
|
|
|
|
Screen.Cursors[crEditRotate] := LoadCursor(HInstance, 'ROTATE_WB');
|
|
|
|
|
Screen.Cursors[crEditScale] := LoadCursor(HInstance, 'SCALE_WB');
|
|
|
|
|
Caption := AppVersionString + APP_BUILD;
|
|
|
|
|
|
|
|
|
|
mnuExportFLame.Enabled := FileExists(flam3Path);
|
|
|
|
|
mnuExportChaotica.Enabled := FileExists(chaoticaPath + '\chaotica.exe');
|
|
|
|
|
|
|
|
|
|
// AV: hack for creating screenshots of Apo windows
|
|
|
|
|
ExtSM := GetSystemMenu(Handle, False);
|
|
|
|
|
InsertMenu(ExtSM, UINT(5), MF_ByPosition or MF_Separator, 0, nil);
|
|
|
|
|
InsertMenu(ExtSM, UINT(6), MF_ByPosition, $C0, PChar(TextByKey('main-menu-screenshot')));
|
|
|
|
|
|
|
|
|
|
FMouseMoveState := msDrag;
|
|
|
|
|
LimitVibrancy := False;
|
|
|
|
|
Favorites := TStringList.Create;
|
|
|
|
|
GetScripts;
|
|
|
|
|
Randomize;
|
|
|
|
|
MainSeed := Random(123456789);
|
|
|
|
|
maincp := TControlPoint.Create;
|
|
|
|
|
ParseCp := TControlPoint.create;
|
|
|
|
|
MemCp := TControlPoint.Create; // AV
|
|
|
|
|
OpenFileType := ftXML;
|
|
|
|
|
Application.OnHint := DisplayHint;
|
|
|
|
|
CanDrawOnResize := False;
|
|
|
|
|
|
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-loadingsettings'));
|
|
|
|
|
|
|
|
|
|
Dte := FormatDateTime('yymmdd', Now);
|
|
|
|
|
if Dte <> RandomDate then
|
|
|
|
|
RandomIndex := 0;
|
|
|
|
|
RandomDate := Dte;
|
|
|
|
|
mnuExit.ShortCut := TextToShortCut('Alt+F4');
|
|
|
|
|
|
|
|
|
|
defKB := Screen.DefaultKbLayout;
|
|
|
|
|
if SetEngLayout then // AV: switch to English language if needed
|
|
|
|
|
begin
|
|
|
|
|
lnum := GetKeyboardLayoutList(High(Layouts) + 1, Layouts);
|
|
|
|
|
for i := 0 to lnum-1 do
|
|
|
|
|
if (LoWord(Layouts[i]) and $FF) = Lang_English then
|
|
|
|
|
begin
|
|
|
|
|
ActivateKeyboardLayout(Layouts[i], 0);
|
|
|
|
|
PInteger(@Screen.DefaultKbLayout)^ := -1; // AV: hack - to rewrite a read-only value
|
|
|
|
|
break;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
FillVariantMenu;
|
|
|
|
|
|
|
|
|
|
tbQualityBox.Text := FloatToStr(defSampleDensity);
|
|
|
|
|
tbShowAlpha.Down := ShowTransparency;
|
|
|
|
|
DrawSelection := true;
|
|
|
|
|
FViewScale := 1;
|
|
|
|
|
|
|
|
|
|
{ ************ AV: setting flame thumbnails properties *************}
|
|
|
|
|
case ThumbPrevQual of
|
|
|
|
|
0: begin
|
|
|
|
|
TThumbnailThread.FPreviewDensity := prevLowQuality;
|
|
|
|
|
mnuLowQuality.Checked := True;
|
|
|
|
|
end;
|
|
|
|
|
1: begin
|
|
|
|
|
TThumbnailThread.FPreviewDensity := prevMediumQuality;
|
|
|
|
|
mnuMediumQuality.Checked := True;
|
|
|
|
|
end;
|
|
|
|
|
2: begin
|
|
|
|
|
TThumbnailThread.FPreviewDensity := prevHighQuality;
|
|
|
|
|
mnuHighQuality.Checked := True;
|
|
|
|
|
end;
|
|
|
|
|
else TThumbnailThread.FPreviewDensity := 1; // just in case...
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
ThumbnailPlaceholder := TBitmap.Create; // AV
|
|
|
|
|
SetThumbnailProperties; // AV
|
|
|
|
|
// AV: deleted duplicated image lists to reduce memory allocation
|
|
|
|
|
ListView1.LargeImages := UsedThumbnails;
|
|
|
|
|
// AV: to prevent updating flame list before it's created
|
|
|
|
|
GeneratingThumbs := True;
|
|
|
|
|
|
|
|
|
|
{ *******************************************************************}
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ClassicListMode = true then
|
|
|
|
|
btnViewListClick(nil)
|
|
|
|
|
else
|
|
|
|
|
btnViewIconsClick(nil);
|
|
|
|
|
|
|
|
|
|
if ConfirmResetUndo = False then ListView1.OnSelectItem := nil; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
SaveSettings; // AV: moved back from top to the end
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormShow(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
Registry: TRegistry;
|
|
|
|
|
i: integer;
|
|
|
|
|
index: integer;
|
|
|
|
|
cmdl : TCommandLine;
|
|
|
|
|
fn, flameXML : string;
|
|
|
|
|
openScript: string;
|
|
|
|
|
autoScript: TStringList; // AV
|
|
|
|
|
begin
|
|
|
|
|
tbGuides.Down := EnableGuides;
|
|
|
|
|
|
|
|
|
|
{ Read position from registry }
|
|
|
|
|
Registry := TRegistry.Create;
|
|
|
|
|
try
|
|
|
|
|
Registry.RootKey := HKEY_CURRENT_USER;
|
|
|
|
|
if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Main', False) then
|
|
|
|
|
begin
|
|
|
|
|
if Registry.ValueExists('Left') then
|
|
|
|
|
MainForm.Left := Registry.ReadInteger('Left');
|
|
|
|
|
if Registry.ValueExists('Top') then
|
|
|
|
|
MainForm.Top := Registry.ReadInteger('Top');
|
|
|
|
|
if Registry.ValueExists('Width') then
|
|
|
|
|
MainForm.Width := Registry.ReadInteger('Width');
|
|
|
|
|
if Registry.ValueExists('Height') then
|
|
|
|
|
MainForm.Height := Registry.ReadInteger('Height');
|
|
|
|
|
if Registry.ValueExists('SortFlames') then // AV
|
|
|
|
|
begin
|
|
|
|
|
if Registry.ReadBool('SortFlames') then SortFlames.Click;
|
|
|
|
|
end;
|
|
|
|
|
if Registry.ValueExists('EnumerateFlames') then // AV
|
|
|
|
|
EnumerateFlames.Checked := Registry.ReadBool('EnumerateFlames');
|
|
|
|
|
end;
|
|
|
|
|
Registry.CloseKey;
|
|
|
|
|
|
|
|
|
|
if Registry.OpenKey('\Software\' + APP_NAME + '\Defaults', False) then
|
|
|
|
|
begin // AV
|
|
|
|
|
if Registry.ValueExists('RandBackColor') then
|
|
|
|
|
RandBackColor := Registry.ReadInteger('RandBackColor')
|
|
|
|
|
else RandBackColor := 0; // AV
|
|
|
|
|
end;
|
|
|
|
|
Registry.CloseKey;
|
|
|
|
|
finally
|
|
|
|
|
Registry.Free;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-initrenderer'));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Application.ProcessMessages; // AV: added to update the status properly
|
|
|
|
|
|
|
|
|
|
{ Synchronize menus etc..}
|
|
|
|
|
// should be defaults....
|
2022-03-08 12:25:51 -05:00
|
|
|
|
UndoIndex := 0;
|
|
|
|
|
UndoMax := 0;
|
|
|
|
|
index := 1;
|
|
|
|
|
ListView1.RowSelect := True;
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
Variation := vRandom;
|
|
|
|
|
Maincp.brightness := defBrightness;
|
|
|
|
|
maincp.contrast := defContrast; // AV
|
|
|
|
|
maincp.gamma := defGamma;
|
|
|
|
|
maincp.vibrancy := defVibrancy;
|
|
|
|
|
maincp.sample_density := defSampleDensity;
|
|
|
|
|
maincp.spatial_oversample := defOversample;
|
|
|
|
|
maincp.spatial_filter_radius := defFilterRadius;
|
|
|
|
|
maincp.gammaThreshRelative := defGammaThreshold;
|
|
|
|
|
|
|
|
|
|
if KeepBackGround and (RandBackColor <> 0) then begin // AV
|
|
|
|
|
maincp.background[0] := RandBackColor and 255;
|
|
|
|
|
maincp.background[1] := RandBackColor shr 8 and 255;
|
|
|
|
|
maincp.background[2] := RandBackColor shr 16 and 255;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
|
|
|
|
|
// somehow this doesn't work:
|
|
|
|
|
// Image.Width := BackPanel.Width - 2;
|
|
|
|
|
// Image.Height := BackPanel.Height - 2;
|
|
|
|
|
|
|
|
|
|
// so we'll do it 'bad' way ;-)
|
|
|
|
|
Image.Align := alNone;
|
|
|
|
|
|
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-initcolormap'));
|
|
|
|
|
if FileExists(AppPath + 'Gradients\default.map') then
|
|
|
|
|
begin
|
|
|
|
|
DefaultPalette := GradientBrowser.LoadFractintMap(AppPath + 'Gradients\default.map');
|
|
|
|
|
maincp.cmap := DefaultPalette;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
cmap_index := random(NRCMAPS);
|
|
|
|
|
GetCMap(cmap_index, 1, maincp.cmap);
|
|
|
|
|
DefaultPalette := maincp.cmap;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
fn := AppPath + randFilename;
|
|
|
|
|
if FileExists(fn) then DeleteFile(fn);
|
|
|
|
|
fn := AppPath + ChangeFileExt(randFilename, '.bak'); // AV
|
|
|
|
|
if FileExists(fn) then DeleteFile(fn);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
cmdl := TCommandLine.Create;
|
|
|
|
|
cmdl.Load;
|
|
|
|
|
|
|
|
|
|
openScript := '';
|
|
|
|
|
|
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-initbatch'));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// get filename from command line argument
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if ParamCount > 0 then
|
|
|
|
|
openFile := ParamStr(1)
|
|
|
|
|
else
|
|
|
|
|
openFile := defFlameFile;
|
|
|
|
|
|
|
|
|
|
if ((openFile = '') or (not FileExists(openFile))) and RememberLastOpenFile then begin
|
|
|
|
|
openFile := LastOpenFile;
|
|
|
|
|
index := LastOpenFileEntry;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// 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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
LastOpenFile := openFile;
|
|
|
|
|
LastOpenFileEntry := index;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (openFile = '') or (not FileExists(openFile)) and
|
2022-06-23 06:22:32 -04:00
|
|
|
|
(not ((fn = '.asc') or (fn = '.aposcript'))) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
MainCp.Width := Image.Width;
|
|
|
|
|
MainCp.Height := Image.Height;
|
|
|
|
|
RandomBatch;
|
|
|
|
|
if APP_BUILD = '' then
|
|
|
|
|
MainForm.Caption := AppVersionString + ' - ' + TextByKey('main-common-randombatch')
|
|
|
|
|
else
|
|
|
|
|
MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + TextByKey('main-common-randombatch');
|
|
|
|
|
OpenFile := AppPath + randFilename;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
OpenFileType := ftXML;
|
|
|
|
|
ListXML(OpenFile, 1);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if batchsize = 1 then DrawFlame;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (fn = '.apo') or (fn = '.undo') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
OpenFileType := ftApo; // AV: we must choose a file type BEFORE updating list view
|
|
|
|
|
ListIFS(OpenFile, 1); // ListFlames(OpenFile, 1);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (fn = '.asc') or (fn = '.aposcript') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
openScript := OpenFile;
|
|
|
|
|
RandomBatch;
|
|
|
|
|
if APP_BUILD = '' then
|
|
|
|
|
MainForm.Caption := AppVersionString + ' - ' + TextByKey('main-common-randombatch')
|
|
|
|
|
else
|
|
|
|
|
MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + TextByKey('main-common-randombatch');
|
|
|
|
|
OpenFile := AppPath + randFilename;
|
|
|
|
|
OpenFileType := ftXML;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ListXML(OpenFile, 1);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if batchsize = 1 then DrawFlame;
|
|
|
|
|
end else begin
|
|
|
|
|
OpenFileType := ftXML;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ListXML(OpenFile, 2);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainForm.ListView1.Selected := MainForm.ListView1.Items[index - 1];
|
|
|
|
|
end;
|
|
|
|
|
if APP_BUILD = '' then MainForm.Caption := AppVersionString + ' - ' + openFile
|
|
|
|
|
else MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + openFile;
|
|
|
|
|
end;
|
|
|
|
|
ListView1.SetFocus; // AV
|
|
|
|
|
CanDrawOnResize := True;
|
|
|
|
|
Statusbar.Panels[3].Text := maincp.name;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AdjustForm.cmbPalette.Items.clear;
|
|
|
|
|
for i := 0 to NRCMAPS -1 do
|
|
|
|
|
AdjustForm.cmbPalette.Items.Add(cMapnames[i]);
|
|
|
|
|
AdjustForm.cmbPalette.ItemIndex := 0;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// ExportDialog.cmbDepth.ItemIndex := 2; // AV: changed inside ExportForm
|
|
|
|
|
// DoNotAskAboutChange := false;
|
|
|
|
|
|
|
|
|
|
SetAutoSaveTimer; // AV: a code block is replaced by a method
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// loading done..now do what is told by cmdline ...
|
|
|
|
|
if (cmdl.CreateFromTemplate) then begin
|
|
|
|
|
if FileExists(cmdl.TemplateFile) then begin
|
|
|
|
|
fn := cmdl.TemplateFile;
|
|
|
|
|
flameXML := LoadXMLFlameText(fn, cmdl.TemplateName);
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
|
|
|
|
|
ScriptEditor.Stopped := True;
|
|
|
|
|
|
|
|
|
|
StopThread;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParseXML(MainCP, flameXML, false); //InvokeLoadXML(flameXML);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
Statusbar.Panels[3].Text := MainCp.name;
|
|
|
|
|
ResizeImage;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
AdjustForm.mnuRandomize.Click;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
cmdl.Free; // <-- AV: fixed memory leak
|
|
|
|
|
|
|
|
|
|
// .. and run autoexec.asc
|
|
|
|
|
SplashWindow.SetInfo(TextByKey('splash-execstartupscript'));
|
|
|
|
|
if (FileExists(AppPath + 'autoexec.asc')) then
|
|
|
|
|
begin
|
|
|
|
|
// AV: first we must check that the file is not empty
|
|
|
|
|
autoScript := TStringList.Create;
|
|
|
|
|
autoScript.LoadFromFile(AppPath + 'autoexec.asc');
|
|
|
|
|
if Trim(autoScript.Text) <> '' then // AV
|
|
|
|
|
begin
|
|
|
|
|
ScriptEditor.LoadRunAndClear(AppPath + 'autoexec.asc');
|
|
|
|
|
mnuRun.Caption := TextByKey('main-menu-script-run');
|
|
|
|
|
btnRunScript.Hint := TextByKey('main-menu-script-run');
|
|
|
|
|
end;
|
|
|
|
|
autoScript.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (openScript <> '') then begin
|
|
|
|
|
ScriptEditor.LoadScriptFile(openScript);
|
|
|
|
|
ScriptEditor.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if ScriptEditor.Editor.IsEmpty then // AV: is there any code?
|
|
|
|
|
begin
|
|
|
|
|
mnuStop.Enabled := False;
|
|
|
|
|
btnStopScript.Enabled := False;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
SplashWindow.Hide;
|
|
|
|
|
SplashWindow.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.SystemErrorMessage: string;
|
|
|
|
|
var
|
|
|
|
|
P: PChar;
|
|
|
|
|
begin
|
|
|
|
|
if FormatMessage(Format_Message_Allocate_Buffer + Format_Message_From_System,
|
|
|
|
|
nil,
|
|
|
|
|
GetLastError,
|
|
|
|
|
0,
|
|
|
|
|
@P,
|
|
|
|
|
0,
|
|
|
|
|
nil) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
Result := P;
|
|
|
|
|
LocalFree(Integer(P))
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
Result := '';
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.SystemErrorMessage2(errno: cardinal): string;
|
|
|
|
|
var
|
|
|
|
|
P: PChar;
|
|
|
|
|
begin
|
|
|
|
|
if FormatMessage(Format_Message_Allocate_Buffer + Format_Message_From_System,
|
|
|
|
|
nil,
|
|
|
|
|
errno,
|
|
|
|
|
0,
|
|
|
|
|
@P,
|
|
|
|
|
0,
|
|
|
|
|
nil) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
Result := P;
|
|
|
|
|
LocalFree(Integer(P))
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
Result := '';
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
|
|
|
|
|
var
|
|
|
|
|
Registry: TRegistry;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
fn: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
if ConfirmExit and (UndoIndex <> 0) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Application.MessageBox(PChar(TextByKey('common-confirmexit')),
|
|
|
|
|
ApophysisSVN, MB_ICONWARNING or MB_YESNO) <> IDYES then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
Action := caNone;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AutoSaveTimer.Enabled := False; // AV
|
|
|
|
|
StopScripter; // AV: stopping the scripter's animation
|
|
|
|
|
|
|
|
|
|
// HtmlHelp(0, nil, HH_CLOSE_ALL, 0);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
{ To capture secondary window positions }
|
|
|
|
|
if EditForm.visible then EditForm.Close;
|
|
|
|
|
if AdjustForm.visible then AdjustForm.close;
|
|
|
|
|
if GradientBrowser.visible then GradientBrowser.close;
|
|
|
|
|
if MutateForm.visible then MutateForm.Close;
|
|
|
|
|
if ScriptEditor.visible then ScriptEditor.Close;
|
|
|
|
|
|
|
|
|
|
{ Stop the render thread }
|
|
|
|
|
if assigned(Renderer) then Renderer.Terminate;
|
|
|
|
|
if assigned(Renderer) then Renderer.WaitFor;
|
|
|
|
|
|
|
|
|
|
if RenderForm.Visible then RenderForm.Close;
|
|
|
|
|
|
|
|
|
|
{ Write position to registry }
|
|
|
|
|
Registry := TRegistry.Create;
|
|
|
|
|
try
|
|
|
|
|
Registry.RootKey := HKEY_CURRENT_USER;
|
|
|
|
|
if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Main', True) then
|
|
|
|
|
begin
|
|
|
|
|
if MainForm.WindowState <> wsMaximized then begin
|
|
|
|
|
Registry.WriteInteger('Top', MainForm.Top);
|
|
|
|
|
Registry.WriteInteger('Left', MainForm.Left);
|
|
|
|
|
Registry.WriteInteger('Width', MainForm.Width);
|
|
|
|
|
Registry.WriteInteger('Height', MainForm.Height);
|
|
|
|
|
end;
|
|
|
|
|
Registry.WriteBool('SortFlames', SortFlames.Checked); // AV
|
|
|
|
|
Registry.WriteBool('EnumerateFlames', EnumerateFlames.Checked); // AV
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Registry.Free;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
CanDrawOnResize := False;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if KeepBackGround then // AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RandBackColor := MainCp.background[2] * 65536 +
|
|
|
|
|
MainCp.background[1] * 256 + MainCp.background[0];
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// AV: remember the flame position if the list was sorted
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if assigned(ListView1.Selected) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
LastOpenFileEntry := ListView1.Selected.Index + 1;
|
|
|
|
|
|
|
|
|
|
SaveSettings;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormDestroy(Sender: TObject);
|
|
|
|
|
var i: word;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//if assigned(Renderer) then Renderer.Terminate;
|
|
|
|
|
//if assigned(Renderer) then Renderer.WaitFor;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if assigned(Renderer) then Renderer.Free;
|
|
|
|
|
if assigned(FViewImage) then FViewImage.Free;
|
|
|
|
|
|
|
|
|
|
ListXmlScanner.Free; // AV: fixed memory leak
|
|
|
|
|
XmlScanner.Free; // AV: fixed memory leak
|
|
|
|
|
|
|
|
|
|
// AV: all memory leaks with cp.used_plugins are fixed
|
|
|
|
|
MainCP.free;
|
|
|
|
|
ParseCp.free;
|
|
|
|
|
MemCp.free; // AV
|
|
|
|
|
Favorites.Free;
|
|
|
|
|
|
|
|
|
|
SubstSource.Free; // AV: fixed memory leak
|
|
|
|
|
SubstTarget.Free; // AV: fixed memory leak
|
|
|
|
|
|
|
|
|
|
MissingPluginList.Free; // AV
|
|
|
|
|
|
|
|
|
|
if assigned(ThumbnailPlaceholder) then
|
|
|
|
|
begin
|
|
|
|
|
ThumbnailPlaceholder.Free; // AV: fixed memory leak
|
|
|
|
|
ThumbnailPlaceholder := nil;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
AvailableLanguages.Free; // AV: fixed memory leak
|
|
|
|
|
for i := 0 to length(Translation.language) - 1 do
|
|
|
|
|
Translation.language[i].Free; // AV: fixed memory leaks
|
|
|
|
|
|
|
|
|
|
ActivateKeyboardLayout(defKB, 0); // AV: restore default user's language
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
|
|
|
|
|
var
|
|
|
|
|
scale: double;
|
|
|
|
|
begin
|
|
|
|
|
if Key = #27 then begin
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msZoomWindowMove:
|
|
|
|
|
FMouseMoveState := msZoomWindow;
|
|
|
|
|
msZoomOutWindowMove:
|
|
|
|
|
FMouseMoveState := msZoomOutWindow;
|
|
|
|
|
msDragMove:
|
|
|
|
|
begin
|
|
|
|
|
FMouseMoveState := msDrag;
|
|
|
|
|
|
|
|
|
|
scale := FViewScale * Image.Width / FViewImage.Width;
|
|
|
|
|
FViewPos.X := FViewPos.X - (FClickRect.Right - FClickRect.Left) / scale;
|
|
|
|
|
FViewPos.Y := FViewPos.Y - (FClickRect.Bottom - FClickRect.Top) / scale;
|
|
|
|
|
end;
|
|
|
|
|
msRotateMove:
|
|
|
|
|
FMouseMoveState := msRotate;
|
|
|
|
|
end;
|
|
|
|
|
DrawImageView;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
//ScriptEditor.Stopped := True;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ ****************************** Misc controls ****************************** }
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.BackPanelResize(Sender: TObject);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
try
|
2022-03-08 12:25:51 -05:00
|
|
|
|
StopThread;
|
|
|
|
|
if CanDrawOnResize then
|
|
|
|
|
reDrawTimer.Enabled := True;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ResizeImage;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
DrawImageView;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
except
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// AV: added the third parameter to prevent multiple updates of the previews
|
|
|
|
|
procedure TMainForm.LoadXMLFlame(filename, name: string; upd: boolean = true);
|
|
|
|
|
var
|
|
|
|
|
i, p: integer;
|
|
|
|
|
FileStrings: TStringList;
|
|
|
|
|
ParamStrings: TStringList;
|
|
|
|
|
Tokens: TStringList;
|
|
|
|
|
time: integer;
|
|
|
|
|
begin
|
|
|
|
|
time := -1;
|
|
|
|
|
FileStrings := TStringList.Create;
|
|
|
|
|
ParamStrings := TStringList.Create;
|
|
|
|
|
|
|
|
|
|
if pos('*untitled', name) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
Tokens := TStringList.Create;
|
|
|
|
|
GetTokens(name, tokens);
|
|
|
|
|
time := StrToInt(tokens[1]);
|
|
|
|
|
Tokens.free;
|
|
|
|
|
end;
|
|
|
|
|
try
|
|
|
|
|
FileStrings.LoadFromFile(filename);
|
|
|
|
|
for i := 0 to FileStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
pname := '';
|
|
|
|
|
ptime := '';
|
|
|
|
|
p := Pos('<flame ', LowerCase(FileStrings[i]));
|
|
|
|
|
if (p <> 0) then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FileStrings[i]))); // AV
|
|
|
|
|
ListXMLScanner.Execute;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if pname <> '' then
|
|
|
|
|
begin
|
|
|
|
|
if (Trim(pname) = Trim(name)) then
|
|
|
|
|
begin
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
Break;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if ptime='' then ptime:='0'; //hack
|
|
|
|
|
if StrToInt(ptime) = time then
|
|
|
|
|
begin
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
Break;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
repeat
|
|
|
|
|
inc(i);
|
|
|
|
|
ParamStrings.Add(FileStrings[i]);
|
|
|
|
|
until pos('</flame>', Lowercase(FileStrings[i])) <> 0;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//ScriptEditor.Stopped := True; // <-- AV: I hate this...
|
|
|
|
|
// If script preview isn't visible, it's useless,
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// otherwise it loads wrong flame from sripter...
|
|
|
|
|
|
|
|
|
|
StopThread;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParseXML(MainCp, ParamStrings.Text, true);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if upd then
|
|
|
|
|
begin // AV: to prevent redrawing when saving a batch
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
UndoIndex := 0;
|
|
|
|
|
UndoMax := 0;
|
|
|
|
|
if fileExists(AppPath + undoFilename) then
|
|
|
|
|
DeleteFile(AppPath + undoFilename);
|
|
|
|
|
Statusbar.Panels[3].Text := Maincp.name;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
|
|
|
|
|
EditForm.SelectedTriangle := 0; // (?)
|
|
|
|
|
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end; // end updates
|
|
|
|
|
|
|
|
|
|
finally
|
|
|
|
|
FileStrings.free;
|
|
|
|
|
ParamStrings.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ResizeImage;
|
|
|
|
|
var
|
|
|
|
|
pw, ph: integer;
|
|
|
|
|
begin
|
|
|
|
|
pw := BackPanel.Width - 2;
|
|
|
|
|
ph := BackPanel.Height - 2;
|
|
|
|
|
begin
|
|
|
|
|
if (MainCP.Width / MainCP.Height) > (pw / ph) then
|
|
|
|
|
begin
|
|
|
|
|
Image.Width := pw;
|
|
|
|
|
Image.Height := round(MainCP.Height / MainCP.Width * pw);
|
|
|
|
|
Image.Left := 1;
|
|
|
|
|
Image.Top := (ph - Image.Height) div 2;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
Image.Height := ph;
|
|
|
|
|
Image.Width := round(MainCP.Width / MainCP.Height * ph);
|
|
|
|
|
Image.Top := 1;
|
|
|
|
|
Image.Left := (pw - Image.Width) div 2;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
//MainCP.AdjustScale(Image.Width, Image.Height);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ListViewColumnClick(Sender: TObject; Column: TListColumn);
|
|
|
|
|
begin // AV
|
|
|
|
|
if Column = ListView1.Columns[0] then
|
|
|
|
|
SortFlames.Click // sorting flames alphabetically or chronologically
|
|
|
|
|
else // if Column = ListView1.Columns[1] then
|
|
|
|
|
EnumerateFlames.Click;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ListPopUpPopup(Sender: TObject); // AV
|
|
|
|
|
var
|
|
|
|
|
i: byte;
|
|
|
|
|
IsSel: boolean;
|
|
|
|
|
begin
|
|
|
|
|
IsSel := assigned(ListView1.Selected);
|
|
|
|
|
mnuListRename.Enabled := IsSel;
|
|
|
|
|
mnuItemDelete.Enabled := IsSel;
|
|
|
|
|
mnuRefreshThumb.Enabled := IsSel;
|
|
|
|
|
|
|
|
|
|
if ClassicListMode then
|
|
|
|
|
for i := 2 to 8 do ListPopUp.Items[i].Visible := False
|
|
|
|
|
else
|
|
|
|
|
for i := 2 to 8 do ListPopUp.Items[i].Visible := True;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ListViewDblClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if not (ClassicListMode or ParseLoadingBatch) then UpdateThumbnails;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.ListViewChange(Sender: TObject; Item: TListItem;
|
|
|
|
|
Change: TItemChange);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (ListView1.Selected <> nil) and
|
|
|
|
|
(Trim(ListView1.Selected.Caption) <> Trim(maincp.name)) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
LastOpenFileEntry := ListView1.Selected.Index + 1;
|
|
|
|
|
RedrawTimer.Enabled := False; //?
|
|
|
|
|
StopThread;
|
|
|
|
|
|
|
|
|
|
if OpenFileType = ftXML then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// ParseLoadingBatch := false; // AV: ?
|
|
|
|
|
LoadXMLFlame(OpenFile, ListView1.Selected.caption);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
AnnoyUser;
|
|
|
|
|
end
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else // if OpenFileType = ftApo then // AV: Undo flame list
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
maincp.Clear; // initialize control point for new flame;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// 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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// Fix Apophysis 1.0 parameters with negative color parameteres!
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
{if ResizeOnLoad then}
|
|
|
|
|
ResizeImage;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.UpdateWindows;
|
|
|
|
|
begin
|
|
|
|
|
if AdjustForm.visible then AdjustForm.UpdateDisplay;
|
|
|
|
|
if EditForm.visible then EditForm.UpdateDisplay;
|
|
|
|
|
if MutateForm.visible then MutateForm.UpdateDisplay;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.LoadUndoFlame(index: integer; filename: string);
|
|
|
|
|
var
|
|
|
|
|
FStrings: TStringList;
|
|
|
|
|
IFSStrings: TStringList;
|
|
|
|
|
EntryStrings, Tokens: TStringList;
|
|
|
|
|
SavedPal: Boolean;
|
|
|
|
|
i, j: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
Palette: TColorMap;
|
|
|
|
|
begin
|
|
|
|
|
//ScriptEditor.Stopped := True;
|
|
|
|
|
|
|
|
|
|
FStrings := TStringList.Create;
|
|
|
|
|
IFSStrings := TStringList.Create;
|
|
|
|
|
Tokens := TStringList.Create;
|
|
|
|
|
EntryStrings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
FStrings.LoadFromFile(filename);
|
|
|
|
|
for i := 0 to FStrings.count - 1 do
|
|
|
|
|
if Pos(Format('%.4d-', [UndoIndex]), 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(Format('%.4d-', [UndoIndex]), 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;
|
|
|
|
|
SavedPal := false;
|
|
|
|
|
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;
|
|
|
|
|
maincp.Clear;
|
|
|
|
|
maincp.zoom := 0;
|
|
|
|
|
maincp.center[0] := 0;
|
|
|
|
|
maincp.center[0] := 0;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
maincp.ParseString(EntryStrings.Text);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
maincp.sample_density := defSampleDensity;
|
|
|
|
|
Center[0] := maincp.Center[0];
|
|
|
|
|
Center[1] := maincp.Center[1];
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
// Trim undo index from title
|
|
|
|
|
maincp.name := Copy(Fstrings[0], 6, length(Fstrings[0]) - 7);
|
|
|
|
|
|
|
|
|
|
if SavedPal then maincp.cmap := palette;
|
|
|
|
|
if AdjustForm.visible then AdjustForm.UpdateDisplay;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
finally
|
|
|
|
|
IFSStrings.Free;
|
|
|
|
|
FStrings.Free;
|
|
|
|
|
Tokens.free;
|
|
|
|
|
EntryStrings.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ResetColorSpeedClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
for i := 0 to Transforms-1 do
|
|
|
|
|
maincp.xform[i].symmetry := 0;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ResetColorValuesClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
for i := 0 to Transforms-1 do
|
|
|
|
|
maincp.xform[i].color := 0;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ResetLocation;
|
|
|
|
|
begin
|
|
|
|
|
maincp.zoom := 0;
|
|
|
|
|
//maincp.FAngle := 0;
|
|
|
|
|
//maincp.Width := Image.Width;
|
|
|
|
|
//maincp.Height := Image.Height;
|
|
|
|
|
maincp.CalcBoundBox;
|
|
|
|
|
center[0] := maincp.center[0];
|
|
|
|
|
center[1] := maincp.center[1];
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ListViewEdited(Sender: TObject; Item: TListItem;
|
|
|
|
|
var S: string);
|
|
|
|
|
var Discard: boolean;
|
|
|
|
|
begin
|
|
|
|
|
if (s <> Item.Caption) then
|
|
|
|
|
begin
|
|
|
|
|
// AV: fixed 'List index out of bounds' bugs
|
|
|
|
|
if (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MessageBox(Handle, PChar(TextByKey('save-status-notitle')), ApophysisSVN, 48);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Discard := True;
|
|
|
|
|
end else if (ListView1.FindCaption(0, s, false, true, false) <> nil) then
|
|
|
|
|
begin
|
|
|
|
|
MessageBox(Handle, PChar(Format(TextByKey('save-status-alreadyexists3'),
|
2022-06-23 06:22:32 -04:00
|
|
|
|
[s])), ApophysisSVN, 48);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Discard := True;
|
|
|
|
|
end
|
|
|
|
|
else if OpenFileType = ftXML then
|
|
|
|
|
Discard := (not RenameXML(Item.Caption, s))
|
|
|
|
|
else
|
|
|
|
|
Discard := (not RenameIFS(Item.Caption, s));
|
|
|
|
|
|
|
|
|
|
if Discard then
|
|
|
|
|
s := Item.Caption
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if SortFlames.Checked and EnumerateFlames.Checked then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
EnumerateFlamesClick(EnumerateFlames); // hmm
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.RedrawTimerTimer(Sender: TObject);
|
|
|
|
|
{ Draw flame when timer fires. This seems to stop a lot of errors }
|
|
|
|
|
begin
|
|
|
|
|
if FMouseMoveState in [msZoomWindowMove, msZoomOutWindowMove, msDragMove, msRotateMove] then exit;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.enabled := False;
|
|
|
|
|
DrawFlame;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuVRandomClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
mnuVRandom.Checked := True;
|
|
|
|
|
// AV: only one variation can be active here
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Variation > vRandom then begin
|
|
|
|
|
VarMenus[Variation].Checked := False;
|
|
|
|
|
mnuBuiltinVars.Checked := False;
|
|
|
|
|
mnuPluginVars.Checked := False;
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
repeat
|
|
|
|
|
Variation := vRandom;
|
|
|
|
|
SetVariation(maincp);
|
|
|
|
|
until not maincp.blowsup(1000);
|
|
|
|
|
inc(randomindex);
|
|
|
|
|
MainCp.name := RandomPrefix + RandomDate + '-' +
|
|
|
|
|
IntToStr(RandomIndex);
|
|
|
|
|
ResetLocation;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuGradClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
AdjustForm.PageControl.TabIndex:=2;
|
|
|
|
|
AdjustForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//**************** Smooth Palette *********************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure swapcolor(var clist: array of cardinal; i, j: integer);
|
|
|
|
|
var
|
|
|
|
|
t: cardinal;
|
|
|
|
|
begin
|
|
|
|
|
t := clist[j];
|
|
|
|
|
clist[j] := clist[i];
|
|
|
|
|
clist[i] := t;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function diffcolor(clist: array of cardinal; i, j: integer): cardinal;
|
|
|
|
|
var
|
|
|
|
|
r1, g1, b1, r2, g2, b2: byte;
|
|
|
|
|
begin
|
|
|
|
|
r1 := clist[j] and 255;
|
|
|
|
|
g1 := clist[j] shr 8 and 255;
|
|
|
|
|
b1 := clist[j] shr 16 and 255;
|
|
|
|
|
r2 := clist[i] and 255;
|
|
|
|
|
g2 := clist[i] shr 8 and 255;
|
|
|
|
|
b2 := clist[i] shr 16 and 255;
|
|
|
|
|
Result := abs((r1 - r2) * (r1 - r2)) + abs((g1 - g2) * (g1 - g2)) +
|
|
|
|
|
abs((b1 - b2) * (b1 - b2));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuSmoothGradientClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
SmoothPalette;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.SmoothPalette;
|
|
|
|
|
{ From Draves' Smooth palette Gimp plug-in }
|
|
|
|
|
var
|
|
|
|
|
Bitmap: TBitMap;
|
|
|
|
|
JPEG: TJPEGImage;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
PNG: TPNGImage; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
pal: TColorMap;
|
|
|
|
|
strings: TStringlist;
|
|
|
|
|
ident, FileName: string;
|
|
|
|
|
len, len_best, as_is, swapd: cardinal;
|
|
|
|
|
cmap_best, original, clist: array[0..255] of cardinal;
|
|
|
|
|
{p, total,} j, rand, tryit, i0, i1, x, y, i, iw, ih: integer;
|
|
|
|
|
fn: string;
|
|
|
|
|
begin
|
|
|
|
|
//Total := Trunc(NumTries * TryLength / 100);
|
|
|
|
|
//p := 0;
|
|
|
|
|
Bitmap := TBitmap.Create;
|
|
|
|
|
strings := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
begin
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
OpenDialog.Filter := RenderForm.SaveDialog.Filter; // AV: added precalc
|
2022-03-08 12:25:51 -05:00
|
|
|
|
OpenDialog.InitialDir := ImageFolder;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
OpenDialog.Title := TextByKey('common-selectimage'); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
OpenDialog.FileName := '';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if OpenDialog.Execute then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
fn := OpenDialog.FileName; // AV
|
|
|
|
|
ImageFolder := ExtractFilePath(fn);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
len_best := 0;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
iw := Bitmap.Width;
|
|
|
|
|
ih := Bitmap.Height;
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
{ Pick colors from 256 random pixels in the image }
|
|
|
|
|
x := random(iw);
|
|
|
|
|
y := random(ih);
|
|
|
|
|
clist[i] := Bitmap.canvas.Pixels[x, y];
|
|
|
|
|
end;
|
|
|
|
|
original := clist;
|
|
|
|
|
cmap_best := clist;
|
|
|
|
|
for tryit := 1 to NumTries do
|
|
|
|
|
begin
|
|
|
|
|
clist := original;
|
|
|
|
|
// scramble
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
rand := random(256);
|
|
|
|
|
swapcolor(clist, i, rand);
|
|
|
|
|
end;
|
|
|
|
|
// measure
|
|
|
|
|
len := 0;
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
len := len + diffcolor(clist, i, i + 1);
|
|
|
|
|
// improve
|
|
|
|
|
for i := 1 to TryLength do
|
|
|
|
|
begin
|
|
|
|
|
//inc(p);
|
|
|
|
|
// StatusBar.SimpleText := Format(TextByKey('main-status-calculatingpalette'), [p div total]);
|
|
|
|
|
i0 := 1 + random(254);
|
|
|
|
|
i1 := 1 + random(254);
|
|
|
|
|
if ((i0 - i1) = 1) then
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i1 - 1, i1) + diffcolor(clist, i0, i0 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i1 - 1, i0) + diffcolor(clist, i1, i0 + 1);
|
|
|
|
|
end
|
|
|
|
|
else if ((i1 - i0) = 1) then
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i0 - 1, i0) + diffcolor(clist, i1, i1 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i0 - 1, i1) + diffcolor(clist, i0, i1 + 1);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i0, i0 + 1) + diffcolor(clist, i0, i0 - 1) +
|
|
|
|
|
diffcolor(clist, i1, i1 + 1) + diffcolor(clist, i1, i1 - 1);
|
|
|
|
|
swapd := diffcolor(clist, i1, i0 + 1) + diffcolor(clist, i1, i0 - 1) +
|
|
|
|
|
diffcolor(clist, i0, i1 + 1) + diffcolor(clist, i0, i1 - 1);
|
|
|
|
|
end;
|
|
|
|
|
if (swapd < as_is) then
|
|
|
|
|
begin
|
|
|
|
|
swapcolor(clist, i0, i1);
|
|
|
|
|
len := abs(len + swapd - as_is);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
if (tryit = 1) or (len < len_best) then
|
|
|
|
|
begin
|
|
|
|
|
cmap_best := clist;
|
|
|
|
|
len_best := len;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
clist := cmap_best;
|
|
|
|
|
// clean
|
|
|
|
|
for i := 1 to 1024 do
|
|
|
|
|
begin
|
|
|
|
|
i0 := 1 + random(254);
|
|
|
|
|
i1 := i0 + 1;
|
|
|
|
|
as_is := diffcolor(clist, i0 - 1, i0) + diffcolor(clist, i1, i1 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i0 - 1, i1) + diffcolor(clist, i0, i1 + 1);
|
|
|
|
|
if (swapd < as_is) then
|
|
|
|
|
begin
|
|
|
|
|
swapcolor(clist, i0, i1);
|
|
|
|
|
len_best := len_best + swapd - as_is;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
{ Convert to TColorMap, Gradient and save }
|
|
|
|
|
FileName := lowercase(ExtractFileName(Opendialog.FileName));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ident := CleanIdentifier(FileName);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
strings.add(ident + ' {');
|
|
|
|
|
strings.add('gradient:');
|
|
|
|
|
strings.add(' title="' + CleanUPRTitle(FileName) + '" smooth=no');
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
pal[i][0] := clist[i] and 255;
|
|
|
|
|
pal[i][1] := clist[i] shr 8 and 255;
|
|
|
|
|
pal[i][2] := clist[i] shr 16 and 255;
|
|
|
|
|
j := round(i * (399 / 255));
|
|
|
|
|
strings.Add(' index=' + IntToStr(j) + ' color=' + intToStr(clist[i]));
|
|
|
|
|
end;
|
|
|
|
|
strings.Add('}');
|
|
|
|
|
if not DirectoryExists(ExtractFilePath(defSmoothPaletteFile)) then // AV
|
|
|
|
|
begin
|
|
|
|
|
CreateDir(AppPath + 'Gradients\');
|
|
|
|
|
defSmoothPaletteFile := AppPath + 'Gradients\SmoothPalette.ugr';
|
|
|
|
|
end;
|
|
|
|
|
SaveGradient(Strings.Text, Ident, defSmoothPaletteFile);
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
maincp.cmap := Pal;
|
|
|
|
|
maincp.cmapindex := -1;
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
|
|
|
|
|
if EditForm.Visible then EditForm.UpdateDisplay;
|
|
|
|
|
if MutateForm.Visible then MutateForm.UpdateDisplay;
|
|
|
|
|
RedrawTimer.enabled := true;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
// StatusBar.SimpleText := '';
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Bitmap.Free;
|
|
|
|
|
strings.Free;
|
|
|
|
|
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
|
|
|
|
|
pal: TColorMap;
|
|
|
|
|
len, len_best, as_is, swapd: cardinal;
|
|
|
|
|
cmap_best, original, clist: array[0..255] of cardinal;
|
|
|
|
|
rand, tryit, i0, i1, i: integer;
|
|
|
|
|
begin
|
|
|
|
|
try
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
len_best := 0;
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
clist[i] := OldPal[i, 2] * 65536 + OldPal[i, 1] * 256 + oldpal[i, 0];
|
|
|
|
|
original := clist;
|
|
|
|
|
cmap_best := clist;
|
|
|
|
|
for tryit := 1 to NumTries do
|
|
|
|
|
begin
|
|
|
|
|
clist := original;
|
|
|
|
|
// scramble
|
|
|
|
|
for i := a to b do
|
|
|
|
|
begin
|
|
|
|
|
{ Pick color from randomly selected index of the palette }
|
|
|
|
|
rand := a + random(b - a + 1); // random(256);
|
|
|
|
|
swapcolor(clist, i, rand);
|
|
|
|
|
end;
|
|
|
|
|
// measure
|
|
|
|
|
len := 0;
|
|
|
|
|
for i := a to b do
|
|
|
|
|
len := len + diffcolor(clist, i, i + 1);
|
|
|
|
|
// improve
|
|
|
|
|
for i := 1 to TryLength do
|
|
|
|
|
begin
|
|
|
|
|
i0 := a + 1 + random(b - a - 1); // 1 + random(254);
|
|
|
|
|
i1 := a + 1 + random(b - a - 1); // 1 + random(254);
|
|
|
|
|
if ((i0 - i1) = 1) then
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i1 - 1, i1) + diffcolor(clist, i0, i0 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i1 - 1, i0) + diffcolor(clist, i1, i0 + 1);
|
|
|
|
|
end
|
|
|
|
|
else if ((i1 - i0) = 1) then
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i0 - 1, i0) + diffcolor(clist, i1, i1 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i0 - 1, i1) + diffcolor(clist, i0, i1 + 1);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
as_is := diffcolor(clist, i0, i0 + 1) + diffcolor(clist, i0, i0 - 1) +
|
|
|
|
|
diffcolor(clist, i1, i1 + 1) + diffcolor(clist, i1, i1 - 1);
|
|
|
|
|
swapd := diffcolor(clist, i1, i0 + 1) + diffcolor(clist, i1, i0 - 1) +
|
|
|
|
|
diffcolor(clist, i0, i1 + 1) + diffcolor(clist, i0, i1 - 1);
|
|
|
|
|
end;
|
|
|
|
|
if (swapd < as_is) then
|
|
|
|
|
begin
|
|
|
|
|
swapcolor(clist, i0, i1);
|
|
|
|
|
len := abs(len + swapd - as_is);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
if (tryit = 1) or (len < len_best) then
|
|
|
|
|
begin
|
|
|
|
|
cmap_best := clist;
|
|
|
|
|
len_best := len;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
clist := cmap_best;
|
|
|
|
|
// clean
|
|
|
|
|
for i := 1 to 1024 do
|
|
|
|
|
begin
|
|
|
|
|
i0 := a + 1 + random(b - a - 1); // 1 + random(254);
|
|
|
|
|
i1 := i0 + 1;
|
|
|
|
|
as_is := diffcolor(clist, i0 - 1, i0) + diffcolor(clist, i1, i1 + 1);
|
|
|
|
|
swapd := diffcolor(clist, i0 - 1, i1) + diffcolor(clist, i0, i1 + 1);
|
|
|
|
|
if (swapd < as_is) then
|
|
|
|
|
begin
|
|
|
|
|
swapcolor(clist, i0, i1);
|
|
|
|
|
len_best := len_best + swapd - as_is;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
{ Convert to TColorMap }
|
|
|
|
|
for i := 0 to 255 do
|
|
|
|
|
begin
|
|
|
|
|
pal[i][0] := clist[i] and 255;
|
|
|
|
|
pal[i][1] := clist[i] shr 8 and 255;
|
|
|
|
|
pal[i][2] := clist[i] shr 16 and 255;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
maincp.cmap := Pal;
|
|
|
|
|
maincp.cmapindex := -1;
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
|
|
|
|
|
if EditForm.Visible then EditForm.UpdateDisplay;
|
|
|
|
|
if MutateForm.Visible then MutateForm.UpdateDisplay;
|
|
|
|
|
RedrawTimer.enabled := true;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
finally
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//**********************************************************************//
|
|
|
|
|
|
|
|
|
|
{ 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;
|
|
|
|
|
|
|
|
|
|
//**********************************************************************//
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.mnuThumbnailQualityClick(Sender: TObject); // AV
|
|
|
|
|
begin
|
|
|
|
|
if TMenuItem(Sender).Checked then exit; // prevent unneseccary updating
|
|
|
|
|
TMenuItem(Sender).Checked := True;
|
|
|
|
|
|
|
|
|
|
case TMenuItem(Sender).Tag of
|
|
|
|
|
0: TThumbnailThread.FPreviewDensity := prevMediumQuality;
|
|
|
|
|
1: TThumbnailThread.FPreviewDensity := prevMediumQuality;
|
|
|
|
|
2: TThumbnailThread.FPreviewDensity := prevHighQuality;
|
|
|
|
|
end;
|
|
|
|
|
ThumbPrevQual := TMenuItem(Sender).Tag;
|
|
|
|
|
|
|
|
|
|
// refresh the list of flame previews
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (OpenFile <> '') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if not ParseLoadingBatch then UpdateThumbnails;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuToolbarClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
Toolbar.Visible := not Toolbar.Visible;
|
|
|
|
|
mnuToolbar.Checked := Toolbar.visible;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuTraceClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
TraceForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuStatusBarClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
// Statusbar.Visible := not Statusbar.Visible;
|
|
|
|
|
// AV: fixed Apo7X bug - someone forget to hide other components...
|
|
|
|
|
BottomDock.Visible := not BottomDock.Visible; // AV
|
|
|
|
|
mnuStatusbar.Checked := BottomDock.Visible; // Statusbar.visible;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuFileContentsClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ListBackPanel.Visible := not ListBackPanel.Visible;
|
|
|
|
|
mnuFileContents.Checked := ListBackPanel.Visible; // ListView1.Visible;
|
|
|
|
|
if ListBackPanel.Visible then
|
|
|
|
|
Splitter.Width := 4
|
|
|
|
|
else
|
|
|
|
|
Splitter.Width := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.Undo;
|
|
|
|
|
begin
|
|
|
|
|
if UndoIndex = UndoMax then
|
|
|
|
|
SaveFlame(maincp, Format('%.4d-', [UndoIndex]) + maincp.name,
|
|
|
|
|
AppPath + undoFilename);
|
|
|
|
|
StopThread;
|
|
|
|
|
Dec(UndoIndex);
|
|
|
|
|
LoadUndoFlame(UndoIndex, AppPath + undoFilename);
|
|
|
|
|
mnuRedo.Enabled := True;
|
|
|
|
|
mnuPopRedo.Enabled := True;
|
|
|
|
|
btnRedo.Enabled := True;
|
|
|
|
|
EditForm.mnuRedo.Enabled := True;
|
|
|
|
|
EditForm.tbRedo.enabled := true;
|
|
|
|
|
AdjustForm.btnRedo.enabled := true;
|
|
|
|
|
if UndoIndex = 0 then begin
|
|
|
|
|
mnuUndo.Enabled := false;
|
|
|
|
|
mnuPopUndo.Enabled := false;
|
|
|
|
|
btnUndo.Enabled := false;
|
|
|
|
|
EditForm.mnuUndo.Enabled := false;
|
|
|
|
|
EditForm.tbUndo.enabled := false;
|
|
|
|
|
AdjustForm.btnUndo.enabled := false;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuUndoClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
Undo;
|
|
|
|
|
StatusBar.Panels[3].Text := maincp.name;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuUnflattenClick(Sender: TObject);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i, t: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
refresh: boolean;
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
refresh := False;
|
|
|
|
|
if maincp.HasFinalXForm then t := Transforms
|
|
|
|
|
else t := Transforms - 1;
|
|
|
|
|
|
|
|
|
|
for i := 0 to t do
|
|
|
|
|
if maincp.xform[i].GetVariation(1) <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
maincp.xform[i].SetVariation(1, 0);
|
|
|
|
|
refresh := True;
|
|
|
|
|
end;
|
|
|
|
|
if refresh then
|
|
|
|
|
begin
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.Redo;
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
Inc(UndoIndex);
|
|
|
|
|
|
|
|
|
|
assert(UndoIndex <= UndoMax, 'Undo list index out of range!');
|
|
|
|
|
|
|
|
|
|
LoadUndoFlame(UndoIndex, AppPath + undoFilename);
|
|
|
|
|
mnuUndo.Enabled := True;
|
|
|
|
|
mnuPopUndo.Enabled := True;
|
|
|
|
|
btnUndo.Enabled := True;
|
|
|
|
|
EditForm.mnuUndo.Enabled := True;
|
|
|
|
|
EditForm.tbUndo.enabled := true;
|
|
|
|
|
AdjustForm.btnUndo.enabled := true;
|
|
|
|
|
if UndoIndex = UndoMax then begin
|
|
|
|
|
mnuRedo.Enabled := false;
|
|
|
|
|
mnuPopRedo.Enabled := false;
|
|
|
|
|
btnRedo.Enabled := false;
|
|
|
|
|
EditForm.mnuRedo.Enabled := false;
|
|
|
|
|
EditForm.tbRedo.enabled := false;
|
|
|
|
|
AdjustForm.btnRedo.enabled := false;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRedoClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
Redo;
|
|
|
|
|
StatusBar.Panels[3].Text := maincp.name;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// AV: added support for fast preview and params saving without rendering
|
|
|
|
|
// for absolute beginners :)
|
|
|
|
|
procedure TMainForm.mnuExportBitmapClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var pic: TPNGImage;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
SaveDialog.DefaultExt := 'png';
|
|
|
|
|
SaveDialog.Filter := Format('%s|*.png', [TextByKey('common-filter-png')]);
|
|
|
|
|
SaveDialog.Filename := maincp.name;
|
|
|
|
|
if SaveDialog.Execute then
|
|
|
|
|
begin
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
pic := TPNGImage.Create;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
try
|
|
|
|
|
pic.Assign(Image.Picture.Bitmap);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
pic.AddtEXt('ApoFlame', AnsiString(Trim(FlameToXML(Maincp))));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
pic.SaveToFile(SaveDialog.Filename);
|
|
|
|
|
finally
|
|
|
|
|
pic.Free;
|
|
|
|
|
end;
|
|
|
|
|
except
|
|
|
|
|
Image.Picture.Bitmap.SaveToFile(ChangeFileExt(SaveDialog.FileName, '.bmp'));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuFullScreenClick(Sender: TObject);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: screen size never changed while app works - moved into OnCreate handler
|
|
|
|
|
{
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FullScreenForm.Width := Screen.Width;
|
|
|
|
|
FullScreenForm.Height := Screen.Height;
|
|
|
|
|
FullScreenForm.Top := 0;
|
|
|
|
|
FullScreenForm.Left := 0;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
}
|
|
|
|
|
FullScreenForm.ActiveForm := Screen.ActiveForm;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FullScreenForm.cp.Copy(maincp);
|
|
|
|
|
FullScreenForm.cp.cmap := maincp.cmap;
|
|
|
|
|
FullScreenForm.Calculate := True;
|
|
|
|
|
FullScreenForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRenderClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
Ext: string;
|
|
|
|
|
NewRender: Boolean;
|
|
|
|
|
begin
|
|
|
|
|
NewRender := True;
|
|
|
|
|
|
|
|
|
|
if Assigned(RenderForm.Renderer) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
NewRender := false;
|
|
|
|
|
|
|
|
|
|
if NewRender then
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.Terminate;
|
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #1
|
|
|
|
|
RenderForm.ResetControls;
|
|
|
|
|
RenderForm.PageCtrl.TabIndex := 0;
|
|
|
|
|
|
|
|
|
|
case renderFileFormat of
|
|
|
|
|
1: Ext := '.bmp';
|
|
|
|
|
2: Ext := '.png';
|
|
|
|
|
3: Ext := '.jpg';
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RenderForm.bRenderAll := False;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
//RenderForm.caption := 'Render ' + #39 + maincp.name + #39 + ' to Disk';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RenderForm.Caption := RenderForm.Hint; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2
|
|
|
|
|
end;
|
|
|
|
|
RenderForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRenderAllClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
Ext: string;
|
|
|
|
|
NewRender: Boolean;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
NewRender := True;
|
|
|
|
|
|
|
|
|
|
if Assigned(RenderForm.Renderer) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')), ApophysisSVN, 36) = ID_NO then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
NewRender := false;
|
|
|
|
|
|
|
|
|
|
if NewRender then
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.Terminate;
|
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #1
|
|
|
|
|
RenderForm.ResetControls;
|
|
|
|
|
RenderForm.PageCtrl.TabIndex := 0;
|
|
|
|
|
|
|
|
|
|
case renderFileFormat of
|
|
|
|
|
1: Ext := '.bmp';
|
|
|
|
|
2: Ext := '.png';
|
|
|
|
|
3: Ext := '.jpg';
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RenderForm.Caption := GetShortHint(tbRenderAll.Hint); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
RenderForm.bRenderAll := true;
|
|
|
|
|
RenderForm.Filename := RenderPath + maincp.name + Ext;
|
|
|
|
|
RenderForm.SaveDialog.FileName := RenderForm.Filename;
|
|
|
|
|
RenderForm.txtFilename.Text := ChangeFileExt(RenderForm.SaveDialog.Filename, Ext);
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//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;
|
|
|
|
|
{
|
2022-03-08 12:25:51 -05:00
|
|
|
|
RenderForm.cp.Copy(MainCP);
|
|
|
|
|
RenderForm.cp.cmap := maincp.cmap;
|
|
|
|
|
RenderForm.zoom := maincp.zoom;
|
|
|
|
|
RenderForm.Center[0] := center[0];
|
|
|
|
|
RenderForm.Center[1] := center[1];
|
2022-06-23 06:22:32 -04:00
|
|
|
|
}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2
|
|
|
|
|
end;
|
|
|
|
|
RenderForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuMutateClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
MutateForm.Show;
|
|
|
|
|
MutateForm.UpdateDisplay;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuAdjustClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
AdjustForm.PageControl.TabIndex := 0;
|
|
|
|
|
AdjustForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure TMainForm.mnuAnimatorClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
StopScripter;
|
|
|
|
|
AnimateForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.mnuResetLocationClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
scale: double;
|
|
|
|
|
dx, dy, cdx, cdy: double;
|
|
|
|
|
sina, cosa: extended;
|
|
|
|
|
begin
|
|
|
|
|
StopThread; // AV
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
try // AV
|
|
|
|
|
scale := MainCP.pixels_per_unit / MainCP.Width * power(2, MainCP.zoom);
|
|
|
|
|
cdx := MainCP.center[0];
|
|
|
|
|
cdy := MainCP.center[1];
|
|
|
|
|
|
|
|
|
|
ResetLocation;
|
|
|
|
|
|
|
|
|
|
cdx := MainCP.center[0] - cdx;
|
|
|
|
|
cdy := MainCP.center[1] - cdy;
|
|
|
|
|
Sincos(MainCP.FAngle, sina, cosa);
|
|
|
|
|
if IsZero(sina) then begin
|
|
|
|
|
dy := cdy*cosa {- cdx*sina};
|
|
|
|
|
dx := (cdx {+ dy*sina})/cosa;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
dx := cdy*sina + cdx*cosa;
|
|
|
|
|
dy := (dx*cosa - cdx)/sina;
|
|
|
|
|
end;
|
|
|
|
|
FViewPos.x := FViewPos.x - dx * scale * Image.Width;
|
|
|
|
|
FViewPos.y := FViewPos.y - dy * scale * Image.Width;
|
|
|
|
|
|
|
|
|
|
FViewScale := FViewScale * MainCP.pixels_per_unit / MainCP.Width * power(2, MainCP.zoom) / scale;
|
|
|
|
|
|
|
|
|
|
DrawImageView;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.enabled := true;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
except on EMathError do // AV
|
|
|
|
|
Trace2('Cannot calculate the flame scale and bounds...');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuAboutClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
AboutForm.ShowModal;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuOpenGradientClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
GradientBrowser.Filename := GradientFile;
|
|
|
|
|
GradientBrowser.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuSaveUndoClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if FileExists(AppPath + undoFilename) then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SaveDialog.DefaultExt := 'apo';
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveDialog.Filter := TextByKey('common-filter-undofiles') + '|*undo;*.apo';
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SaveDialog.InitialDir := ParamFolder;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SaveDialog.Filename := maincp.name;
|
|
|
|
|
if SaveDialog.Execute then
|
|
|
|
|
begin
|
|
|
|
|
if FileExists(SaveDialog.Filename) then DeleteFile(SaveDialog.Filename);
|
|
|
|
|
CopyFile(PChar(AppPath + undoFilename), PChar(SaveDialog.Filename), False);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
|
|
|
|
begin
|
|
|
|
|
if Assigned(RenderForm.Renderer) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')),
|
|
|
|
|
ApophysisSVN, 36) = ID_NO then
|
|
|
|
|
CanClose := False;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AboutToExit := CanClose;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormActivate(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if Assigned(Renderer) then Renderer.Priority := tpNormal;
|
|
|
|
|
mnuPaste.Enabled := FlameInClipboard; // AV
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.FormDeactivate(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if Assigned(Renderer) then Renderer.Priority := tpLower;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuCalculateColorsClick(Sender: TObject);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRandomizeColorValuesClick(Sender: TObject);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
inc(MainSeed);
|
|
|
|
|
RandSeed := MainSeed;
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
for i := 0 to Transforms - 1 do
|
|
|
|
|
maincp.xform[i].color := random;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuEditScriptClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ScriptEditor.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuRunClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if not ScriptEditor.Editor.IsEmpty then // AV: is there any code?
|
|
|
|
|
ScriptEditor.RunScript;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuOpenScriptClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ScriptEditor.OpenScript;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuStopClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
//ScriptEditor.Stopped := True;
|
|
|
|
|
// AV: what if script is paused?
|
|
|
|
|
ScriptEditor.btnStop.Click; // AV
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
procedure TMainForm.mnuImportGimpClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
flist: tStringList;
|
|
|
|
|
begin
|
|
|
|
|
flist := TStringList.Create;
|
|
|
|
|
OpenDialog.Filter := Format('%s|*.*', [TextByKey('common-filter-allfiles')]);
|
|
|
|
|
try
|
|
|
|
|
if OpenDialog.Execute then
|
|
|
|
|
begin
|
|
|
|
|
flist.loadFromFile(OpenDialog.filename);
|
|
|
|
|
maincp.clear;
|
|
|
|
|
maincp.ParseStringList(flist);
|
|
|
|
|
maincp.Width := Image.Width;
|
|
|
|
|
maincp.Height := Image.Height;
|
|
|
|
|
maincp.zoom := 0;
|
|
|
|
|
maincp.CalcBoundBox;
|
|
|
|
|
center[0] := maincp.center[0];
|
|
|
|
|
center[1] := maincp.center[1];
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
flist.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuManageFavoritesClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
MenuItem: TMenuItem;
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
if FavoritesForm.ShowModal = mrOK then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Favorites.Count <> 0 then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
for i := 0 to Favorites.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
s := ExtractFileName(Favorites[i]);
|
|
|
|
|
s := Copy(s, 0, length(s) - Length(ExtractFileExt(s)));
|
|
|
|
|
MenuItem := FavouriteScripts1.Find(s);
|
|
|
|
|
if MenuItem <> nil then
|
|
|
|
|
MenuItem.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
GetScripts;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.DisableFavorites;
|
|
|
|
|
var
|
|
|
|
|
MenuItem: TMenuItem;
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to Favorites.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
s := ExtractFileName(Favorites[i]);
|
|
|
|
|
s := Copy(s, 0, length(s) - Length(ExtractFileExt(s)));
|
|
|
|
|
MenuItem := FavouriteScripts1.Find(s);
|
|
|
|
|
if MenuItem <> nil then
|
|
|
|
|
MenuItem.Enabled := False;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.EnableFavorites;
|
|
|
|
|
var
|
|
|
|
|
MenuItem: TMenuItem;
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to Favorites.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
s := ExtractFileName(Favorites[i]);
|
|
|
|
|
s := Copy(s, 0, length(s) - Length(ExtractFileExt(s)));
|
|
|
|
|
MenuItem := FavouriteScripts1.Find(s);
|
|
|
|
|
if MenuItem <> nil then
|
|
|
|
|
MenuItem.Enabled := True;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.EnumerateFlamesClick(Sender: TObject);
|
|
|
|
|
var i: integer;
|
|
|
|
|
begin
|
|
|
|
|
with MainForm.ListView1.Items do
|
|
|
|
|
begin
|
|
|
|
|
BeginUpdate;
|
|
|
|
|
for i := 0 to Count - 1 do Item[i].SubItems.Clear; // AV: hide the index
|
|
|
|
|
|
|
|
|
|
if TMenuItem(Sender).Checked then
|
|
|
|
|
begin // AV: displaying the index
|
|
|
|
|
MainForm.ListView1.Column[1].Caption := ' N ';
|
|
|
|
|
if FlameEnumMode = 0 then
|
|
|
|
|
for i := 0 to Count - 1 do Item[i].SubItems.Add(IntToStr(i))
|
|
|
|
|
else
|
|
|
|
|
for i := 0 to Count - 1 do Item[i].SubItems.Add(IntToStr(i+1));
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
MainForm.ListView1.Column[1].Caption := '';
|
|
|
|
|
|
|
|
|
|
EndUpdate;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuImageSizeClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AdjustForm.PageControl.TabIndex := 3;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
AdjustForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.AddSymmetryClick(Sender: TObject);
|
|
|
|
|
var finTX: TXForm;
|
|
|
|
|
begin
|
|
|
|
|
if (Transforms + TMenuItem(Sender).Tag > NXForms) then Exit;
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
finTX := TXForm.Create;
|
|
|
|
|
finTX.Assign(MainCp.xform[Transforms]);
|
|
|
|
|
MainCp.NormalizeProbabilities;
|
|
|
|
|
add_symmetry_to_control_point(MainCp, TMenuItem(Sender).Tag);
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
MainCp.xform[Transforms].Assign(finTX);
|
|
|
|
|
ResetLocation;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
finTX.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.AddTemplateClick(Sender: TObject); // AV
|
|
|
|
|
var
|
|
|
|
|
tmpdir: string;
|
|
|
|
|
begin
|
|
|
|
|
tmpdir := AppPath + 'Templates\';
|
|
|
|
|
if not DirectoryExists(tmpdir) then
|
|
|
|
|
CreateDir(tmpdir);
|
|
|
|
|
|
|
|
|
|
with SaveForm do
|
|
|
|
|
begin
|
|
|
|
|
SaveType := stSaveTemplate;
|
|
|
|
|
Filename := tmpdir + 'Fractal Templates.template';
|
|
|
|
|
Title := maincp.name;
|
|
|
|
|
ActiveControl := txtTitle;
|
|
|
|
|
if ShowModal = mrOK then
|
|
|
|
|
begin
|
|
|
|
|
maincp.name := Title;
|
|
|
|
|
StatusBar.Panels[3].Text := maincp.name;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
if SaveXMLFlame(maincp, maincp.name, Filename) and (FileName = OpenFile) then
|
|
|
|
|
AddFlameToList;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.AddTileClick(Sender: TObject);
|
|
|
|
|
var finTX: TXForm;
|
|
|
|
|
begin
|
|
|
|
|
if (Transforms + 6 > NXForms) then Exit;
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
finTX := TXForm.Create;
|
|
|
|
|
finTX.Assign(MainCp.xform[Transforms]);
|
|
|
|
|
MainCp.NormalizeProbabilities;
|
|
|
|
|
tile_control_point(MainCp, TMenuItem(Sender).Tag);
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
MainCp.xform[Transforms].Assign(finTX);
|
|
|
|
|
ResetLocation;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
finTX.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// AV: make a common event handler for Main and Adjust forms
|
|
|
|
|
procedure TMainForm.ApplicationEventsActivate(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if GradientInClipboard then
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.mnuPaste.enabled := true;
|
|
|
|
|
AdjustForm.btnPaste.enabled := true;
|
|
|
|
|
mnuPaste.enabled := false;
|
|
|
|
|
end
|
|
|
|
|
else if FlameInClipboard then
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.mnuPaste.enabled := false;
|
|
|
|
|
AdjustForm.btnPaste.enabled := false;
|
|
|
|
|
if (pos('Memorized XForm Parameters', Clipboard.AsText) > 0) then
|
|
|
|
|
mnuPaste.enabled := False // AV: hack
|
|
|
|
|
else
|
|
|
|
|
mnuPaste.Enabled := true;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.mnuPaste.enabled := false;
|
|
|
|
|
AdjustForm.btnPaste.enabled := false;
|
|
|
|
|
mnuPaste.enabled := false;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ParseXML(var cp1: TControlPoint; const params: string; const ignoreErrors : boolean);
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
nxform := 0;
|
|
|
|
|
FinalXformLoaded := false;
|
|
|
|
|
ActiveXformSet := 0;
|
|
|
|
|
XMLPaletteFormat := '';
|
|
|
|
|
XMLPaletteCount := 0;
|
|
|
|
|
SurpressHandleMissingPlugins := ignoreErrors;
|
|
|
|
|
|
|
|
|
|
ParseCp.Free; // we're creating this CP from the scratch
|
|
|
|
|
ParseCp := TControlPoint.create; // to reset variables properly (randomize)
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
XMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(params)));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
XMLScanner.Execute;
|
|
|
|
|
|
|
|
|
|
cp1.copy(ParseCp);
|
|
|
|
|
|
|
|
|
|
if (Parsecp.cmapindex = -2) then
|
|
|
|
|
begin
|
|
|
|
|
if cp1.cmapindex < NRCMAPS then
|
|
|
|
|
GetCMap(cp1.cmapindex, 1, cp1.cmap)
|
|
|
|
|
{else
|
|
|
|
|
ShowMessage('Palette index too high')};
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RotateCMapHue(cp1); // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if FinalXformLoaded = false then begin
|
|
|
|
|
cp1.xform[nxform].Clear;
|
|
|
|
|
cp1.xform[nxform].symmetry := 1;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if nxform < NXFORMS then
|
|
|
|
|
for i := nxform to NXFORMS - 1 do
|
|
|
|
|
cp1.xform[i].density := 0;
|
|
|
|
|
|
|
|
|
|
// Check for symmetry parameter
|
|
|
|
|
if ParseCp.symmetry <> 0 then
|
|
|
|
|
begin
|
|
|
|
|
add_symmetry_to_control_point(cp1, ParseCp.symmetry);
|
|
|
|
|
cp1.symmetry := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
cp1.FillUsedPlugins;
|
|
|
|
|
SurpressHandleMissingPlugins := false;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.PasteFlameXML(flameXML: string); // AV
|
|
|
|
|
begin
|
|
|
|
|
if (flameXML <> '') then
|
|
|
|
|
begin
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// StopScripter;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
StopThread;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParseXML(MainCP, flameXML, false); // AV: fixed - was PChar instead String
|
2022-03-08 12:25:51 -05:00
|
|
|
|
AnnoyUser;
|
|
|
|
|
Transforms := MainCp.TrianglesFromCP(MainTriangles);
|
|
|
|
|
Statusbar.Panels[3].Text := MainCp.name;
|
|
|
|
|
if AutoSaveXML then // AV: saving loaded parameters in the current file
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
while XMLEntryExists(MainCp.name, OpenFile) do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainCp.name := MainCp.name + ' (new)'; // hmm...
|
|
|
|
|
if (OpenFile = AppPath + randfilename) then // random batch will be deleted
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SaveXMLFlame(MainCp, MainCp.name, IfThen(DirectoryExists(ExtractFilePath(AutoSavePath)),
|
|
|
|
|
ExtractFilePath(AutoSavePath), AppPath) + 'Saved by ApophysisAV.flame'); // :)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// AV: display these changes and scroll to the selected item
|
|
|
|
|
if SaveXMLFlame(MainCp, MainCp.name, OpenFile) then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
AddFlameToList; // AV: show the new item
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
ResizeImage;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
Application.ProcessMessages;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuPasteClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
//if Clipboard.HasFormat(CF_TEXT) then
|
|
|
|
|
if FlameInClipboard then // AV
|
|
|
|
|
PasteFlameXML(Clipboard.AsText);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuCopyClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
txt: string;
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
txt := Trim(FlameToXML(Maincp));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Clipboard.SetTextBuf(PChar(txt));
|
|
|
|
|
mnuPaste.enabled := true;
|
|
|
|
|
|
|
|
|
|
AdjustForm.mnuPaste.enabled := False;
|
|
|
|
|
AdjustForm.btnPaste.enabled := False;
|
|
|
|
|
|
|
|
|
|
// AV: for pasting multiple transforms into editor
|
|
|
|
|
MemCp.Clear;
|
|
|
|
|
for i := 0 to Maincp.NumXForms - 1 do //FIXME: skip final transform!
|
|
|
|
|
MemCp.xform[i].Assign(Maincp.xform[i]);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
EditForm.PasteTransform.Enabled := True;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function WinShellExecute(const Operation, AssociatedFile: string): Boolean;
|
|
|
|
|
var
|
|
|
|
|
a1: string;
|
|
|
|
|
r: Cardinal;
|
|
|
|
|
begin
|
|
|
|
|
a1 := Operation;
|
|
|
|
|
if a1 = '' then
|
|
|
|
|
a1 := 'open';
|
|
|
|
|
|
|
|
|
|
r := ShellExecute(
|
2022-06-23 06:22:32 -04:00
|
|
|
|
application.handle,
|
|
|
|
|
pchar(a1),
|
|
|
|
|
pchar(AssociatedFile),
|
|
|
|
|
'',
|
|
|
|
|
'',
|
|
|
|
|
SW_SHOWNORMAL
|
2022-03-08 12:25:51 -05:00
|
|
|
|
);
|
|
|
|
|
if (r > 32) then WinShellExecute := true
|
|
|
|
|
else WinShellExecute := false;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure WinShellOpen(const AssociatedFile: string);
|
|
|
|
|
begin
|
|
|
|
|
WinShellExecute('open', AssociatedFile);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuExportFlameClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
FileList: Tstringlist;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Ext: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
cp1: TControlPoint;
|
|
|
|
|
begin
|
|
|
|
|
if not FileExists(flam3Path) then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Application.MessageBox(PChar(TextByKey('main-status-noflam3')), ApophysisSVN, 16);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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
|
2022-06-23 06:22:32 -04:00
|
|
|
|
1: Ext := '.jpg';
|
|
|
|
|
2: Ext := '.ppm';
|
|
|
|
|
3: Ext := '.png';
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
FileList := TstringList.Create;
|
|
|
|
|
cp1 := TControlPoint.Create;
|
|
|
|
|
cp1.copy(Maincp);
|
|
|
|
|
ExportDialog.ImageWidth := ExportWidth;
|
|
|
|
|
ExportDialog.ImageHeight := ExportHeight;
|
|
|
|
|
ExportDialog.Sample_density := ExportDensity;
|
|
|
|
|
ExportDialog.Filter_Radius := ExportFilter;
|
|
|
|
|
ExportDialog.Oversample := ExportOversample;
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ExportDialog.Filename := RenderPath + Maincp.name + Ext;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if ExportDialog.ShowModal = mrOK then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Ext := ExtractFileExt(ExportDialog.Filename);
|
|
|
|
|
if Ext = '.ppm' then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ExportFileFormat := 2
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else if Ext = '.png' then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ExportFileFormat := 3
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else // if Ext = '.jpg' then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ExportFileFormat := 1;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Delete(Ext, 1, 1);
|
|
|
|
|
{
|
2022-03-08 12:25:51 -05:00
|
|
|
|
case ExportFileFormat of
|
|
|
|
|
1: Ext := 'jpg';
|
|
|
|
|
2: Ext := 'ppm';
|
|
|
|
|
3: Ext := 'png';
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ExportWidth := ExportDialog.ImageWidth;
|
|
|
|
|
ExportHeight := ExportDialog.ImageHeight;
|
|
|
|
|
ExportDensity := ExportDialog.Sample_density;
|
|
|
|
|
ExportFilter := ExportDialog.Filter_Radius;
|
|
|
|
|
ExportOversample := ExportDialog.Oversample;
|
|
|
|
|
ExportEstimator := ExportDialog.Estimator;
|
|
|
|
|
ExportEstimatorMin := ExportDialog.EstimatorMin;
|
|
|
|
|
ExportEstimatorCurve := ExportDialog.EstimatorCurve;
|
|
|
|
|
ExportGammaTreshold := ExportDialog.GammaTreshold;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: user cannot change the following, anyway
|
|
|
|
|
//ExportJitters := ExportDialog.Jitters;
|
|
|
|
|
//ExportBatches := ExportDialog.Batches;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
cp1.sample_density := ExportDensity;
|
|
|
|
|
cp1.spatial_oversample := ExportOversample;
|
|
|
|
|
cp1.spatial_filter_radius := ExportFilter;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
cp1.nbatches := 1; //ExportBatches;
|
|
|
|
|
cp1.jitters := 1; //ExportJitters;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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.gamma_threshold := ExportGammaTreshold;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FileList.Text := FlameToXML(cp1, true);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
FileList.SaveToFile(ChangeFileExt(ExportDialog.Filename, '.flame'));
|
|
|
|
|
FileList.Clear;
|
|
|
|
|
FileList.Add('@echo off');
|
|
|
|
|
FileList.Add('set verbose=1');
|
|
|
|
|
FileList.Add('set format=' + Ext);
|
|
|
|
|
if ExportFileFormat = 1 then
|
|
|
|
|
FileList.Add('set jpeg=' + IntToStr(JPEGQuality));
|
|
|
|
|
case ExportDialog.cmbDepth.ItemIndex of
|
|
|
|
|
0: FileList.Add('set bits=16');
|
|
|
|
|
1: FileList.Add('set bits=32');
|
|
|
|
|
2: FileList.Add('set bits=33');
|
|
|
|
|
3: FileList.Add('set bits=64');
|
|
|
|
|
end;
|
|
|
|
|
if ExportDialog.udStrips.Position > 1 then
|
|
|
|
|
FileList.Add('set nstrips=' + IntToStr(ExportDialog.udStrips.Position));
|
|
|
|
|
if (PNGTransparency > 0) then
|
|
|
|
|
FileList.Add('set transparency=1')
|
|
|
|
|
else
|
|
|
|
|
FileList.Add('set transparency=0');
|
|
|
|
|
FileList.Add('set out=' + ExportDialog.Filename);
|
|
|
|
|
FileList.Add('@echo Rendering "' + ExportDialog.Filename + '"');
|
|
|
|
|
|
|
|
|
|
FileList.Add('"' + flam3Path + '" < "' + ChangeFileExt(ExportDialog.Filename, '.flame') + '"');
|
|
|
|
|
FileList.SaveToFile(ChangeFileExt(ExportDialog.Filename, '.bat'));
|
|
|
|
|
if ExportDialog.chkRender.Checked then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SetCurrentDir(ExtractFilePath(ExportDialog.Filename));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
WinShellOpen(ChangeFileExt(ExportDialog.Filename, '.bat'));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
FileList.Free;
|
|
|
|
|
cp1.free;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ExportDialog.Free; // AV: destroying unnecessary form
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
procedure ParseCompactColors(cp: TControlPoint; count: integer; in_data: string; alpha: boolean = true);
|
|
|
|
|
function HexChar(c: Char): Byte;
|
|
|
|
|
begin
|
|
|
|
|
case c of
|
|
|
|
|
'0'..'9': Result := Byte(c) - Byte('0');
|
|
|
|
|
'a'..'f': Result := (Byte(c) - Byte('a')) + 10;
|
|
|
|
|
'A'..'F': Result := (Byte(c) - Byte('A')) + 10;
|
|
|
|
|
else
|
|
|
|
|
Result := 0;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
var
|
|
|
|
|
i, pos, len: integer;
|
|
|
|
|
c: char;
|
|
|
|
|
data: string;
|
|
|
|
|
begin
|
|
|
|
|
// diable generating pallete
|
|
|
|
|
if Parsecp.cmapindex = -2 then
|
|
|
|
|
Parsecp.cmapindex := -1;
|
|
|
|
|
|
|
|
|
|
Assert(Count = 256, 'only 256 color gradients are supported at the moment');
|
|
|
|
|
data := '';
|
|
|
|
|
for i := 1 to Length(in_data) do
|
|
|
|
|
begin
|
|
|
|
|
c := in_data[i];
|
|
|
|
|
if CharInSet(c,['0'..'9']+['A'..'F']+['a'..'f']) then data := data + c;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if alpha then len := count * 8
|
|
|
|
|
else len := count * 6;
|
|
|
|
|
|
|
|
|
|
Assert(len = Length(data), 'color-data size mismatch');
|
|
|
|
|
|
|
|
|
|
for i := 0 to Count-1 do begin
|
|
|
|
|
if alpha then pos := i*8 + 2
|
|
|
|
|
else pos := i*6;
|
|
|
|
|
Parsecp.cmap[i][0] := 16 * HexChar(Data[pos + 1]) + HexChar(Data[pos + 2]);
|
|
|
|
|
Parsecp.cmap[i][1] := 16 * HexChar(Data[pos + 3]) + HexChar(Data[pos + 4]);
|
|
|
|
|
Parsecp.cmap[i][2] := 16 * HexChar(Data[pos + 5]) + HexChar(Data[pos + 6]);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ListXmlScannerStartTag(Sender: TObject;
|
|
|
|
|
TagName: string; Attributes: TAttrList);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (TagName = 'flame') then begin // AV: fixed
|
|
|
|
|
pname := string(Attributes.value('name'));
|
|
|
|
|
ptime := string(Attributes.value('time'));
|
|
|
|
|
// pversion := string(Attributes.value('version'));
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.XMLScannerStartTag(Sender: TObject; TagName: string;
|
|
|
|
|
Attributes: TAttrList);
|
|
|
|
|
var
|
|
|
|
|
Tokens: TStringList;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v: string; //TStringType;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ParsePos, i : integer;
|
|
|
|
|
begin
|
|
|
|
|
Tokens := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
|
|
|
|
|
if TagName='xformset' then // unused in this release...
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('enabled'));
|
|
|
|
|
if v <> '' then ParseCP.finalXformEnabled := (StrToInt(v) <> 0)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else ParseCP.finalXformEnabled := true;
|
|
|
|
|
|
|
|
|
|
inc(activeXformSet);
|
|
|
|
|
end
|
|
|
|
|
else if TagName='flame' then
|
|
|
|
|
begin
|
|
|
|
|
BeginParsing;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.value('version')); // AV
|
|
|
|
|
if (pos('Apophysis 2.0', v) > 0) or (v = '') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
oldApo := true else oldApo := false;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Parsecp.cmapindex := StrToInt(v)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
|
|
|
|
Parsecp.cmapindex := -1;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.value('gradient'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Parsecp.cmapindex := StrToInt(v)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
|
|
|
|
Parsecp.cmapindex := -1;
|
|
|
|
|
|
|
|
|
|
//ParseCP.hue_rotation := 1;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.value('hue')); // AV: to animate the palette
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Parsecp.hue_rotation := StrToFloat(v)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
|
|
|
|
ParseCP.hue_rotation := 1;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (LimitVibrancy) and (Parsecp.vibrancy > 1) then Parsecp.vibrancy := 1;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('gamma_threshold'));
|
|
|
|
|
if v <> '' then Parsecp.gamma_threshold := StrToFloat(v)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else Parsecp.gamma_threshold := 0;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// 3d
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
//density estimation
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v = '1') then Parsecp.enable_de := true;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('new_linear'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v = '1') then // AV
|
|
|
|
|
Parsecp.noLinearFix := true
|
|
|
|
|
else ParseCp.noLinearFix := false;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('curves'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ParsePos := -1;
|
|
|
|
|
for i := 0 to 3 do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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]);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('center'));
|
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
Parsecp.center[0] := StrToFloat(Tokens[0]);
|
|
|
|
|
Parsecp.center[1] := StrToFloat(Tokens[1]);
|
|
|
|
|
except
|
|
|
|
|
Parsecp.center[0] := 0;
|
|
|
|
|
Parsecp.center[1] := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('size'));
|
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
Parsecp.width := StrToInt(Tokens[0]);
|
|
|
|
|
Parsecp.height := StrToInt(Tokens[1]);
|
|
|
|
|
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('background'));
|
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
Parsecp.background[0] := Floor(StrToFloat(Tokens[0]) * 255);
|
|
|
|
|
Parsecp.background[1] := Floor(StrToFloat(Tokens[1]) * 255);
|
|
|
|
|
Parsecp.background[2] := Floor(StrToFloat(Tokens[2]) * 255);
|
|
|
|
|
except
|
|
|
|
|
Parsecp.background[0] := 0;
|
|
|
|
|
Parsecp.background[1] := 0;
|
|
|
|
|
Parsecp.background[2] := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('soloxform'));
|
|
|
|
|
if v <> '' then Parsecp.soloXform := StrToInt(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('plugins'));
|
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (tokens.Count > 0) then begin
|
|
|
|
|
ParseCP.used_plugins.Clear;
|
|
|
|
|
|
|
|
|
|
for i := 0 to tokens.Count - 1 do
|
|
|
|
|
ParseCP.used_plugins.Add(tokens[i]);
|
|
|
|
|
end;
|
|
|
|
|
(* // AV: commented out since it's useless
|
|
|
|
|
v := Attributes.Value('nick');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Trim(v) = '' then v := SheepNick;
|
|
|
|
|
Parsecp.Nick := v;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
v := Attributes.Value('url');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Trim(v) = '' then v := SheepUrl;
|
|
|
|
|
Parsecp.URL := v;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
*)
|
|
|
|
|
end
|
|
|
|
|
else if TagName='palette' then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
XMLPaletteFormat := string(Attributes.Value('format'));
|
|
|
|
|
XMLPaletteCount := StrToIntDef(string(Attributes.Value('count')), 256);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Tokens.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function flatten_val(Attributes: TAttrList): double;
|
|
|
|
|
var
|
|
|
|
|
vv: array of double;
|
|
|
|
|
vn: array of string;
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
|
|
|
|
d: boolean;
|
|
|
|
|
begin
|
|
|
|
|
// AV: invert the behavior since it flatten real 3D figures like bubble
|
|
|
|
|
vn := ['crop', 'auger', 'bipolar', 'blur', 'blur_circle', 'blur_pixelize',
|
|
|
|
|
'blur_zoom', 'horseshoe', 'diamond', 'disc', 'bent2', 'escher', 'eyefish',
|
|
|
|
|
'fan2', 'flux', 'foci', 'log', 'bwraps', 'juliascope', 'julian', 'mobius',
|
|
|
|
|
'noise', 'ngon', 'curl', 'rings2', 'scry', 'spherical', 'spiral', 'cropn',
|
|
|
|
|
'swirl', 'wedge', 'checks', 'polar', 'polar2', 'linear', 'cross', 'pdj',
|
|
|
|
|
'hyperbolic', 'radial_blur', 'elliptic', 'lazysusan', 'post_smartcrop',
|
|
|
|
|
'circlecrop', 'rectangles'];
|
|
|
|
|
|
|
|
|
|
SetLength(vv, length(vn)); // AV
|
|
|
|
|
|
|
|
|
|
d := false;
|
|
|
|
|
for i := 0 to High(vn) do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := string(Attributes.Value(Utf8String(vn[i])));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (s <> '') then vv[i] := StrToFloat(s)
|
|
|
|
|
else vv[i] := 0;
|
|
|
|
|
d := d or (vv[i] <> 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// AV: changed 0 to 1 and vice versa
|
|
|
|
|
if (d) then Result := 1
|
|
|
|
|
else Result := 0;
|
|
|
|
|
|
|
|
|
|
SetLength(vv, 0);
|
|
|
|
|
SetLength(vn, 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function linear_val(Attributes: TAttrList): double;
|
|
|
|
|
var
|
|
|
|
|
vv: array of double;
|
|
|
|
|
vn: array of string;
|
|
|
|
|
i: integer;
|
|
|
|
|
s: string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
begin
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetLength(vv, 2);
|
|
|
|
|
vn := ['linear3D', 'linear'];
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Result := 0;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to 1 do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := string(Attributes.Value(Utf8String(vn[i])));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (s <> '') then vv[i] := StrToFloat(s)
|
|
|
|
|
else vv[i] := 0;
|
|
|
|
|
Result := Result + vv[i];
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
SetLength(vv, 0);
|
|
|
|
|
SetLength(vn, 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.XmlScannerContent(Sender: TObject; Content: String);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if XMLPaletteCount <= 0 then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
//ShowMessage('ERROR: No colors in palette!');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
raise Exception.Create(TextByKey('common-invalidformat') + ': palette'); // AV
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if XMLPaletteFormat = 'RGB' then
|
|
|
|
|
begin
|
|
|
|
|
ParseCompactColors(ParseCP, XMLPaletteCount, Content, false);
|
|
|
|
|
end
|
|
|
|
|
else if XMLPaletteFormat = 'RGBA' then
|
|
|
|
|
begin
|
|
|
|
|
ParseCompactColors(ParseCP, XMLPaletteCount, Content);
|
|
|
|
|
end
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else
|
|
|
|
|
raise Exception.Create(TextByKey('common-invalidformat') + ': palette'); // AV
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Parsecp.cmapindex := -1;
|
|
|
|
|
|
|
|
|
|
// AV: restored hue rotation support, useful for animation
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RotateCMapHue(Parsecp);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
XMLPaletteFormat := '';
|
|
|
|
|
XMLPaletteCount := 0;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.XMLScannerEmptyTag(Sender: TObject; TagName: string;
|
|
|
|
|
Attributes: TAttrList);
|
|
|
|
|
var
|
|
|
|
|
i, j, k, vindex: integer; // j, k - AV
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v, l, s: string; //TStringType;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
d, floatcolor, vl, n: double;
|
|
|
|
|
Tokens: TStringList;
|
|
|
|
|
begin
|
|
|
|
|
|
|
|
|
|
Tokens := TStringList.Create;
|
|
|
|
|
try
|
|
|
|
|
if (TagName = 'xform') or (TagName = 'finalxform') then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if {(TagName = 'finalxform') and} (FinalXformLoaded) then
|
|
|
|
|
Application.MessageBox(PChar(TextByKey('common-invalidformat')), ApophysisSVN, MB_ICONERROR)
|
|
|
|
|
// ShowMessage('ERROR: No xforms allowed after FinalXform!')
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else
|
2022-06-23 06:22:32 -04:00
|
|
|
|
begin // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to Attributes.Count - 1 do begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if not ScanVariations(string(attributes.Name(i))) and
|
|
|
|
|
not ScanVariables(string(attributes.Name(i))) then
|
|
|
|
|
CheckAttribute(string(Attributes.Name(i)));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
if (TagName = 'finalxform') or (activeXformSet > 0) then FinalXformLoaded := true;
|
|
|
|
|
|
|
|
|
|
with ParseCP.xform[nXform] do begin
|
|
|
|
|
Clear;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('weight'));
|
|
|
|
|
if (v <> '') and (TagName = 'xform') then density := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (TagName = 'finalxform') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('enabled'));
|
|
|
|
|
if v <> '' then ParseCP.finalXformEnabled := (StrToInt(v) <> 0)
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else ParseCP.finalXformEnabled := true;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if activexformset > 0 then density := 0; // tmp...
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//**************** AV: checking variation order ***********//
|
|
|
|
|
v := string(Attributes.Value('var_order'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
k := -1;
|
|
|
|
|
for j := 0 to Tokens.Count-1 do
|
|
|
|
|
begin
|
|
|
|
|
vindex := ifs.IndexOf(Tokens[j]);
|
|
|
|
|
if vindex >= 0 then
|
|
|
|
|
begin
|
|
|
|
|
inc(k);
|
|
|
|
|
ifs.Move(vindex, k);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//************************************************************//
|
|
|
|
|
|
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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]);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('post'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
GetTokens(v, tokens);
|
|
|
|
|
if Tokens.Count < 6 then
|
|
|
|
|
Application.MessageBox(PChar(TextByKey('common-invalidformat') + ': post'),
|
|
|
|
|
ApophysisSVN, MB_ICONERROR);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
p[0][0] := StrToFloat(Tokens[0]);
|
|
|
|
|
p[0][1] := StrToFloat(Tokens[1]);
|
|
|
|
|
p[1][0] := StrToFloat(Tokens[2]);
|
|
|
|
|
p[1][1] := StrToFloat(Tokens[3]);
|
|
|
|
|
p[2][0] := StrToFloat(Tokens[4]);
|
|
|
|
|
p[2][1] := StrToFloat(Tokens[5]);
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('chaos'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('opacity'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if StrToFloat(v) = 0.0 then begin
|
2022-03-08 12:25:51 -05:00
|
|
|
|
transOpacity := 0;
|
|
|
|
|
end else begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
transOpacity := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// 7x.9 name tag
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('name'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
TransformName := v;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('plotmode'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
|
|
|
|
if v = 'off' then begin
|
|
|
|
|
transOpacity := 0;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// tricky: attempt to convert parameters to 15C+-format if necessary
|
|
|
|
|
if ParseCp.noLinearFix then
|
|
|
|
|
for i := 0 to 1 do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := ReadWithSubst(Attributes, varnames(i));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SetVariation(i, StrToFloat(v))
|
|
|
|
|
else
|
|
|
|
|
SetVariation(i, 0);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
SetVariation(0, linear_val(Attributes));
|
|
|
|
|
if ApplyFlatten then // AV
|
|
|
|
|
SetVariation(1, flatten_val(Attributes));
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// now parse the rest of the variations...as usual
|
|
|
|
|
for i := 2 to NRVAR - 1 do
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := ReadWithSubst(Attributes, varnames(i));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SetVariation(i, StrToFloat(v))
|
|
|
|
|
else
|
|
|
|
|
SetVariation(i, 0);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// and the variables
|
|
|
|
|
for i := 0 to GetNrVariableNames - 1 do begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := GetVariableNameAt(i);
|
|
|
|
|
v := ReadWithSubst(Attributes, s);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then begin
|
|
|
|
|
{$ifndef VAR_STR}
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
|
|
|
|
SetVariable(s, d);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{$else}
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SetVariableStr(s, v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{$endif}
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
{***** AV: tryig to convert old Apo 2.0x variations into new ones *****}
|
|
|
|
|
if oldApo then begin
|
|
|
|
|
// AV: 'perspective' into 'projective'
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('perspective'));
|
|
|
|
|
s := string(Attributes.Value('projective'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') and (s = '') then // avoid to overwrite
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('projective'), d);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('perspective_dist'));
|
|
|
|
|
l := string(Attributes.Value('perspective_angle'));
|
|
|
|
|
vl := StrToFloat(v); // dist
|
|
|
|
|
d := StrToFloat(l); // angle
|
2022-03-08 12:25:51 -05:00
|
|
|
|
n := 0;
|
|
|
|
|
SetVariable('pr_A', n);
|
|
|
|
|
SetVariable('pr_B1', n);
|
|
|
|
|
SetVariable('pr_C1', n);
|
|
|
|
|
SetVariable('pr_A2', n);
|
|
|
|
|
SetVariable('pr_C2', n);
|
|
|
|
|
SetVariable('pr_A1', vl);
|
|
|
|
|
SetVariable('pr_C', vl);
|
|
|
|
|
n := -sin(d * pi * 0.5);
|
|
|
|
|
SetVariable('pr_B', n);
|
|
|
|
|
n := vl * cos(d * pi * 0.5);
|
|
|
|
|
SetVariable('pr_B2', n);
|
|
|
|
|
n := 1;
|
|
|
|
|
SetVariable('projective_mode', n);
|
|
|
|
|
end
|
|
|
|
|
else if (v <> '') and (s <> '') then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
begin
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MissingPlugin.MissingPluginList.Add('perspective');
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MissingPlugin.MissingPluginList.Add('perspective_angle');
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('perspective_dist');
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('rings'));
|
|
|
|
|
s := string(Attributes.Value('rings2'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') and (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('rings2'), d);
|
|
|
|
|
n := c[2][0];
|
|
|
|
|
SetVariable('rings2_val', n);
|
|
|
|
|
n := 1;
|
|
|
|
|
SetVariable('rings2_old', n);
|
|
|
|
|
end
|
|
|
|
|
else if (v <> '') and (s <> '') then
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('rings');
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('fan'));
|
|
|
|
|
s := string(Attributes.Value('fan2'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') and (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('fan2'), d);
|
|
|
|
|
n := c[2][0];
|
|
|
|
|
SetVariable('fan2_x', n);
|
|
|
|
|
n := c[2][1];
|
|
|
|
|
SetVariable('fan2_y', n);
|
|
|
|
|
n := 0; // AV: it is 1 only for 2.09 'fan2'
|
|
|
|
|
SetVariable('fan2_old', n);
|
|
|
|
|
end
|
|
|
|
|
else if (v <> '') and (s <> '') then
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('fan');
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('bent'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := string(Attributes.Value('bent2'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('bent2'), d);
|
|
|
|
|
n := 2;
|
|
|
|
|
SetVariable('bent2_x', n);
|
|
|
|
|
n := 0.5;
|
|
|
|
|
SetVariable('bent2_y', n);
|
|
|
|
|
n := 1;
|
|
|
|
|
SetVariable('bent2_z', n);
|
|
|
|
|
end
|
|
|
|
|
else MissingPlugin.MissingPluginList.Add('bent');
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('waves'));
|
|
|
|
|
s := string(Attributes.Value('waves2'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') and (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('waves2'), d);
|
|
|
|
|
n := c[1][0];
|
|
|
|
|
SetVariable('waves2_scalex', n);
|
|
|
|
|
n := 1/(sqr(c[2][0]) + 1E-300);
|
|
|
|
|
SetVariable('waves2_freqx', n);
|
|
|
|
|
n := c[1][1];
|
|
|
|
|
SetVariable('waves2_scaley', n);
|
|
|
|
|
n := 1/(sqr(c[2][1]) + 1E-300);
|
|
|
|
|
SetVariable('waves2_freqy', n);
|
|
|
|
|
n := 0;
|
|
|
|
|
SetVariable('waves2_scalez', n);
|
|
|
|
|
SetVariable('waves2_freqz', n);
|
|
|
|
|
end
|
|
|
|
|
else if (v <> '') and (s <> '') then
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('waves');
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('popcorn'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := string(Attributes.Value('popcorn2'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (s = '') then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
d := StrToFloat(v);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(GetVariationIndex('popcorn2'), d);
|
|
|
|
|
n := c[2][0];
|
|
|
|
|
SetVariable('popcorn2_x', n);
|
|
|
|
|
n := c[2][1];
|
|
|
|
|
SetVariable('popcorn2_y', n);
|
|
|
|
|
n := 3;
|
|
|
|
|
SetVariable('popcorn2_c', n);
|
|
|
|
|
end
|
|
|
|
|
else MissingPlugin.MissingPluginList.Add('popcorn');
|
|
|
|
|
end;
|
|
|
|
|
end; // oldApo
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: Droste into Escher
|
|
|
|
|
v := string(Attributes.Value('droste'));
|
|
|
|
|
s := string(Attributes.Value('escher'));
|
|
|
|
|
if (v <> '') and (s = '') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else if (v <> '') and (s <> '') then
|
|
|
|
|
begin
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('droste');
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('droste_r1');
|
|
|
|
|
MissingPlugin.MissingPluginList.Add('droste_r2');
|
|
|
|
|
end;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// Spherical3D into inversion3D
|
|
|
|
|
v := string(Attributes.Value('Spherical3D'));
|
|
|
|
|
if (v <> '') and (GetVariationIndex('Spherical3D')< 0) then
|
|
|
|
|
// if plugin is NOT available
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// arch into Z_arch
|
|
|
|
|
v := string(Attributes.Value('arch'));
|
|
|
|
|
if (v <> '') then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{********************************************************}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// legacy variation/variable notation
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('var1'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to NRVAR - 1 do
|
|
|
|
|
SetVariation(i, 0);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
SetVariation(StrToInt(v), 1);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value('var'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if v <> '' then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to NRVAR - 1 do
|
|
|
|
|
SetVariation(i, 0);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
GetTokens(v, tokens);
|
|
|
|
|
if Tokens.Count > NRVAR then
|
|
|
|
|
Application.MessageBox(PChar(TextByKey('common-invalidformat')),
|
|
|
|
|
ApophysisSVN, MB_ICONERROR);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to Tokens.Count - 1 do
|
|
|
|
|
SetVariation(i, StrToFloat(Tokens[i]));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: prevent crash with flames containing over 100 xforms
|
|
|
|
|
{$ifndef T500}
|
|
|
|
|
if nXform < NXFORMS then
|
|
|
|
|
{$endif}
|
|
|
|
|
Inc(nXform);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
if TagName = 'color' then
|
|
|
|
|
begin
|
|
|
|
|
// disable generating palette
|
|
|
|
|
//if Parsecp.cmapindex = -2 then
|
|
|
|
|
Parsecp.cmapindex := -1;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i := StrToInt(string(Attributes.value('index')));
|
|
|
|
|
v := string(Attributes.value('rgb'));
|
|
|
|
|
GetTokens(v, tokens);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
floatcolor := StrToFloat(Tokens[0]);
|
|
|
|
|
Parsecp.cmap[i][0] := round(floatcolor);
|
|
|
|
|
floatcolor := StrToFloat(Tokens[1]);
|
|
|
|
|
Parsecp.cmap[i][1] := round(floatcolor);
|
|
|
|
|
floatcolor := StrToFloat(Tokens[2]);
|
|
|
|
|
Parsecp.cmap[i][2] := round(floatcolor);
|
|
|
|
|
end;
|
|
|
|
|
if TagName = 'colors' then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
ParseCompactcolors(Parsecp, StrToInt(string(Attributes.value('count'))),
|
|
|
|
|
string(Attributes.value('data')));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Parsecp.cmapindex := -1;
|
|
|
|
|
end;
|
|
|
|
|
if TagName = 'symmetry' then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i := StrToInt(string(Attributes.value('kind')));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Parsecp.symmetry := i;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if TagName = 'xdata' then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Parsecp.xdata := Parsecp.xdata + string(Attributes.value('content'));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
finally
|
|
|
|
|
Tokens.free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuFlamepdfClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
WinShellOpen('http://www.flam3.com/flame_draves.pdf');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuFlattenClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
i, j, t: integer;
|
|
|
|
|
v: double;
|
|
|
|
|
refresh: boolean;
|
|
|
|
|
flat: array of integer;
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
refresh := False;
|
|
|
|
|
// AV: using new Delphi's feature for dynamic arrays
|
|
|
|
|
flat := [GetVariationIndex('crop'), GetVariationIndex('auger'),
|
|
|
|
|
GetVariationIndex('bipolar'), GetVariationIndex('blur'),
|
|
|
|
|
GetVariationIndex('blur_circle'), GetVariationIndex('blur_pixelize'),
|
|
|
|
|
GetVariationIndex('blur_zoom'), GetVariationIndex('horseshoe'),
|
|
|
|
|
GetVariationIndex('diamond'), GetVariationIndex('disc'),
|
|
|
|
|
GetVariationIndex('bent2'), GetVariationIndex('escher'),
|
|
|
|
|
GetVariationIndex('eyefish'), GetVariationIndex('fan2'),
|
|
|
|
|
GetVariationIndex('flux'), GetVariationIndex('foci'),
|
|
|
|
|
GetVariationIndex('log'), GetVariationIndex('bwraps'),
|
|
|
|
|
GetVariationIndex('juliascope'), GetVariationIndex('julian'),
|
|
|
|
|
GetVariationIndex('mobius'), GetVariationIndex('noise'),
|
|
|
|
|
GetVariationIndex('ngon'), GetVariationIndex('curl'),
|
|
|
|
|
GetVariationIndex('rings2'), GetVariationIndex('scry'),
|
|
|
|
|
GetVariationIndex('spherical'), GetVariationIndex('spiral'),
|
|
|
|
|
GetVariationIndex('circlecrop'), GetVariationIndex('swirl'),
|
|
|
|
|
GetVariationIndex('wedge'), GetVariationIndex('rectangles'),
|
|
|
|
|
GetVariationIndex('polar'), GetVariationIndex('polar2'),
|
|
|
|
|
GetVariationIndex('linear'), GetVariationIndex('cross'),
|
|
|
|
|
GetVariationIndex('pdj'), GetVariationIndex('hyperbolic'),
|
|
|
|
|
GetVariationIndex('radial_blur'), GetVariationIndex('elliptic'),
|
|
|
|
|
GetVariationIndex('lazysusan'), GetVariationIndex('checks'),
|
|
|
|
|
GetVariationIndex('cropn'), GetVariationIndex('post_smartcrop')];
|
|
|
|
|
|
|
|
|
|
if maincp.HasFinalXForm then t := Transforms
|
|
|
|
|
else t := Transforms - 1;
|
|
|
|
|
|
|
|
|
|
for i := 0 to t do
|
|
|
|
|
for j in flat do // AV: iterate only for chosen variation indices
|
|
|
|
|
begin
|
|
|
|
|
if (j < 0) then continue;
|
|
|
|
|
v := maincp.xform[i].GetVariation(j);
|
|
|
|
|
if (v <> 0) and (maincp.xform[i].GetVariation(1) = 0) then
|
|
|
|
|
begin
|
|
|
|
|
maincp.xform[i].SetVariation(1, 1); // apply flatten
|
|
|
|
|
refresh := True;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if refresh then
|
|
|
|
|
begin
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
SetLength(flat, 0);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
procedure TMainForm.ImageMouseDown(Sender: TObject; Button: TMouseButton;
|
|
|
|
|
Shift: TShiftState; X, Y: Integer);
|
|
|
|
|
begin
|
|
|
|
|
(*
|
|
|
|
|
if button = mbMiddle then begin
|
|
|
|
|
//FMouseMoveState := msHeight;
|
|
|
|
|
exit;
|
|
|
|
|
end else if button = mbRight then begin
|
|
|
|
|
//FMouseMoveState := msPitchYaw;
|
|
|
|
|
camDragValueY := MainCP.cameraPitch * 180.0 / PI;
|
|
|
|
|
camDragValueX := MainCP.cameraYaw * 180.0 / PI;
|
|
|
|
|
|
|
|
|
|
camDragMode := true;
|
|
|
|
|
camDragPos.x := 0;
|
|
|
|
|
camDragPos.y := 0;
|
|
|
|
|
camDragOld.x := x;
|
|
|
|
|
camDragOld.y := y;
|
|
|
|
|
camMM := false;
|
|
|
|
|
//SetCaptureControl(TControl(Sender));
|
|
|
|
|
|
|
|
|
|
//Screen.Cursor := crNone;
|
|
|
|
|
//GetCursorPos(mousepos); // hmmm
|
|
|
|
|
//mousePos := (Sender as TControl).ClientToScreen(Point(x, y));
|
|
|
|
|
camDragged := false;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
if button <> mbLeft then exit;
|
|
|
|
|
FClickRect.TopLeft := Point(x, y);
|
|
|
|
|
FClickRect.BottomRight := FClickRect.TopLeft;
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msZoomWindow:
|
|
|
|
|
begin
|
|
|
|
|
FSelectRect.TopLeft := Point(x, y);
|
|
|
|
|
FSelectRect.BottomRight := Point(x, y);
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
|
|
|
|
|
// if ssAlt in Shift then
|
|
|
|
|
// FMouseMoveState := msZoomOutWindowMove
|
|
|
|
|
// else
|
|
|
|
|
FMouseMoveState := msZoomWindowMove;
|
|
|
|
|
end;
|
|
|
|
|
msZoomOutWindow:
|
|
|
|
|
begin
|
|
|
|
|
FSelectRect.TopLeft := Point(x, y);
|
|
|
|
|
FSelectRect.BottomRight := Point(x, y);
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
|
|
|
|
|
// if ssAlt in Shift then
|
|
|
|
|
// FMouseMoveState := msZoomWindowMove
|
|
|
|
|
// else
|
|
|
|
|
FMouseMoveState := msZoomOutWindowMove;
|
|
|
|
|
end;
|
|
|
|
|
msDrag:
|
|
|
|
|
begin
|
|
|
|
|
if not assigned(FViewImage) then exit;
|
|
|
|
|
|
|
|
|
|
// FSelectRect.TopLeft := Point(x, y);
|
|
|
|
|
// FSelectRect.BottomRight := Point(x, y);
|
|
|
|
|
FMouseMoveState := msDragMove;
|
|
|
|
|
end;
|
|
|
|
|
msRotate:
|
|
|
|
|
begin
|
|
|
|
|
FClickAngle := arctan2(y - Image.Height/2, Image.Width/2 - x);
|
|
|
|
|
|
|
|
|
|
FRotateAngle := 0;
|
|
|
|
|
// FSelectRect.Left := x;
|
|
|
|
|
DrawRotateLines(FRotateAngle);
|
|
|
|
|
FMouseMoveState := msRotateMove;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.ImageMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
|
|
|
|
|
const
|
|
|
|
|
snap_angle = 0.261799387799149; // AV: the same as 15*pi/180;
|
|
|
|
|
var
|
|
|
|
|
dx, dy, cx, cy, sgn: integer;
|
|
|
|
|
sc, vx, vy, scale: double;
|
|
|
|
|
q : Extended;
|
|
|
|
|
begin
|
|
|
|
|
{
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msRotate, msRotateMove:
|
|
|
|
|
Image.Cursor := crEditRotate;
|
|
|
|
|
msDrag, msDragMove:
|
|
|
|
|
Image.Cursor := crEditMove;
|
|
|
|
|
else
|
|
|
|
|
Image.Cursor := crEditArrow;
|
|
|
|
|
end;
|
|
|
|
|
}
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msZoomWindowMove,
|
|
|
|
|
msZoomOutWindowMove:
|
|
|
|
|
begin
|
|
|
|
|
if DrawSelection then DrawZoomWindow;
|
|
|
|
|
FClickRect.BottomRight := Point(x, y);
|
|
|
|
|
dx := x - FClickRect.TopLeft.X;
|
|
|
|
|
dy := y - FClickRect.TopLeft.Y;
|
|
|
|
|
|
|
|
|
|
if ssShift in Shift then begin
|
|
|
|
|
if (dy = 0) or (abs(dx/dy) >= Image.Width/Image.Height) then
|
|
|
|
|
dy := Round(dx / Image.Width * Image.Height)
|
|
|
|
|
else
|
|
|
|
|
dx := Round(dy / Image.Height * Image.Width);
|
|
|
|
|
FSelectRect.Left := FClickRect.TopLeft.X - dx;
|
|
|
|
|
FSelectRect.Top := FClickRect.TopLeft.Y - dy;
|
|
|
|
|
FSelectRect.Right := FClickRect.TopLeft.X + dx;
|
|
|
|
|
FSelectRect.Bottom := FClickRect.TopLeft.Y + dy;
|
|
|
|
|
end
|
|
|
|
|
else if ssCtrl in Shift then begin
|
|
|
|
|
FSelectRect.TopLeft := FClickRect.TopLeft;
|
|
|
|
|
sgn := IfThen(dy*dx >=0, 1, -1);
|
|
|
|
|
if (dy = 0) or (abs(dx/dy) >= Image.Width/Image.Height) then begin
|
|
|
|
|
FSelectRect.Right := x;
|
|
|
|
|
FSelectRect.Bottom := FClickRect.TopLeft.Y + sgn * Round(dx / Image.Width * Image.Height);
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
FSelectRect.Right := FClickRect.TopLeft.X + sgn * Round(dy / Image.Height * Image.Width);
|
|
|
|
|
FSelectRect.Bottom := y;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
sgn := IfThen(dy*dx >=0, 1, -1);
|
|
|
|
|
if (dy = 0) or (abs(dx/dy) >= Image.Width/Image.Height) then begin
|
|
|
|
|
cy := (y + FClickRect.TopLeft.Y) div 2;
|
|
|
|
|
FSelectRect.Left := FClickRect.TopLeft.X;
|
|
|
|
|
FSelectRect.Right := x;
|
|
|
|
|
FSelectRect.Top := cy - sgn * Round(dx / 2 / Image.Width * Image.Height);
|
|
|
|
|
FSelectRect.Bottom := cy + sgn * Round(dx / 2 / Image.Width * Image.Height);
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
cx := (x + FClickRect.TopLeft.X) div 2;
|
|
|
|
|
FSelectRect.Left := cx - sgn * Round(dy / 2 / Image.Height * Image.Width);
|
|
|
|
|
FSelectRect.Right := cx + sgn * Round(dy / 2 / Image.Height * Image.Width);
|
|
|
|
|
FSelectRect.Top := FClickRect.TopLeft.Y;
|
|
|
|
|
FSelectRect.Bottom := y;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
DrawSelection := true;
|
|
|
|
|
end;
|
|
|
|
|
msDragMove:
|
|
|
|
|
begin
|
|
|
|
|
assert(assigned(FviewImage));
|
|
|
|
|
assert(FViewScale <> 0);
|
|
|
|
|
|
|
|
|
|
scale := FViewScale * Image.Width / FViewImage.Width;
|
|
|
|
|
FViewPos.X := FViewPos.X + (x - FClickRect.Right) / scale;
|
|
|
|
|
FViewPos.Y := FViewPos.Y + (y - FClickRect.Bottom) / scale;
|
|
|
|
|
//FClickRect.BottomRight := Point(x, y);
|
|
|
|
|
|
|
|
|
|
DrawImageView;
|
|
|
|
|
end;
|
|
|
|
|
{ msPitchYaw:
|
|
|
|
|
begin
|
|
|
|
|
if camDragMode and ( (x <> camDragOld.x) or (y <> camDragOld.y) ) then
|
|
|
|
|
begin
|
|
|
|
|
Inc(camDragPos.x, x - camDragOld.x);
|
|
|
|
|
Inc(camDragPos.y, y - camDragOld.y);
|
|
|
|
|
|
|
|
|
|
vx := Round6(camDragValueX + camDragPos.x / 10);
|
|
|
|
|
vy := Round6(camDragValueY - camDragPos.y / 10);
|
|
|
|
|
|
|
|
|
|
MainCP.cameraPitch := vy * PI / 180.0;
|
|
|
|
|
MainCP.cameraYaw := vx * PI / 180.0;
|
|
|
|
|
|
|
|
|
|
vx := Round(vx);
|
|
|
|
|
vy := Round(vy);
|
|
|
|
|
|
|
|
|
|
camDragged := True;
|
|
|
|
|
//StatusBar.Panels.Items[1].Text := Format('Pitch: %f<>, Yaw: %f<>', [vx,vy]);
|
|
|
|
|
end;
|
|
|
|
|
end; }
|
|
|
|
|
msRotateMove:
|
|
|
|
|
begin
|
|
|
|
|
if DrawSelection then DrawRotatelines(FRotateAngle);
|
|
|
|
|
|
|
|
|
|
FRotateAngle := arctan2(y-Image.Height/2, Image.Width/2-x) - FClickAngle;
|
|
|
|
|
if ssShift in Shift then // angle snap
|
|
|
|
|
FRotateAngle := Round(FRotateAngle/snap_angle)*snap_angle;
|
|
|
|
|
//SelectRect.Left := x;
|
|
|
|
|
|
|
|
|
|
// pdjpointgen.Rotate(FRotateAngle);
|
|
|
|
|
// FRotateAngle := 0;
|
|
|
|
|
|
|
|
|
|
DrawRotatelines(FRotateAngle);
|
|
|
|
|
DrawSelection := true;
|
|
|
|
|
{
|
|
|
|
|
Image.Refresh;
|
|
|
|
|
if AdjustForm.Visible then begin
|
|
|
|
|
MainCp.FAngle:=-FRotateAngle;
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
end;
|
|
|
|
|
}
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
FClickRect.BottomRight := Point(x, y);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function ScaleRect(r: TRect; scale: double): TSRect;
|
|
|
|
|
begin
|
|
|
|
|
Result.Left := r.Left * scale;
|
|
|
|
|
Result.Top := r.Top * scale;
|
|
|
|
|
Result.Right := r.Right * scale;
|
|
|
|
|
Result.Bottom := r.Bottom * scale;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.ImageMouseUp(Sender: TObject; Button: TMouseButton;
|
|
|
|
|
Shift: TShiftState; X, Y: Integer);
|
|
|
|
|
var
|
|
|
|
|
scale: double;
|
|
|
|
|
rs: TSRect;
|
|
|
|
|
begin
|
|
|
|
|
case FMouseMoveState of
|
|
|
|
|
msZoomWindowMove:
|
|
|
|
|
begin
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
FMouseMoveState := msZoomWindow;
|
|
|
|
|
if (abs(FSelectRect.Left - FSelectRect.Right) < 10) or
|
|
|
|
|
(abs(FSelectRect.Top - FSelectRect.Bottom) < 10) then
|
|
|
|
|
Exit; // zoom to much or double clicked
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.ZoomtoRect(ScaleRect(FSelectRect, MainCP.Width / Image.Width));
|
|
|
|
|
|
|
|
|
|
FViewScale := FViewScale * Image.Width / abs(FSelectRect.Right - FSelectRect.Left);
|
|
|
|
|
FViewPos.x := FViewPos.x - ((FSelectRect.Right + FSelectRect.Left) - Image.Width)/2;
|
|
|
|
|
FViewPos.y := FViewPos.y - ((FSelectRect.Bottom + FSelectRect.Top) - Image.Height)/2;
|
|
|
|
|
DrawImageView;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
msZoomOutWindowMove:
|
|
|
|
|
begin
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
FMouseMoveState := msZoomOutWindow;
|
|
|
|
|
if (abs(FSelectRect.Left - FSelectRect.Right) < 10) or
|
|
|
|
|
(abs(FSelectRect.Top - FSelectRect.Bottom) < 10) then
|
|
|
|
|
Exit; // zoom to much or double clicked
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.ZoomOuttoRect(ScaleRect(FSelectRect, MainCP.Width / Image.Width));
|
|
|
|
|
|
|
|
|
|
scale := Image.Width / abs(FSelectRect.Right - FSelectRect.Left);
|
|
|
|
|
FViewScale := FViewScale / scale;
|
|
|
|
|
FViewPos.x := scale * (FViewPos.x + ((FSelectRect.Right + FSelectRect.Left) - Image.Width)/2);
|
|
|
|
|
FViewPos.y := scale * (FViewPos.y + ((FSelectRect.Bottom + FSelectRect.Top) - Image.Height)/2);
|
|
|
|
|
|
|
|
|
|
DrawImageView;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
msDragMove:
|
|
|
|
|
begin
|
|
|
|
|
FClickRect.BottomRight := Point(x, y);
|
|
|
|
|
FMouseMoveState := msDrag;
|
|
|
|
|
|
|
|
|
|
if ((x = 0) and (y = 0)) or // double clicked
|
|
|
|
|
((FClickRect.left = FClickRect.right) and (FClickRect.top = FClickRect.bottom))
|
|
|
|
|
then Exit;
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.MoveRect(ScaleRect(FClickRect, MainCP.Width / Image.Width));
|
|
|
|
|
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
msRotateMove:
|
|
|
|
|
begin
|
|
|
|
|
DrawRotatelines(FRotateAngle);
|
|
|
|
|
|
|
|
|
|
FMouseMoveState := msRotate;
|
|
|
|
|
|
|
|
|
|
if (FRotateAngle = 0) then Exit; // double clicked
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
if MainForm_RotationMode = 0 then MainCp.Rotate(FRotateAngle)
|
|
|
|
|
else MainCp.Rotate(-FRotateAngle);
|
|
|
|
|
|
|
|
|
|
if assigned(FViewImage) then begin
|
|
|
|
|
FViewImage.Free;
|
|
|
|
|
FViewImage := nil;
|
|
|
|
|
DrawImageView;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
{ msPitchYaw:
|
|
|
|
|
begin
|
|
|
|
|
camDragMode := false;
|
|
|
|
|
Screen.Cursor := crDefault;
|
|
|
|
|
|
|
|
|
|
if camDragged then
|
|
|
|
|
begin
|
|
|
|
|
camDragged := False;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end; }
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.DrawImageView;
|
|
|
|
|
var
|
|
|
|
|
i, j: integer;
|
|
|
|
|
bm: TBitmap;
|
|
|
|
|
r: TRect;
|
|
|
|
|
scale: double;
|
|
|
|
|
const
|
|
|
|
|
msg = #54; // 'NO PREVIEW';
|
|
|
|
|
var
|
|
|
|
|
ok: boolean;
|
|
|
|
|
GlobalMemoryInfo: TMemoryStatus; // holds the global memory status information
|
|
|
|
|
area: int64;
|
|
|
|
|
gridp: integer;
|
|
|
|
|
begin
|
|
|
|
|
bm := TBitmap.Create;
|
|
|
|
|
bm.Width := Image.Width;
|
|
|
|
|
bm.Height := Image.Height;
|
|
|
|
|
with bm.Canvas do begin
|
|
|
|
|
if ShowTransparency then begin
|
|
|
|
|
Brush.Color := $F0F0F0;
|
|
|
|
|
FillRect(Rect(0, 0, bm.Width, bm.Height));
|
|
|
|
|
Brush.Color := $C0C0C0;
|
|
|
|
|
for i := 0 to ((bm.Width - 1) shr 3) do begin
|
|
|
|
|
for j := 0 to ((bm.Height - 1) shr 3) do begin
|
|
|
|
|
if odd(i + j) then
|
|
|
|
|
FillRect(Rect(i shl 3, j shl 3, (i+1) shl 3, (j+1) shl 3));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
Brush.Color := MainCP.background[0] or (MainCP.background[1] shl 8) or (MainCP.background[2] shl 16);
|
|
|
|
|
FillRect(Rect(0, 0, bm.Width, bm.Height));
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
ok := false;
|
|
|
|
|
if assigned(FViewImage) then begin
|
|
|
|
|
scale := FViewScale * Image.Width / FViewImage.Width;
|
|
|
|
|
|
|
|
|
|
r.Left := Image.Width div 2 + round(scale * (FViewPos.X - FViewImage.Width/2));
|
|
|
|
|
r.Right := Image.Width div 2 + round(scale * (FViewPos.X + FViewImage.Width/2));
|
|
|
|
|
r.Top := Image.Height div 2 + round(scale * (FViewPos.Y - FViewImage.Height/2));
|
|
|
|
|
r.Bottom := Image.Height div 2 + round(scale * (FViewPos.Y + FViewImage.Height/2));
|
|
|
|
|
|
|
|
|
|
GlobalMemoryInfo.dwLength := SizeOf(GlobalMemoryInfo);
|
|
|
|
|
GlobalMemoryStatus(GlobalMemoryInfo);
|
|
|
|
|
area := abs(r.Right - r.Left) * int64(abs(r.Bottom - r.Top));
|
|
|
|
|
|
|
|
|
|
if (area * 4 < GlobalMemoryInfo.dwAvailPhys div 2) or
|
|
|
|
|
(area <= Screen.Width*Screen.Height*4) then
|
|
|
|
|
try
|
|
|
|
|
FViewImage.Draw(bm.Canvas, r);
|
|
|
|
|
ok := true;
|
|
|
|
|
except
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
// Gridlines for composition (taken from JK mod by Jed Kelsey)
|
|
|
|
|
if (EnableGuides) then begin
|
|
|
|
|
with bm.Canvas do begin
|
|
|
|
|
Pen.Width := 1;
|
|
|
|
|
Pen.Color := TColor(LineCenterColor); //$000000; // Center
|
|
|
|
|
MoveTo(0, bm.Height shr 1); LineTo(bm.Width, bm.Height shr 1);
|
|
|
|
|
MoveTo(bm.Width shr 1, 0); LineTo(bm.Width shr 1, bm.Height);
|
|
|
|
|
Pen.Color := TColor(LineThirdsColor); //$C000C0; // Thirds
|
|
|
|
|
gridp := Floor(bm.Height/3);
|
|
|
|
|
MoveTo(0, gridp); LineTo(bm.Width, gridp);
|
|
|
|
|
MoveTo(0, bm.Height-gridp); LineTo(bm.Width, bm.Height-gridp);
|
|
|
|
|
gridp := Floor(bm.Width/3);
|
|
|
|
|
MoveTo(gridp, 0); LineTo(gridp, bm.Height);
|
|
|
|
|
MoveTo(bm.Width-gridp, 0); LineTo(bm.Width-gridp, bm.Height);
|
|
|
|
|
Pen.Color := TColor(LineGRColor); //$0000F0; // "Golden Ratio" (per axis)
|
|
|
|
|
gridp := Floor(bm.Height * 0.61803399);
|
|
|
|
|
MoveTo(0, gridp); LineTo(bm.Width, gridp);
|
|
|
|
|
MoveTo(0, bm.Height-gridp); LineTo(bm.Width, bm.Height-gridp);
|
|
|
|
|
gridp := Floor(bm.Width * 0.61803399);
|
|
|
|
|
MoveTo(gridp, 0); LineTo(gridp, bm.Height);
|
|
|
|
|
MoveTo(bm.Width-gridp, 0); LineTo(bm.Width-gridp, bm.Height);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if not ok then
|
|
|
|
|
with bm.Canvas do
|
|
|
|
|
begin
|
|
|
|
|
Font.Name := 'Wingdings'; // 'Arial';
|
|
|
|
|
Font.Height := bm.Height div 4;
|
|
|
|
|
Font.Color := $808080;
|
|
|
|
|
Brush.Style := bsClear;
|
|
|
|
|
i := (bm.Width - TextWidth(msg)) div 2;
|
|
|
|
|
j := (bm.Height - TextHeight(msg)) div 2;
|
|
|
|
|
Font.Color := 0;
|
|
|
|
|
TextOut(i+2,j+2, msg);
|
|
|
|
|
Font.Color := clWhite; //$808080;
|
|
|
|
|
TextOut(i,j, msg);
|
|
|
|
|
end;
|
|
|
|
|
Image.Picture.Graphic := bm;
|
|
|
|
|
//EditForm.PaintBackground;
|
|
|
|
|
Image.Refresh;
|
|
|
|
|
bm.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
(*
|
|
|
|
|
procedure TMainForm.DrawPitchYawLines(YawAngle: double; PitchAngle: double);
|
|
|
|
|
var
|
|
|
|
|
bkuPen: TPen;
|
|
|
|
|
points: array[0..3] of TPoint;
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
bkuPen := TPen.Create;
|
|
|
|
|
bkuPen.Assign(Image.Canvas.Pen);
|
|
|
|
|
Image.Canvas.Pen.Mode := pmXor;
|
|
|
|
|
Image.Canvas.Pen.Color := clWhite;
|
|
|
|
|
Image.Canvas.Pen.Style := psDot; //psDash;
|
|
|
|
|
Image.Canvas.Brush.Style := bsClear;
|
|
|
|
|
|
|
|
|
|
// Image.Canvas.Rectangle(FSelectRect);
|
|
|
|
|
points[0].x := 0;
|
|
|
|
|
points[0].y := round((Image.Height / 2) * sin(PitchAngle));
|
|
|
|
|
points[1].x := Image.Width - 1;
|
|
|
|
|
points[1].y := points[0].y;
|
|
|
|
|
points[2].x := points[1].x;
|
|
|
|
|
points[2].y := round((Image.Height) - ((Image.Height / 2) * sin(PitchAngle)));
|
|
|
|
|
points[3].x := points[0].x;
|
|
|
|
|
points[3].y := points[2].y;
|
|
|
|
|
|
|
|
|
|
Image.Canvas.MoveTo(Points[3].x, Points[3].y);
|
|
|
|
|
for i := 0 to 3 do begin
|
|
|
|
|
Image.Canvas.LineTo(Points[i].x, Points[i].y);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Image.Canvas.Pen.Assign(bkuPen);
|
|
|
|
|
bkuPen.Free;
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.DrawRotateLines(Angle: double);
|
|
|
|
|
var
|
|
|
|
|
bkuPen: TPen;
|
|
|
|
|
points: array[0..3] of TPoint;
|
|
|
|
|
i,x,y: integer;
|
|
|
|
|
begin
|
|
|
|
|
bkuPen := TPen.Create;
|
|
|
|
|
bkuPen.Assign(Image.Canvas.Pen);
|
|
|
|
|
Image.Canvas.Pen.Mode := pmXor;
|
|
|
|
|
Image.Canvas.Pen.Color := clWhite;
|
|
|
|
|
Image.Canvas.Pen.Style := psDot; //psDash;
|
|
|
|
|
Image.Canvas.Brush.Style := bsClear;
|
|
|
|
|
|
|
|
|
|
// Image.Canvas.Rectangle(FSelectRect);
|
|
|
|
|
points[0].x := (Image.Width div 2)-1;
|
|
|
|
|
points[0].y := (Image.Height div 2)-1;
|
|
|
|
|
points[1].x := (Image.Width div 2)-1;
|
|
|
|
|
points[1].y := -Image.Height div 2;
|
|
|
|
|
points[2].x := -Image.Width div 2;
|
|
|
|
|
points[2].y := -Image.Height div 2;
|
|
|
|
|
points[3].x := -Image.Width div 2;
|
|
|
|
|
points[3].y := (Image.Height div 2)-1;
|
|
|
|
|
|
|
|
|
|
for i := 0 to 3 do begin
|
|
|
|
|
x := points[i].x;
|
|
|
|
|
y := points[i].y;
|
|
|
|
|
|
|
|
|
|
points[i].x := round(cos(Angle) * x + sin(Angle) * y) + Image.Width div 2;
|
|
|
|
|
points[i].y := round(-sin(Angle) * x + cos(Angle) * y) + Image.Height div 2;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Image.Canvas.MoveTo(Points[3].x, Points[3].y);
|
|
|
|
|
for i := 0 to 3 do begin
|
|
|
|
|
Image.Canvas.LineTo(Points[i].x, Points[i].y);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Image.Canvas.Pen.Assign(bkuPen);
|
|
|
|
|
bkuPen.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.DrawZoomWindow;
|
|
|
|
|
const
|
|
|
|
|
cornerSize = 32;
|
|
|
|
|
var
|
|
|
|
|
bkuPen: TPen;
|
|
|
|
|
dx, dy, cx, cy: integer;
|
|
|
|
|
l, r, t, b: integer;
|
|
|
|
|
begin
|
|
|
|
|
bkuPen := TPen.Create;
|
|
|
|
|
bkuPen.Assign(Image.Canvas.Pen);
|
|
|
|
|
with Image.Canvas do begin
|
|
|
|
|
Pen.Mode := pmXor;
|
|
|
|
|
Pen.Color := clWhite;
|
|
|
|
|
Brush.Style := bsClear;
|
|
|
|
|
|
|
|
|
|
Pen.Style := psDot; //psDash;
|
|
|
|
|
|
|
|
|
|
if ssShift in FShiftState then
|
|
|
|
|
begin
|
|
|
|
|
dx := FClickRect.Right - FClickRect.Left;
|
|
|
|
|
dy := FClickRect.Bottom - FClickRect.Top;
|
|
|
|
|
Rectangle(FClickRect.Left - dx, FClickRect.Top - dy, FClickRect.Right, FClickRect.Bottom);
|
|
|
|
|
end
|
|
|
|
|
else Rectangle(FClickRect);
|
|
|
|
|
|
|
|
|
|
dx := FSelectRect.Right - FSelectRect.Left;
|
|
|
|
|
if dx >= 0 then begin
|
|
|
|
|
l := FSelectRect.Left - 1;
|
|
|
|
|
r := FSelectRect.Right;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
dx := -dx;
|
|
|
|
|
l := FSelectRect.Right - 1;
|
|
|
|
|
r := FSelectRect.Left;
|
|
|
|
|
end;
|
|
|
|
|
dx := min(dx div 2 - 1, cornerSize);
|
|
|
|
|
|
|
|
|
|
dy := FSelectRect.Bottom - FSelectRect.Top;
|
|
|
|
|
if dy >= 0 then begin
|
|
|
|
|
t := FSelectRect.Top - 1;
|
|
|
|
|
b := FSelectRect.Bottom;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
dy := -dy;
|
|
|
|
|
t := FSelectRect.Bottom - 1;
|
|
|
|
|
b := FSelectRect.Top;
|
|
|
|
|
end;
|
|
|
|
|
dy := min(dy div 2, cornerSize);
|
|
|
|
|
|
|
|
|
|
pen.Style := psSolid;
|
|
|
|
|
|
|
|
|
|
MoveTo(l + dx, t);
|
|
|
|
|
LineTo(l, t);
|
|
|
|
|
LineTo(l, t + dy);
|
|
|
|
|
MoveTo(r - dx, t);
|
|
|
|
|
LineTo(r, t);
|
|
|
|
|
LineTo(r, t + dy);
|
|
|
|
|
MoveTo(r - dx, b);
|
|
|
|
|
LineTo(r, b);
|
|
|
|
|
LineTo(r, b - dy);
|
|
|
|
|
MoveTo(l + dx, b);
|
|
|
|
|
LineTo(l, b);
|
|
|
|
|
LineTo(l, b - dy);
|
|
|
|
|
{
|
|
|
|
|
cx := (l + r) div 2;
|
|
|
|
|
cy := (t + b) div 2;
|
|
|
|
|
MoveTo(cx - dx div 2, cy);
|
|
|
|
|
LineTo(cx + dx div 2 + 1, cy);
|
|
|
|
|
MoveTo(cx, cy - dy div 2);
|
|
|
|
|
LineTo(cx, cy + dy div 2 + 1);
|
|
|
|
|
}
|
|
|
|
|
Pen.Assign(bkuPen);
|
|
|
|
|
end;
|
|
|
|
|
bkuPen.Free;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
//***************************************************************************//
|
2022-03-08 12:25:51 -05:00
|
|
|
|
procedure TMainForm.FillVariantMenu;
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i, j: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
s: string;
|
|
|
|
|
NewMenuItem : TMenuItem;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
svars: TStringList;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
SetLength(VarMenus, NrVar);
|
|
|
|
|
// AV: to prevent underlined letters with GUI themes
|
|
|
|
|
mnuBuiltinVars.AutoHotkeys := maManual;
|
|
|
|
|
mnuPluginVars.AutoHotkeys := maManual;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
svars := TStringList.Create;
|
|
|
|
|
svars.Sorted := True;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
for i := 0 to NRVAR - 1 do begin
|
|
|
|
|
NewMenuItem := TMenuItem.Create(self);
|
|
|
|
|
s := varnames(i);
|
|
|
|
|
NewMenuItem.Caption := uppercase(s[1]) + copy(s, 2, length(s)-1);
|
|
|
|
|
NewMenuItem.OnClick := VariantMenuClick;
|
|
|
|
|
NewMenuItem.Enabled := True;
|
|
|
|
|
NewMenuItem.Name := 'var' + intTostr(i);
|
|
|
|
|
NewMenuItem.Tag := i;
|
|
|
|
|
NewMenuItem.GroupIndex := 2;
|
|
|
|
|
NewMenuItem.RadioItem := True;
|
|
|
|
|
VarMenus[i] := NewMenuItem;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
mnuPluginVars.Add(NewMenuItem);
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.VariantMenuClick(Sender: TObject);
|
|
|
|
|
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...
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if Variation > vRandom then
|
|
|
|
|
VarMenus[Variation].Checked := False
|
|
|
|
|
else
|
|
|
|
|
mnuVRandom.Checked := False;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (TMenuItem(Sender).Tag >= NumBuiltinVars) then
|
|
|
|
|
begin
|
|
|
|
|
mnuBuiltinVars.Checked := False;
|
|
|
|
|
mnuPluginVars.Checked := True;
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
mnuBuiltinVars.Checked := True;
|
|
|
|
|
mnuPluginVars.Checked := False;
|
|
|
|
|
end;
|
|
|
|
|
UpdateUndo;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: changed Variation to integer - no more ugly type-casting here!
|
|
|
|
|
Variation := TMenuItem(Sender).Tag;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
SetVariation(maincp);
|
|
|
|
|
ResetLocation;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{ /////////////////////////////////////////////////////////////////////////// }
|
|
|
|
|
|
|
|
|
|
// 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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: Apo UI Appearance /////////////////////////////
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.CreateStyleList;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: smallint;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
s: string;
|
|
|
|
|
apostyle : TMenuItem;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
for i := 0 to Length(TStyleManager.StyleNames)-1 do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
apostyle := TMenuItem.Create(mnuApoStyle);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
s := TStyleManager.StyleNames[i];
|
2022-03-08 12:25:51 -05:00
|
|
|
|
apostyle.Caption := s;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (TStyleManager.ActiveStyle.Name = s) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
apostyle.Checked := True;
|
|
|
|
|
apostyle.Name := 'style' + IntToStr(i);
|
|
|
|
|
apostyle.RadioItem := True;
|
|
|
|
|
apostyle.Enabled := True;
|
|
|
|
|
apostyle.Tag := i;
|
|
|
|
|
apostyle.OnClick := StyleItemClick;
|
|
|
|
|
mnuApoStyle.Add(apostyle);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.ShowStyledWindows(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
self.ApplyThemedColors;
|
|
|
|
|
ScriptEditor.AdjustScripterColors;
|
|
|
|
|
EditForm.RedrawButtons;
|
|
|
|
|
AboutForm.SetTitleColor;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.StyleItemClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
newGUI: string;
|
|
|
|
|
Registry: TRegistry;
|
|
|
|
|
begin
|
|
|
|
|
if not TMenuItem(Sender).Checked then
|
|
|
|
|
begin
|
|
|
|
|
TMenuItem(Sender).Checked := True;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
newGUI := TMenuItem(Sender).Caption;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
StopThread; // ?
|
2022-03-08 12:25:51 -05:00
|
|
|
|
self.OnShow := ShowStyledWindows;
|
|
|
|
|
|
|
|
|
|
if EditForm.Visible then EditForm.Close;
|
|
|
|
|
if AdjustForm.Visible then AdjustForm.Close;
|
|
|
|
|
if MutateForm.Visible then MutateForm.Close;
|
|
|
|
|
if ScriptEditor.Visible then ScriptEditor.Close;
|
|
|
|
|
|
|
|
|
|
TStyleManager.TrySetStyle(newGUI, false);
|
|
|
|
|
|
|
|
|
|
except on EAccessViolation do // hmmm...
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MessageBox(0, PChar(TextByKey('options-restartnotice')),
|
|
|
|
|
ApophysisSVN, MB_ICONWARNING);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Registry := TRegistry.Create;
|
|
|
|
|
try
|
|
|
|
|
Registry.RootKey := HKEY_CURRENT_USER;
|
|
|
|
|
if Registry.OpenKey('\Software\' + APP_NAME + '\Defaults', True) then
|
|
|
|
|
Registry.WriteString('UIStyle', newGUI);
|
|
|
|
|
Registry.CloseKey;
|
|
|
|
|
finally
|
|
|
|
|
Registry.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
//--Z--////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.tbQualityBoxKeyPress(Sender: TObject; var Key: Char);
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (Key = ',') then Key := '.'; // AV
|
|
|
|
|
if not CharinSet(Key,['0'..'9', #8, #13, #27, '.']) then Key := #0; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if key = #13 then
|
|
|
|
|
begin
|
|
|
|
|
tbQualityBoxSet(Sender);
|
|
|
|
|
key := #0;
|
|
|
|
|
end
|
|
|
|
|
else if key = #27 then // AV: Esc
|
|
|
|
|
tbQualityBox.Text := FloatToStr(defSampleDensity);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.tbQualityBoxSet(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
q: double;
|
|
|
|
|
begin
|
|
|
|
|
try
|
|
|
|
|
q := StrToFloat(tbQualityBox.Text);
|
|
|
|
|
except
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
|
|
|
|
defSampleDensity := q;
|
|
|
|
|
|
|
|
|
|
StopThread;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
procedure TMainForm.ImageDblClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if FMouseMoveState = msRotateMove then
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.FAngle := 0;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end
|
|
|
|
|
else mnuResetLocationClick(Sender);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
procedure TMainForm.tbShowAlphaClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
//tbShowAlpha.Down := not tbShowAlpha.Down;
|
|
|
|
|
ShowTransparency := tbShowAlpha.Down;
|
|
|
|
|
|
|
|
|
|
DrawImageView;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
procedure TMainForm.tbShowTraceClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
TraceForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
procedure TMainForm.FormKeyUpDown(Sender: TObject; var Key: Word;
|
|
|
|
|
Shift: TShiftState);
|
|
|
|
|
var
|
|
|
|
|
MousePos: TPoint;
|
|
|
|
|
begin
|
|
|
|
|
if Shift <> FShiftState then begin
|
|
|
|
|
if FMouseMoveState in [msZoomWindowMove, msZoomOutWindowMove, msRotateMove, msDragMove] then
|
|
|
|
|
begin
|
|
|
|
|
// hack: to generate MouseMove event
|
|
|
|
|
GetCursorPos(MousePos);
|
|
|
|
|
SetCursorPos(MousePos.x, MousePos.y);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (FMouseMoveState in [msZoomWindowMove, msZoomOutWindowMove]) then
|
|
|
|
|
begin
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
FShiftState := Shift;
|
|
|
|
|
DrawZoomWindow;
|
|
|
|
|
end
|
|
|
|
|
else FShiftState := Shift;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.btnViewIconsClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ListView1.ViewStyle := vsIcon;
|
|
|
|
|
btnViewList.Down := false;
|
|
|
|
|
btnViewIcons.Down := true;
|
|
|
|
|
ClassicListMode := false;
|
|
|
|
|
|
|
|
|
|
// AV: refresh flame images ONLY if they didn't exist
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if not GeneratingThumbs then RunThumbnailThread;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// AV: scroll down to the selected flame preview
|
|
|
|
|
if MainForm.ListView1.SelCount > 0 then
|
|
|
|
|
MainForm.ListView1.Selected.MakeVisible(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.btnViewListClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ListView1.ViewStyle := vsReport;
|
|
|
|
|
btnViewList.Down := true;
|
|
|
|
|
btnViewIcons.Down := false;
|
|
|
|
|
ClassicListMode := true;
|
|
|
|
|
ListView1.Column[1].Caption := IfThen(EnumerateFlames.Checked,' N ', '');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.XmlScannerEndTag(Sender: TObject; TagName: String);
|
|
|
|
|
var sb : string;
|
|
|
|
|
begin
|
|
|
|
|
if (TagName = 'flame') then begin
|
|
|
|
|
EndParsing(ParseCP, sb);
|
|
|
|
|
MainForm.StatusBar.Panels[0].Text := sb;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.tbCurvesClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
AdjustForm.UpdateDisplay;
|
|
|
|
|
AdjustForm.PageControl.TabIndex:=4;
|
|
|
|
|
AdjustForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.tbMessagesClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
if (LoadForm.Showing = false) then LoadForm.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.btNewClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var saved: boolean;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
StopThread; // AV
|
|
|
|
|
if AlwaysCreateBlankFlame then
|
2022-06-23 06:22:32 -04:00
|
|
|
|
EditForm.mnuResetAllClick(Sender) // AV
|
|
|
|
|
else
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure TMainForm.ToolBarResize(Sender: TObject);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (Toolbar.Width <= TbBreakWidth) then
|
|
|
|
|
Toolbar.Height := 60 // 26 * 2 + 8
|
2022-03-08 12:25:51 -05:00
|
|
|
|
else Toolbar.Height := 26;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// AV: exactly the same code exists in the Global module
|
|
|
|
|
function Split(const fText: String; const fSep: Char; fTrim: Boolean=false; fQuotes: Boolean=false):TStringList;
|
|
|
|
|
var vI: Integer;
|
|
|
|
|
vBuffer: String;
|
|
|
|
|
vOn: Boolean;
|
|
|
|
|
begin
|
|
|
|
|
Result := TStringList.Create;
|
|
|
|
|
vBuffer:='';
|
|
|
|
|
vOn:=true;
|
|
|
|
|
for vI:=1 to Length(fText) do
|
|
|
|
|
begin
|
|
|
|
|
if (fQuotes and(fText[vI]=fSep)and vOn)or(Not(fQuotes) and (fText[vI]=fSep)) then
|
|
|
|
|
begin
|
|
|
|
|
if fTrim then vBuffer:=Trim(vBuffer);
|
|
|
|
|
if vBuffer='' then vBuffer:=fSep; // !!! e.g. split(',**',',')...
|
|
|
|
|
if vBuffer[1]=fSep then
|
|
|
|
|
vBuffer:=Copy(vBuffer,2,Length(vBuffer));
|
|
|
|
|
Result.Add(vBuffer);
|
|
|
|
|
vBuffer:='';
|
|
|
|
|
end;
|
|
|
|
|
if fQuotes then
|
|
|
|
|
begin
|
|
|
|
|
if fText[vI]='"' then
|
|
|
|
|
begin
|
|
|
|
|
vOn:=Not(vOn);
|
|
|
|
|
Continue;
|
|
|
|
|
end;
|
|
|
|
|
if (fText[vI]<>fSep)or((fText[vI]=fSep)and(vOn=false)) then
|
|
|
|
|
vBuffer:=vBuffer+fText[vI];
|
|
|
|
|
end else
|
|
|
|
|
if fText[vI]<>fSep then
|
|
|
|
|
vBuffer:=vBuffer+fText[vI];
|
|
|
|
|
end;
|
|
|
|
|
if vBuffer<>'' then
|
|
|
|
|
begin
|
|
|
|
|
if fTrim then vBuffer:=Trim(vBuffer);
|
|
|
|
|
Result.Add(vBuffer);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuResetUIClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
ListBackPanel.Width := ThumbnailSize + 90;
|
|
|
|
|
Splitter.Left := ListBackPanel.Width;
|
|
|
|
|
ListView1.Columns[0].Width := ThumbnailSize + 30; // AV
|
|
|
|
|
ListView1.Columns[1].Width := 35; // AV
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.AutoSaveTimerTimer(Sender: TObject);
|
|
|
|
|
var
|
2022-06-23 06:22:32 -04:00
|
|
|
|
filename, title, bakname : string;
|
|
|
|
|
FileListPre: TStringList;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
filename := AutoSavePath;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
title := CleanXMLName(maincp.name) + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
if FileExists(filename) then begin
|
|
|
|
|
FileListPre := TStringList.create;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
bakname := ChangeFileExt(filename, '.tmp');
|
|
|
|
|
if FileExists(bakname) then DeleteFile(bakname);
|
|
|
|
|
RenameFile(filename, bakname);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
finally
|
|
|
|
|
FileListPre.Free;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.Restorelastautosave1Click(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var fn: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if (not FileExists(AutoSavePath)) then
|
2022-03-08 12:25:51 -05:00
|
|
|
|
raise Exception.Create(TextByKey('main-status-noautosave')); // AV
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// StopScripter;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
fn := AutoSavePath;
|
|
|
|
|
LastOpenFile := fn;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Maincp.name := ''; // AV: ?
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ParamFolder := ExtractFilePath(fn);
|
|
|
|
|
OpenFile := fn;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
if APP_BUILD = '' then
|
|
|
|
|
MainForm.Caption := AppVersionString + ' - ' + openFile
|
|
|
|
|
else
|
|
|
|
|
MainForm.Caption := AppVersionString + ' ' + APP_BUILD + ' - ' + openFile;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
OpenFileType := ftXML;
|
|
|
|
|
ListXML(fn, 1)
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuHelpTopicsClick(Sender: TObject);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// var URL, HelpTopic: string;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{
|
|
|
|
|
if EditForm.Active then HelpTopic := 'Transform editor.htm'
|
2022-03-08 12:25:51 -05:00
|
|
|
|
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);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
URL := AppPath + Application.HelpFile;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if HelpTopic <> '' then URL := URL + '::\' + HelpTopic;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
{
|
2022-03-08 12:25:51 -05:00
|
|
|
|
function TMainForm.RetrieveXML(cp : TControlPoint):string;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: commented out since we can call it directly
|
|
|
|
|
Result := FlameToXML(cp, false);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
}
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
procedure TMainForm.tbGuidesClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
// tbGuides.Down := not tbGuides.Down;
|
|
|
|
|
EnableGuides := tbGuides.Down;
|
|
|
|
|
DrawImageView;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
function WinExecAndWait32(FileName: string): integer;
|
|
|
|
|
var
|
|
|
|
|
zAppName: array[0..1024] of Char;
|
|
|
|
|
zCurDir: array[0..255] of Char;
|
|
|
|
|
WorkDir: string;
|
|
|
|
|
StartupInfo: TStartupInfo;
|
|
|
|
|
ProcessInfo: TProcessInformation;
|
|
|
|
|
r : dword;
|
|
|
|
|
begin
|
|
|
|
|
StrPCopy(zAppName, FileName);
|
|
|
|
|
GetDir(0, WorkDir);
|
|
|
|
|
StrPCopy(zCurDir, WorkDir);
|
|
|
|
|
FillChar(StartupInfo, Sizeof(StartupInfo), #0);
|
|
|
|
|
StartupInfo.cb := Sizeof(StartupInfo);
|
|
|
|
|
|
|
|
|
|
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
|
|
|
|
|
StartupInfo.wShowWindow := 0;
|
|
|
|
|
if (not CreateProcess(nil, zAppName, nil, nil, false, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo)) then
|
|
|
|
|
Result := -1
|
|
|
|
|
else begin
|
|
|
|
|
WaitforSingleObject(ProcessInfo.hProcess, INFINITE);
|
|
|
|
|
GetExitCodeProcess(ProcessInfo.hProcess, r);
|
|
|
|
|
result := r;
|
|
|
|
|
CloseHandle(ProcessInfo.hProcess);
|
|
|
|
|
CloseHandle(ProcessInfo.hThread);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuTurnFlameToScriptClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
txt: string;
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
txt := Trim(FlameToXML(Maincp));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
ScriptEditor.ScriptFromFlame(txt);
|
|
|
|
|
ScriptEditor.Show;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
procedure TMainForm.RunThumbnailThread;
|
|
|
|
|
var
|
|
|
|
|
thumbs: TThumbnailThread;
|
|
|
|
|
begin
|
|
|
|
|
thumbs := TThumbnailThread.Create;
|
|
|
|
|
thumbs.Start; // AV: Resume method is deprecated here
|
|
|
|
|
GeneratingThumbs := True;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
constructor TThumbnailThread.Create;
|
|
|
|
|
begin
|
|
|
|
|
inherited create(True); // AV: don't run the thread immediately
|
|
|
|
|
FreeOnTerminate := true; // AV: fixed - someone forgot to free the memory
|
|
|
|
|
Trace2('Creating ThumbnailThread #' + IntToStr(self.ThreadID));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FlameItems := MainForm.ListView1.Items; // AV: keep the reference to flame list
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
destructor TThumbnailThread.Destroy;
|
|
|
|
|
begin
|
|
|
|
|
// AV: added tracing to fix Apo7X memory leaks
|
|
|
|
|
Synchronize(
|
|
|
|
|
procedure
|
|
|
|
|
begin
|
|
|
|
|
Trace2('Destroying ThumbnailThread #' + IntToStr(self.ThreadID));
|
|
|
|
|
end);
|
|
|
|
|
inherited;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TThumbnailThread.Execute;
|
|
|
|
|
var
|
|
|
|
|
Renderer : TRenderer;
|
|
|
|
|
cp : TControlPoint;
|
|
|
|
|
Thumbnail : TBitmap;
|
|
|
|
|
flameXML, fCaption : string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
w, h: integer;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
r : double;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Fitem: TListItem;
|
|
|
|
|
FlameProc: TProc;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
inherited;
|
|
|
|
|
Renderer := TRenderer.Create;
|
|
|
|
|
cp := TControlPoint.Create;
|
|
|
|
|
Thumbnail := TBitmap.Create;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
try // AV: added try-finally block
|
|
|
|
|
// AV: moved outside the loop for speed
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Thumbnail.SetSize(FThumbnailSize, FThumbnailSize);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Thumbnail.PixelFormat := pf24bit;
|
|
|
|
|
Thumbnail.HandleType := bmDIB;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
Thumbnail.Canvas.Lock; // AV: added thread-safe handling
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Thumbnail.Canvas.Brush.Color := WinColor; // AV: theme-aware GetSysColor(5);
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
|
|
|
|
cp.Clear;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
fCaption := Fitem.Caption;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
FlameProc; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
cp.spatial_oversample := defOversample;
|
|
|
|
|
cp.spatial_filter_radius := defFilterRadius;
|
|
|
|
|
cp.sample_density := FPreviewDensity; // AV
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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
|
|
|
|
|
MainForm.UsedThumbnails.Add(Thumbnail, nil);
|
|
|
|
|
Fitem.ImageIndex := MainForm.UsedThumbnails.Count - 1;
|
|
|
|
|
Trace2('Generating thumbnail for "' + fCaption + '"');
|
|
|
|
|
end);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if Terminated then break; // AV
|
|
|
|
|
end;
|
|
|
|
|
finally
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Thumbnail.Canvas.UnLock; // AV: added thread-safe handling
|
|
|
|
|
Thumbnail.Free;
|
|
|
|
|
Thumbnail := nil;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
cp.Free;
|
|
|
|
|
Renderer.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure ListXML(FileName: string; sel: integer; selname: string = '');
|
|
|
|
|
var
|
|
|
|
|
FStrings : TStringList;
|
|
|
|
|
i, p : integer;
|
|
|
|
|
title : string;
|
|
|
|
|
item : TListItem;
|
|
|
|
|
begin
|
|
|
|
|
MainForm.ParseLoadingBatch := true;
|
|
|
|
|
FStrings := TStringList.Create;
|
|
|
|
|
FStrings.LoadFromFile(FileName);
|
|
|
|
|
|
|
|
|
|
MainForm.ListView1.Items.BeginUpdate;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
// AV: moved all the main code inside try-finally block
|
|
|
|
|
// because Apo often crashes here
|
|
|
|
|
MainForm.ListView1.Items.Clear;
|
|
|
|
|
|
|
|
|
|
// AV: moved from TThumbnailThread.Execute - seems like it saves a lot of time
|
|
|
|
|
MainForm.UsedThumbnails.Clear;
|
|
|
|
|
MainForm.UsedThumbnails.Add(ThumbnailPlaceholder, nil);
|
|
|
|
|
|
|
|
|
|
if (Pos('<flame ', Lowercase(FStrings.Text)) <> 0) then
|
|
|
|
|
begin
|
|
|
|
|
for i := 0 to FStrings.Count - 1 do
|
|
|
|
|
begin
|
|
|
|
|
p := Pos('<flame ', LowerCase(FStrings[i]));
|
|
|
|
|
if (p <> 0) then
|
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
MainForm.ListXMLScanner.LoadFromBuffer(PAnsiChar(Utf8String(FStrings[i])));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
MainForm.ListXMLScanner.Execute;
|
|
|
|
|
|
|
|
|
|
if Trim(pname) = '' then
|
|
|
|
|
Title := '*untitled ' + ptime
|
|
|
|
|
else
|
|
|
|
|
Title := Trim(pname);
|
|
|
|
|
if Title <> '' then
|
|
|
|
|
begin
|
|
|
|
|
if ((i mod 5) = 0) then
|
|
|
|
|
MainForm.LoadSaveProgress.Position :=
|
|
|
|
|
round(100 * i / FStrings.Count);
|
|
|
|
|
item := MainForm.ListView1.Items.Add;
|
|
|
|
|
item.Caption := Title;
|
|
|
|
|
item.ImageIndex := 0; // AV: now we can load a hourglass icon
|
2022-06-23 06:22:32 -04:00
|
|
|
|
// AV: hack - remember the creation order in an unused field
|
|
|
|
|
item.OverlayIndex := MainForm.ListView1.Items.Count;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
MainForm.LoadSaveProgress.Position := 0;
|
|
|
|
|
//MainForm.ListView1.AllocBy := MainForm.ListView1.Items.Count;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if ClassicListMode then // AV: thumbs are useless
|
2022-03-08 12:25:51 -05:00
|
|
|
|
GeneratingThumbs := False
|
2022-06-23 06:22:32 -04:00
|
|
|
|
else
|
|
|
|
|
MainForm.RunThumbnailThread; // AV: wrap it into a separate method
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
finally
|
|
|
|
|
MainForm.ListView1.Items.EndUpdate;
|
|
|
|
|
FStrings.Free;
|
|
|
|
|
|
|
|
|
|
with MainForm.ListView1 do // AV
|
|
|
|
|
if Items.Count > 0 then // AV: added a check
|
|
|
|
|
case sel of
|
|
|
|
|
0: Selected := Items[Items.Count - 1];
|
|
|
|
|
1: Selected := Items[0];
|
|
|
|
|
2: if (selname <> '') then // AV: show the flame with the specified name
|
|
|
|
|
Selected := FindCaption(0, selname, false, true, false);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if MainForm.EnumerateFlames.Checked then // AV: displaying indices
|
|
|
|
|
MainForm.EnumerateFlamesClick(MainForm.EnumerateFlames);
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
MainForm.ParseLoadingBatch := false;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
|
|
|
|
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;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.RefreshThumbnail;
|
|
|
|
|
var
|
|
|
|
|
Renderer : TRenderer;
|
|
|
|
|
Thumbnail : TBitmap;
|
|
|
|
|
r, sd: double;
|
|
|
|
|
i, w, h, w_old, h_old: integer;
|
|
|
|
|
begin
|
|
|
|
|
if not Assigned(ListView1.Selected) then exit;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
i := ListView1.Selected.ImageIndex;
|
|
|
|
|
if (i >= UsedThumbnails.Count) then exit;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
w_old := Maincp.Width;
|
|
|
|
|
h_old := Maincp.Height;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
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);
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
sd := Maincp.sample_density;
|
|
|
|
|
Maincp.AdjustScale(w, h);
|
|
|
|
|
Maincp.spatial_oversample := defOversample;
|
|
|
|
|
Maincp.spatial_filter_radius := defFilterRadius;
|
|
|
|
|
Maincp.sample_density := TThumbnailThread.FPreviewDensity;
|
|
|
|
|
|
|
|
|
|
Renderer := TRenderer.Create;
|
|
|
|
|
Thumbnail := TBitmap.Create;
|
|
|
|
|
try
|
|
|
|
|
Renderer.SetCP(Maincp);
|
|
|
|
|
Renderer.Render;
|
|
|
|
|
|
|
|
|
|
Thumbnail.PixelFormat := pf24bit;
|
|
|
|
|
Thumbnail.HandleType := bmDIB;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Thumbnail.SetSize(ThumbnailSize, ThumbnailSize);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Thumbnail.Canvas.Brush.Color := WinColor; // theme-aware system color
|
|
|
|
|
Thumbnail.Canvas.FillRect(Rect(0, 0, ThumbnailSize, ThumbnailSize));
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Thumbnail.Canvas.Draw((ThumbnailSize - w) shr 1,
|
|
|
|
|
(ThumbnailSize - h) shr 1, Renderer.GetImage);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
try
|
2022-06-23 06:22:32 -04:00
|
|
|
|
UsedThumbnails.Replace(i, Thumbnail, nil);
|
|
|
|
|
i := ListView1.Selected.Index;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
ListView1.Items.Item[i].Update;
|
|
|
|
|
Trace2('Updating thumbnail for "' + ListView1.Items[i].Caption + '"');
|
|
|
|
|
except
|
|
|
|
|
ListView1.Items[i].ImageIndex := 0;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
Thumbnail.Free;
|
|
|
|
|
Thumbnail := nil;
|
|
|
|
|
Renderer.Free;
|
|
|
|
|
// restore old settings
|
|
|
|
|
Maincp.AdjustScale(w_old, h_old);
|
|
|
|
|
Maincp.sample_density := sd;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.UpdateThumbnails; // AV: refreshes images only
|
|
|
|
|
var
|
|
|
|
|
i: integer;
|
|
|
|
|
begin
|
|
|
|
|
UsedThumbnails.Clear;
|
|
|
|
|
UsedThumbnails.Add(ThumbnailPlaceholder, nil);
|
|
|
|
|
|
|
|
|
|
with ListView1.Items do
|
|
|
|
|
begin
|
|
|
|
|
BeginUpdate;
|
|
|
|
|
for i := 0 to Count - 1 do Item[i].ImageIndex := 0; // hourglass icon
|
|
|
|
|
EndUpdate;
|
|
|
|
|
end;
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
RunThumbnailThread;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
|
|
|
|
|
// hightlight the item if possible
|
|
|
|
|
ListView1.Selected := ListView1.ItemFocused;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.SetThumbnailProperties; // AV
|
|
|
|
|
begin
|
|
|
|
|
if UseSmallThumbnails then
|
|
|
|
|
ThumbnailSize := 96
|
|
|
|
|
else
|
|
|
|
|
ThumbnailSize := 128;
|
|
|
|
|
UsedThumbnails.Height := ThumbnailSize;
|
|
|
|
|
UsedThumbnails.Width := ThumbnailSize;
|
|
|
|
|
|
|
|
|
|
TThumbnailThread.FThumbnailSize := ThumbnailSize;
|
|
|
|
|
LoadThumbnailPlaceholder(ThumbnailSize);
|
|
|
|
|
|
|
|
|
|
mnuResetUI.Click;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuReportFlameClick(Sender: TObject);
|
|
|
|
|
var
|
|
|
|
|
str: string;
|
|
|
|
|
i : integer;
|
|
|
|
|
begin
|
|
|
|
|
if (not LoadForm.Visible) then LoadForm.Show;
|
|
|
|
|
str := MainCP.name + #13#10 + StringOfChar('=', length(MainCP.name)) + #13#10 +
|
|
|
|
|
Format(TextByKey('main-report-transformcount'), [MainCp.NumXForms]) + #13#10 +
|
|
|
|
|
Format(TextByKey('main-report-finaltransform'), [IfThen(maincp.finalXformEnabled, TextByKey('common-yes'), TextByKey('common-no'))]) + #13#10 +
|
|
|
|
|
TextByKey('main-report-usedplugins');
|
|
|
|
|
MainCP.FillUsedPlugins;
|
|
|
|
|
if MainCp.used_plugins.Count = 0 then begin
|
|
|
|
|
LoadForm.Output.Text := LoadForm.Output.Text + #13#10 + str + ' ' + TextByKey('main-report-noplugins') + #13#10;
|
|
|
|
|
exit;
|
|
|
|
|
end;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
for i := 0 to MainCP.used_plugins.Count-1 do
|
2022-03-08 12:25:51 -05:00
|
|
|
|
str := str + #13#10 + ' - ' + MainCP.used_plugins[i];
|
2022-06-23 06:22:32 -04:00
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
// 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),
|
|
|
|
|
TextByKey('common-yes'), TextByKey('common-no'));
|
|
|
|
|
str := str + #13#10 + TextByKey('main-report-flame3d') + #32 +
|
|
|
|
|
IfThen((MainCP.cameraPitch <> 0) or (MainCP.cameraRoll <> 0) or (pos('_rotate_', str) > 0),
|
|
|
|
|
TextByKey('common-yes'), TextByKey('common-no'));
|
|
|
|
|
|
2022-06-23 06:22:32 -04:00
|
|
|
|
if MainCp.Comment <> '' then
|
|
|
|
|
str := str + #13#10 + TextByKey('common-comment') + ': '#13#10'"' +
|
|
|
|
|
MainCp.Comment + '"';
|
|
|
|
|
|
2022-03-08 12:25:51 -05:00
|
|
|
|
LoadForm.Output.Text := LoadForm.Output.Text + #13#10 + str + #13#10;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuExportChaoticaClick(Sender: TObject);
|
|
|
|
|
begin
|
|
|
|
|
MainCP.FillUsedPlugins;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
C_ExecuteChaotica(FlameToXml(MainCp), MainCp.used_plugins, UseX64IfPossible);
|
2022-03-08 12:25:51 -05:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.mnuManualClick(Sender: TObject); // AV: Apo7X link is dead...
|
|
|
|
|
begin
|
|
|
|
|
// AV: first link is for Russian people only
|
|
|
|
|
// WinShellOpen('https://books.google.ru/books?id=PbMAAQAAQBAJ&printsec=frontcover&hl=ru#v=onepage&q&f=false');
|
|
|
|
|
WinShellOpen('https://www.amazon.com/Fractals-Everywhere-Dover-Books-Mathematics/dp/0486488705');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.CalculateColorSpeed1Click(Sender: TObject); // AV
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.CalculateColorSpeed;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.CalculateWeightsClick(Sender: TObject); // AV
|
|
|
|
|
begin
|
|
|
|
|
StopThread;
|
|
|
|
|
UpdateUndo;
|
|
|
|
|
MainCp.CalculateWeights;
|
|
|
|
|
RedrawTimer.Enabled := True;
|
|
|
|
|
UpdateWindows;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMainForm.CreateSubstMap;
|
|
|
|
|
begin
|
|
|
|
|
// AV: set backward compatibility since both plugins crash the scripter
|
|
|
|
|
SubstSource.Add('epispiral'); SubstTarget.Add('Epispiral');
|
|
|
|
|
SubstSource.Add('epispiral_n'); SubstTarget.Add('Epispiral_n');
|
|
|
|
|
SubstSource.Add('epispiral_thickness'); SubstTarget.Add('Epispiral_thickness');
|
|
|
|
|
SubstSource.Add('epispiral_holes'); SubstTarget.Add('Epispiral_holes');
|
|
|
|
|
|
|
|
|
|
{ AV: Apo7X has a bug here: when a source variation
|
|
|
|
|
is avaliable as a plugin, the application internally sets both versions
|
|
|
|
|
(source and substitute). It gives wrong visual results. So I added a checking }
|
|
|
|
|
if (GetVariationIndex('cross2') < 0) then begin // only if plugin is not loaded
|
|
|
|
|
SubstSource.Add('cross2'); SubstTarget.Add('cross');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('bwraps2') < 0) then begin
|
|
|
|
|
SubstSource.Add('bwraps2'); SubstTarget.Add('bwraps');
|
|
|
|
|
SubstSource.Add('bwraps2_cellsize'); SubstTarget.Add('bwraps_cellsize');
|
|
|
|
|
SubstSource.Add('bwraps2_space'); SubstTarget.Add('bwraps_space');
|
|
|
|
|
SubstSource.Add('bwraps2_gain'); SubstTarget.Add('bwraps_gain');
|
|
|
|
|
SubstSource.Add('bwraps2_inner_twist'); SubstTarget.Add('bwraps_inner_twist');
|
|
|
|
|
SubstSource.Add('bwraps2_outer_twist'); SubstTarget.Add('bwraps_outer_twist');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('pre_bwraps2') < 0) then begin
|
|
|
|
|
SubstSource.Add('pre_bwraps2'); SubstTarget.Add('pre_bwraps');
|
|
|
|
|
SubstSource.Add('pre_bwraps2_cellsize'); SubstTarget.Add('pre_bwraps_cellsize');
|
|
|
|
|
SubstSource.Add('pre_bwraps2_space'); SubstTarget.Add('pre_bwraps_space');
|
|
|
|
|
SubstSource.Add('pre_bwraps2_gain'); SubstTarget.Add('pre_bwraps_gain');
|
|
|
|
|
SubstSource.Add('pre_bwraps2_inner_twist'); SubstTarget.Add('pre_bwraps_inner_twist');
|
|
|
|
|
SubstSource.Add('pre_bwraps2_outer_twist'); SubstTarget.Add('pre_bwraps_outer_twist');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('post_bwraps2') < 0) then begin
|
|
|
|
|
SubstSource.Add('post_bwraps2'); SubstTarget.Add('post_bwraps');
|
|
|
|
|
SubstSource.Add('post_bwraps2_cellsize'); SubstTarget.Add('post_bwraps_cellsize');
|
|
|
|
|
SubstSource.Add('post_bwraps2_space'); SubstTarget.Add('post_bwraps_space');
|
|
|
|
|
SubstSource.Add('post_bwraps2_gain'); SubstTarget.Add('post_bwraps_gain');
|
|
|
|
|
SubstSource.Add('post_bwraps2_inner_twist'); SubstTarget.Add('post_bwraps_inner_twist');
|
|
|
|
|
SubstSource.Add('post_bwraps2_outer_twist'); SubstTarget.Add('post_bwraps_outer_twist');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('bwraps7') < 0) then begin
|
|
|
|
|
SubstSource.Add('bwraps7'); SubstTarget.Add('bwraps');
|
|
|
|
|
SubstSource.Add('bwraps7_cellsize'); SubstTarget.Add('bwraps_cellsize');
|
|
|
|
|
SubstSource.Add('bwraps7_space'); SubstTarget.Add('bwraps_space');
|
|
|
|
|
SubstSource.Add('bwraps7_gain'); SubstTarget.Add('bwraps_gain');
|
|
|
|
|
SubstSource.Add('bwraps7_inner_twist'); SubstTarget.Add('bwraps_inner_twist');
|
|
|
|
|
SubstSource.Add('bwraps7_outer_twist'); SubstTarget.Add('bwraps_outer_twist');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('logn') < 0) then begin
|
|
|
|
|
SubstSource.Add('logn'); SubstTarget.Add('log');
|
|
|
|
|
SubstSource.Add('logn_base'); SubstTarget.Add('log_base');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('circleblur') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('circleblur'); SubstTarget.Add('blur_circle');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('circle2') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('circle2'); SubstTarget.Add('blur_circle');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('boarders') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('boarders'); SubstTarget.Add('boarders2');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('dc_boarders') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('dc_boarders'); SubstTarget.Add('boarders2');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('splits3D') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('splits3D'); SubstTarget.Add('splits');
|
|
|
|
|
SubstSource.Add('splits3D_x'); SubstTarget.Add('splits_x');
|
|
|
|
|
SubstSource.Add('splits3D_y'); SubstTarget.Add('splits_y');
|
|
|
|
|
SubstSource.Add('splits3D_z'); SubstTarget.Add('splits_z');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('blob_fl') < 0) then // AV
|
|
|
|
|
begin
|
|
|
|
|
SubstSource.Add('blob_fl'); SubstTarget.Add('blob');
|
|
|
|
|
SubstSource.Add('blob_fl_high'); SubstTarget.Add('blob_fl_high');
|
|
|
|
|
SubstSource.Add('blob_fl_low'); SubstTarget.Add('blob_low');
|
|
|
|
|
SubstSource.Add('blob_fl_waves'); SubstTarget.Add('blob_waves');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('twintrian2') < 0) then begin // AV
|
|
|
|
|
SubstSource.Add('twintrian2'); SubstTarget.Add('twintrian');
|
|
|
|
|
end;
|
|
|
|
|
if (GetVariationIndex('Z_disc2') < 0) then // AV
|
|
|
|
|
begin
|
|
|
|
|
SubstSource.Add('Z_disc2'); SubstTarget.Add('disc2');
|
|
|
|
|
SubstSource.Add('Z_disc2_rot'); SubstTarget.Add('disc2_rot');
|
|
|
|
|
SubstSource.Add('Z_disc2_twist'); SubstTarget.Add('disc2_twist');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
function TMainForm.ReadWithSubst(Attributes: TAttrList; attrname: string): string;
|
2022-06-23 06:22:32 -04:00
|
|
|
|
var i: integer;
|
|
|
|
|
v: string; //TStringType;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value(Utf8String(attrname)));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Result := v;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
for i := 0 to SubstTarget.Count - 1 do begin
|
|
|
|
|
if (SubstTarget[i] = attrname) then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
v := string(Attributes.Value(Utf8String(SubstSource[i])));
|
2022-03-08 12:25:51 -05:00
|
|
|
|
if (v <> '') then begin
|
2022-06-23 06:22:32 -04:00
|
|
|
|
Result := v;
|
2022-03-08 12:25:51 -05:00
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
Result := '';
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end.
|