Apophysis-AV/Forms/Animate.pas

832 lines
23 KiB
ObjectPascal
Raw Normal View History

{ Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina }
unit Animate;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, StdCtrls, ComCtrls, ExtCtrls,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Samples.Spin, Vcl.Buttons,
Menus, ControlPoint, RenderingInterface, Translation;
type
TAnimateForm = class(TForm)
seFPS: TSpinEdit;
seDuration: TSpinEdit;
edOutFlame: TEdit;
btSetFlame: TSpeedButton;
gbOutput: TGroupBox;
pnlFPS: TPanel;
pnlDuration: TPanel;
pnlOutFlame: TPanel;
btSaveAnimation: TButton;
pnlFrameWidth: TPanel;
pnlFrameHeight: TPanel;
seFrameWidth: TSpinEdit;
seFrameHeight: TSpinEdit;
pnlPrefix: TPanel;
edPrefix: TEdit;
cbAspectRatio: TComboBox;
pnlRatio: TPanel;
AnimPages: TPageControl;
tsSettings: TTabSheet;
chkListFlames: TCheckBox;
AnimStatus: TStatusBar;
gbFrame: TGroupBox;
tsAnimation: TTabSheet;
gbAnimType: TGroupBox;
cbAnimType: TComboBox;
pnlAnimType: TPanel;
pnlStartFlame: TPanel;
cbFlames: TComboBox;
pnlEndFlame: TPanel;
cbFlamesTo: TComboBox;
gbPreview: TGroupBox;
AnimPreview: TImage;
btClose: TButton;
chkResetLocation: TCheckBox;
chkRender: TCheckBox;
QualityPopup: TPopupMenu;
mnuLowQuality: TMenuItem;
mnuMediumQuality: TMenuItem;
mnuHighQuality: TMenuItem;
pnlFrameExt: TPanel;
cbFrameExt: TComboBox;
gbFrameQuality: TGroupBox;
pnlDensity: TPanel;
pnlFilter: TPanel;
pnlOversample: TPanel;
txtDensity: TComboBox;
txtFilterRadius: TEdit;
sbFilterRadius: TSpinButton;
seOversample: TSpinEdit;
lbSeconds: TLabel;
pnlPreview: TPanel;
tbPlay: TSpeedButton;
tbStop: TSpeedButton;
chkInvertBG: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btSaveAnimationClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure btSetFlameClick(Sender: TObject);
procedure cbAspectRatioChange(Sender: TObject);
procedure seFrameWidthChange(Sender: TObject);
procedure seFrameHeightChange(Sender: TObject);
procedure cbFlamesChange(Sender: TObject);
procedure cbAnimTypeChange(Sender: TObject);
procedure tbPlayClick(Sender: TObject);
procedure btCloseClick(Sender: TObject);
procedure mnuPreviewQualityClick(Sender: TObject);
procedure chkRenderClick(Sender: TObject);
procedure sbFilterRadiusDownClick(Sender: TObject);
procedure sbFilterRadiusUpClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure tbStopClick(Sender: TObject);
private
{ Private declarations }
totFrames: integer;
FrameWidth, FrameHeight: integer;
FrameRatio: double;
AnimPrefix, SaveAnimPath: string;
AnimType: shortint;
AnimCp, PreviewCp: TControlPoint;
PreviewDensity: double;
AnimRender: TRenderer;
AnimProc, DrawPreviewProc: TProc;
StatusGenerating, StatusFinished: string;
CurrentFlame: string;
StopAnimate: boolean;
StartBG: array [0..2] of byte;
procedure ARotateFlame;
procedure ARotateReference;
procedure ARotate3DCamera;
procedure ARotateGradient;
procedure ARotateHue;
procedure AMorphing;
procedure LerpBG(const i: integer);
procedure DoAnimate;
procedure FillFlameList;
procedure ChangeControlState(const activate: boolean);
public
{ Public declarations }
procedure UpdateControls;
end;
var
AnimateForm: TAnimateForm;
implementation
{$R *.dfm}
uses
Main, Editor, Global, XForm, XFormMan, CMap, FormRender, Registry;
procedure TAnimateForm.btCloseClick(Sender: TObject);
begin
AnimRender.Stop;
tbStopClick(Sender);
Close;
end;
procedure TAnimateForm.btSaveAnimationClick(Sender: TObject);
var
i: word;
FrameFolder: string;
begin
// AV: first we must check the output directory
SaveAnimPath := edOutFlame.Text;
if SaveAnimPath = '' then begin
Application.MessageBox(PChar(TextByKey('render-status-nofilename')),
ApophysisSVN, 48);
exit;
end;
if not DirectoryExists(ExtractFilePath(SaveAnimPath)) then
raise Exception.Create(TextByKey('render-status-pathdoesnotexist')); // AV
if FileExists(SaveAnimPath) then begin
if Application.MessageBox(PChar(
Format(TextByKey('render-status-fileexists-message1'),[SaveAnimPath]) +
#13#10 + TextByKey('render-status-fileexists-message2')),
ApophysisSVN, 52) = ID_NO then exit;
DeleteFile(SaveAnimPath);
end;
AnimPrefix := edPrefix.Text;
cbFlamesChange(Sender);
AnimCp.AdjustScale(FrameWidth, FrameHeight);
StopAnimate := False;
ChangeControlState(false);
if chkInvertBG.Checked then
for i := 0 to 2 do
StartBG[i] := AnimCp.background[i];
AnimProc := procedure
begin
MainForm.SaveXMLFlame(AnimCp, AnimCp.name, SaveAnimPath);
end;
DoAnimate;
if StopAnimate then begin
AnimStatus.SimpleText := TextByKey('animate-status-stopped');
exit;
end
else
AnimStatus.SimpleText := StatusFinished;
ChangeControlState(true);
if FileExists(SaveAnimPath) then
begin
if chkListFlames.Checked then
begin
OpenFile := SaveAnimPath;
OpenFileType := ftXML;
ListXML(SaveAnimPath, 1);
end;
if chkRender.Checked then
begin
if Assigned(RenderForm.Renderer) then
if Application.MessageBox(PChar(TextByKey('render-status-confirmstop')),
ApophysisSVN, 36) = ID_NO then exit;
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.Terminate;
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #1
RenderForm.ResetControls;
RenderForm.bRenderAll := true;
if Assigned(RenderForm.Renderer) then RenderForm.Renderer.WaitFor; // hmm #2
RenderForm.RenderFlameFile := SaveAnimPath;
SetLength(RenderForm.FlameNames, totFrames);
for i := 0 to totFrames - 1 do
RenderForm.FlameNames[i] := AnimPrefix + Format('%.3d', [i]);
if CreateAnimFolder then begin
FrameFolder := RemoveExt(SaveAnimPath) + '\';
CreateDir(FrameFolder); // create a separate folder for flames
end else
FrameFolder := ExtractFilePath(SaveAnimPath);
RenderForm.Filename := FrameFolder + AnimCp.name +
cbFrameExt.Items[cbFrameExt.ItemIndex];
renderFileFormat := cbFrameExt.ItemIndex + 1;
renderOversample := seOversample.Value;
renderFilterRadius := StrToFloat(txtFilterRadius.Text);
renderDensity := StrToFloat(txtDensity.Text);
renderWidth := seFrameWidth.Value;
renderHeight := seFrameHeight.Value;
SaveInFlame := False; // all flames are already saved
RenderForm.Show;
self.Close;
RenderForm.btnRenderClick(Sender);
end;
end;
end;
procedure TAnimateForm.btSetFlameClick(Sender: TObject);
begin
with MainForm.SaveDialog do begin
Filter := TextByKey('common-filter-flamefiles') + '|*.flame;*.xml|'
+ TextByKey('common-filter-allfiles') + '|*.*';
InitialDir := ParamFolder;
FileName := ExtractFileName(edOutFlame.Text);
if Execute then
begin
if ExtractFileExt(FileName) = '' then
FileName := FileName + '.flame';
edOutFlame.Text := FileName;
end;
end;
end;
procedure TAnimateForm.cbAnimTypeChange(Sender: TObject);
begin
AnimType := cbAnimType.ItemIndex;
if AnimType < 5 then
begin
cbFlamesTo.ItemIndex := cbFlames.ItemIndex;
cbFlamesTo.Enabled := False;
end
else begin
cbFlamesTo.Enabled := True;
end;
end;
procedure TAnimateForm.cbAspectRatioChange(Sender: TObject);
var
r: double;
begin
case cbAspectRatio.ItemIndex of
0, 1: FrameRatio := FrameWidth / FrameHeight;
2: FrameRatio := 1.5;
3: FrameRatio := 4 / 3;
4: FrameRatio := 1.25;
5: FrameRatio := 16 / 9;
6: FrameRatio := 1.6;
7: FrameRatio := 21 / 9;
end;
if FrameRatio > (pnlPreview.Width / pnlPreview.Height) then
begin
AnimPreview.Width := pnlPreview.Width;
r := FrameWidth / AnimPreview.Width;
AnimPreview.Height := round(FrameHeight / r);
AnimPreview.Left := 0;
AnimPreview.Top := (pnlPreview.Height - AnimPreview.Height) shr 1;
end
else begin
AnimPreview.Height := pnlPreview.Height;
r := FrameHeight / AnimPreview.height;
AnimPreview.Width := round(FrameWidth / r);
AnimPreview.Top := 0;
AnimPreview.Left := (pnlPreview.Width - AnimPreview.Width) shr 1;
end;
end;
procedure TAnimateForm.cbFlamesChange(Sender: TObject);
var
flameXML: string;
i: integer;
begin
i := cbFlames.ItemIndex;
if i < 0 then exit;
if i < (cbFlames.Items.Count - 1) then
begin
flameXML := LoadXMLFlameText(Openfile, cbFlames.Items[i]);
MainForm.ParseXML(AnimCp, flameXML, true);
end
else
AnimCp.Copy(MainCp);
seFrameWidth.Value := AnimCp.Width;
seFrameHeight.Value := AnimCp.Height;
cbAspectRatioChange(Sender);
DrawPreviewProc;
end;
procedure TAnimateForm.chkRenderClick(Sender: TObject);
begin
gbFrameQuality.Enabled := chkRender.Checked;
cbFrameExt.Enabled := chkRender.Checked;
end;
procedure TAnimateForm.FillFlameList;
var FItem: TListItem;
begin
cbFlames.Clear;
for FItem in MainForm.ListView1.Items do
cbFlames.AddItem(FItem.Caption, nil);
cbFlames.AddItem(MainCp.name + CurrentFlame, nil);
cbFlames.ItemIndex := cbFlames.Items.Count - 1;
cbFlamesTo.Items.Assign(cbFlames.Items);
cbFlamesTo.ItemIndex := cbFlames.ItemIndex;
end;
procedure TAnimateForm.LerpBG(const i: integer);
var
k, k1: double;
c: byte;
begin
//if (totFrames <= 1) then exit;
k := i / (totFrames - 1);
k1 := (1 - k);
for c := 0 to 2 do
AnimCp.background[c] := Round(k1 * StartBG[c] + k * (255 - StartBG[c]));
end;
procedure TAnimateForm.ARotateFlame;
var
j: integer;
i, nx: smallint;
rstep: double;
Triangles: TTriangles;
fx: TXForm;
begin
rstep := 2 * pi / totFrames;
nx := AnimCp.NumXForms;
fx := TXForm.Create;
fx.Assign(AnimCp.xform[nx]);
AnimCp.TrianglesFromCp(Triangles);
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
for i := -1 to nx - 1 do
Triangles[i] := RotateTriangle(Triangles[i], rstep * j);
AnimCp.GetFromTriangles(Triangles, nx);
AnimCp.xform[nx].Assign(fx);
if chkResetLocation.Checked then AnimCp.CalcBoundbox;
if chkInvertBG.Checked then LerpBG(j);
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
fx.Free;
end;
procedure TAnimateForm.ARotateReference;
var
j, nx: integer;
rstep: double;
Triangles: TTriangles;
fx: TXForm;
begin
rstep := 2 * pi / totFrames;
nx := AnimCp.NumXForms;
fx := TXForm.Create;
fx.Assign(AnimCp.xform[nx]);
AnimCp.TrianglesFromCp(Triangles);
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
Triangles[-1] := RotateTriangle(Triangles[-1], rstep * j);
AnimCp.GetFromTriangles(Triangles, nx);
AnimCp.xform[nx].Assign(fx);
if chkResetLocation.Checked then AnimCp.CalcBoundbox;
if chkInvertBG.Checked then LerpBG(j);
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
fx.Free;
end;
procedure TAnimateForm.ARotate3DCamera;
var
j: integer;
rstep: double;
begin
rstep := 2 * pi / totFrames;
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
AnimCp.cameraPitch := AnimCp.cameraPitch + rstep;
AnimCp.cameraYaw := AnimCp.cameraYaw + rstep;
AnimCp.cameraRoll := AnimCp.cameraRoll + rstep;
if chkResetLocation.Checked then AnimCp.CalcBoundbox;
if chkInvertBG.Checked then LerpBG(j);
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
end;
procedure TAnimateForm.ARotateGradient;
var
i, j, n: integer;
rstep: double;
SourceMap: TColorMap;
begin
SourceMap := AnimCp.cmap;
rstep := 256 / totFrames;
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
for i := 0 to 255 do
begin
n := (256 + i - Round(rstep * j)) mod 256;
AnimCp.cmap[i,0] := SourceMap[n,0];
AnimCp.cmap[i,1] := SourceMap[n,1];
AnimCp.cmap[i,2] := SourceMap[n,2];
end;
if chkInvertBG.Checked then LerpBG(j);
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
end;
procedure TAnimateForm.ARotateHue;
var
j: integer;
h: double;
begin
h := 1 / totFrames;
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
AnimCp.hue_rotation := h;
RotateCMapHue(AnimCp);
AnimCp.hue_rotation := 1;
if chkInvertBG.Checked then LerpBG(j);
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
end;
procedure TAnimateForm.AMorphing;
var
j: integer;
t: smallint;
SourceCp, TargetCp: TControlPoint;
flameXML: string;
begin
j := cbFlamesTo.ItemIndex;
if j = cbFlames.ItemIndex then begin
Application.MessageBox(PChar(TextByKey('animate-status-changeflame')),
ApophysisSVN, 48);
exit;
end;
SourceCp := AnimCp.Clone;
SourceCp.time := 0;
if j < (cbFlamesTo.Items.Count - 1) then
begin
TargetCp := TControlPoint.Create;
flameXML := LoadXMLFlameText(Openfile, cbFlamesTo.Items[j]);
MainForm.ParseXML(TargetCp, flameXML, true);
end
else
TargetCp := MainCp.Clone;
TargetCp.time := totFrames - 1;
PrepareToInterpolation(SourceCp, TargetCp); // adjust non-common parameters
if chkInvertBG.Checked then
for j := 0 to 2 do // invert target background
TargetCp.background[j] := 255 - SourceCp.background[j];
t := AnimType - 5; // interpolation type
try
for j := 0 to totFrames - 1 do
begin
AnimStatus.SimpleText := Format(StatusGenerating, [j+1, totFrames]);
AnimCp.InterpolateAll(SourceCp, TargetCp, j, t);
if chkResetLocation.Checked then AnimCp.CalcBoundbox;
AnimCp.name := AnimPrefix + Format('%.3d', [j]);
AnimProc;
if StopAnimate then break;
end;
finally
SourceCp.Free;
TargetCp.Free;
end;
end;
procedure TAnimateForm.DoAnimate;
begin
totFrames := seFPS.Value * seDuration.Value;
try
case AnimType of
0: ARotateFlame;
1: ARotateReference;
2: ARotate3DCamera;
3: ARotateGradient;
4: ARotateHue;
5..8: AMorphing;
end;
except
// TODO
end;
end;
procedure TAnimateForm.FormClose(Sender: TObject; var Action: TCloseAction);
var
Registry: TRegistry;
begin
{ Write position to registry }
Registry := TRegistry.Create;
try
Registry.RootKey := HKEY_CURRENT_USER;
if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Animate', True) then
begin
Registry.WriteInteger('Top', self.Top);
Registry.WriteInteger('Left', self.Left);
Registry.WriteBool('ResetLocation', chkResetLocation.Checked);
Registry.WriteBool('ListFlames', chkListFlames.Checked);
Registry.WriteBool('RenderFrames', chkRender.Checked);
Registry.WriteInteger('AnimationType', cbAnimType.ItemIndex);
end;
finally
Registry.Free;
end;
end;
procedure TAnimateForm.FormCreate(Sender: TObject);
begin
self.Caption := TextByKey('animate-title');
tsSettings.Caption := TextByKey('animate-general');
tsAnimation.Caption := TextByKey('animate-animation');
gbOutput.Caption := TextByKey('animate-output');
pnlOutFlame.Caption := TextByKey('animate-outflame');
pnlPrefix.Caption := TextByKey('animate-prefix');
gbPreview.Caption := TextByKey('animate-preview');
pnlFrameExt.Caption := TextByKey('animate-graphicext');
pnlDuration.Caption := TextByKey('animate-duration');
lbSeconds.Caption := TextByKey('common-seconds');
pnlFPS.Caption := TextByKey('animate-fps');
gbFrame.Caption := TextByKey('animate-frame');
pnlFrameWidth.Caption := TextByKey('common-width');
pnlFrameHeight.Caption := TextByKey('common-height');
pnlRatio.Caption := TextByKey('adjustment-tab-size-ratio');
cbAspectRatio.Items[0] := TextByKey('adjustment-tab-size-custom');
cbAspectRatio.Items[1] := TextByKey('common-keepaspect');
cbAspectRatio.ItemIndex := 1; // keep current aspect ratio
gbFrameQuality.Caption := TextByKey('common-quality');
pnlFilter.Caption := TextByKey('common-filterradius');
pnlDensity.Caption := TextByKey('common-density');
pnlOversample.Caption := TextByKey('common-oversample');
gbAnimType.Caption := TextByKey('animate-parameters');
pnlAnimType.Caption := TextByKey('animate-type');
chkListFlames.Caption := TextByKey('animate-showframes');
chkRender.Caption := TextByKey('animate-render');
chkResetLocation.Caption := TextByKey('animate-resetlocation');
chkInvertBG.Caption := TextByKey('animate-invertbg');
tbPlay.Caption := TextByKey('common-start');
btSaveAnimation.Caption := TextByKey('animate-save');
btClose.Caption := TextByKey('common-close');
btSetFlame.Hint := TextByKey('common-browse');
StatusGenerating := TextByKey('animate-status-generating');
StatusFinished := TextByKey('animate-status-finished');
CurrentFlame := #32 + TextByKey('animate-currentflame');
pnlStartFlame.Caption := TextByKey('animate-initflame');
pnlEndFlame.Caption := TextByKey('animate-finalflame');
tbPlay.Hint := TextByKey('animate-playhint');
tbStop.Hint := TextByKey('animate-stophint');
tbStop.Caption := TextByKey('animate-stop');
btSaveAnimation.Hint := TextByKey('animate-savehint');
cbAnimType.Items[0] := TextByKey('animate-kind-rotateflame');
cbAnimType.Items[1] := TextByKey('animate-kind-rotatereference');
cbAnimType.Items[2] := TextByKey('animate-kind-rotatecamera');
cbAnimType.Items[3] := TextByKey('animate-kind-rotatepalette');
cbAnimType.Items[4] := TextByKey('animate-kind-rotatehue');
cbAnimType.Items[5] := TextByKey('animate-kind-morph1');
cbAnimType.Items[6] := TextByKey('animate-kind-morph2');
cbAnimType.Items[7] := TextByKey('animate-kind-morph3');
cbAnimType.Items[8] := TextByKey('animate-kind-morph4');
cbAnimType.ItemIndex := 0;
mnuLowQuality.Caption := TextByKey('common-lowquality');
mnuMediumQuality.Caption := TextByKey('common-mediumquality');
mnuHighQuality.Caption := TextByKey('common-highquality');
case AnimPrevQual of
0: begin
PreviewDensity := prevLowQuality;
mnuLowQuality.Checked := True;
end;
1: begin
PreviewDensity := prevMediumQuality;
mnuMediumQuality.Checked := True;
end;
2: begin
PreviewDensity := prevHighQuality;
mnuHighQuality.Checked := True;
end;
end;
AnimCp := TControlPoint.Create;
PreviewCp := TControlPoint.Create;
AnimRender := TRenderer.Create;
DrawPreviewProc := procedure
begin
PreviewCp.Copy(AnimCp);
PreviewCp.sample_density := PreviewDensity;
PreviewCp.AdjustScale(AnimPreview.Width, AnimPreview.Height);
AnimRender.Stop;
AnimRender.SetCP(PreviewCp);
AnimRender.Render;
AnimPreview.Picture.Graphic := AnimRender.GetImage;
Application.ProcessMessages;
end;
end;
procedure TAnimateForm.FormDestroy(Sender: TObject);
begin
AnimCp.Free;
PreviewCp.Free;
AnimRender.Free;
end;
procedure TAnimateForm.FormShow(Sender: TObject);
var
Registry: TRegistry;
begin
{ Read position from registry }
Registry := TRegistry.Create;
try
Registry.RootKey := HKEY_CURRENT_USER;
if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Animate', False) then
begin
if Registry.ValueExists('Left') then
self.Left := Registry.ReadInteger('Left');
if Registry.ValueExists('Top') then
self.Top := Registry.ReadInteger('Top');
if Registry.ValueExists('ResetLocation') then
chkResetLocation.Checked := Registry.ReadBool('ResetLocation');
if Registry.ValueExists('ListFlames') then
chkListFlames.Checked := Registry.ReadBool('ListFlames');
if Registry.ValueExists('RenderFrames') then
chkRender.Checked := Registry.ReadBool('RenderFrames');
if Registry.ValueExists('AnimationType') then
cbAnimType.ItemIndex := Registry.ReadInteger('AnimationType');
Registry.CloseKey;
end;
finally
Registry.Free;
end;
cbFrameExt.ItemIndex := defFrameExt;
txtDensity.Text := FloatToStr(renderDensity);
txtFilterRadius.Text := FloatToStr(Round6(renderFilterRadius));
seOversample.Value := renderOversample;
edPrefix.Text := defAnimPrefix;
seFPS.Value := AnimFPS;
edOutFlame.Text := ParamFolder + MainCp.name + ' (animated).flame';
chkRenderClick(Sender);
cbAnimTypeChange(Sender);
UpdateControls;
end;
procedure TAnimateForm.mnuPreviewQualityClick(Sender: TObject);
begin
if TMenuItem(Sender).Checked then exit; // prevent unneseccary updating
TMenuItem(Sender).Checked := True;
case TMenuItem(Sender).Tag of
0: PreviewDensity := prevMediumQuality;
1: PreviewDensity := prevMediumQuality;
2: PreviewDensity := prevHighQuality;
end;
AnimPrevQual := TMenuItem(Sender).Tag;
DrawPreviewProc;
end;
procedure TAnimateForm.sbFilterRadiusDownClick(Sender: TObject);
var n: double;
begin
try
n := StrToFloat(txtFilterRadius.Text);
n := Round6(n - 0.05);
if (n > 0) then
txtFilterRadius.Text := FloatToStr(n);
except
raise Exception.Create(TextByKey('render-status-invalidfilterradius'));
end;
end;
procedure TAnimateForm.sbFilterRadiusUpClick(Sender: TObject);
var n: double;
begin
try
n := StrToFloat(txtFilterRadius.Text);
txtFilterRadius.Text := Format('%.3g', [n + 0.05]);
except
raise Exception.Create(TextByKey('render-status-invalidfilterradius'));
end;
end;
procedure TAnimateForm.seFrameHeightChange(Sender: TObject);
begin
try
FrameHeight := seFrameHeight.Value;
if (cbAspectRatio.ItemIndex > 0) and seFrameHeight.Focused then
begin
FrameWidth := Round(FrameHeight * FrameRatio);
seFrameWidth.Value := FrameWidth;
end;
except
end;
end;
procedure TAnimateForm.seFrameWidthChange(Sender: TObject);
begin
try
FrameWidth := seFrameWidth.Value;
if (cbAspectRatio.ItemIndex > 0) and seFrameWidth.Focused then
begin
FrameHeight := Round(FrameWidth / FrameRatio);
seFrameHeight.Value := FrameHeight;
end;
except
end;
end;
procedure TAnimateForm.tbPlayClick(Sender: TObject);
var i: byte;
begin
StopAnimate := False;
cbFlamesChange(Sender);
ChangeControlState(false);
if chkInvertBG.Checked then
for i := 0 to 2 do
StartBG[i] := AnimCp.background[i];
AnimProc := DrawPreviewProc;
DoAnimate;
AnimStatus.SimpleText := '';
ChangeControlState(true);
end;
procedure TAnimateForm.tbStopClick(Sender: TObject);
begin
StopAnimate := True;
ChangeControlState(true);
end;
procedure TAnimateForm.ChangeControlState(const activate: boolean);
begin
gbFrame.Enabled := activate;
gbAnimType.Enabled := activate;
btSaveAnimation.Enabled := activate;
tbPlay.Enabled := activate;
tbStop.Enabled := not activate;
end;
procedure TAnimateForm.UpdateControls;
begin
FillFlameList;
cbFlamesChange(self);
end;
end.