832 lines
23 KiB
ObjectPascal
832 lines
23 KiB
ObjectPascal
{ 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.
|