{  Apophysis AV "Phoenix Edition" Copyright (C) 2021 Alice V. Koryagina }

unit varDisc2;

interface

uses
  BaseVariation, XFormMan;
             
{$ifdef CPUX86}
  {$define _ASM_}
{$endif}  			 

type
  TVariationDisc2 = class(TBaseVariation)
  private
    rot, add, p, k, sinadd, cosadd: double;
  public
    constructor Create;

    class function GetName: string; override;
    class function GetInstance: TBaseVariation; override;

    function GetNrVariables: integer; override;
    function GetVariableNameAt(const Index: integer): string; override;

    function SetVariable(const Name: string; var value: double): boolean; override;
    function GetVariable(const Name: string; var value: double): boolean; override;

    procedure Prepare; override;
    procedure CalcFunction; override;
  end;

implementation

uses
  Math;

{ TVariationDisc2 }

///////////////////////////////////////////////////////////////////////////////
constructor TVariationDisc2.Create;
begin
  rot := random + 0.5;
end;

///////////////////////////////////////////////////////////////////////////////
procedure TVariationDisc2.Prepare;
var t: double;
begin
	p := vvar / PI;
	k := rot * PI;
	SinCos(add, sinadd, cosadd);
	cosadd := cosadd - 1;
	if (add > PI2) then begin
		t := 1 + add - PI2;
		cosadd := cosadd * t;
		sinadd := sinadd * t;
	end
	else if (add < -PI2) then begin
		t := 1 + add + PI2;
		cosadd := cosadd * t;
		sinadd := sinadd * t;
	end;
end;

///////////////////////////////////////////////////////////////////////////////

procedure TVariationDisc2.CalcFunction;
{$ifndef _ASM_}
var
  r, sinr, cosr: extended;
begin
  SinCos(k * (FTx^ + FTy^), sinr, cosr);
  r := p * arctan2(FTx^, FTy^);
  FPx^ := FPx^ + (sinr + cosadd) * r;
  FPy^ := FPy^ + (cosr + sinadd) * r;
{$else}
asm
    mov     edx, [eax + FTx]
    fld     qword ptr [edx]
    fld     qword ptr [edx + 8]
    fpatan
    fmul    qword ptr [eax + p]
    fld     qword ptr [edx]
    fadd    qword ptr [edx + 8]
    fmul    qword ptr [eax + k]
    fsincos
    fadd    qword ptr [eax + sinadd]
    fmul    st, st(2)
    fadd    qword ptr [edx + 24]
    fstp    qword ptr [edx + 24]
    fadd    qword ptr [eax + cosadd]
    fmulp
    fadd    qword ptr [edx + 16]
    fstp    qword ptr [edx + 16]
{$endif}
end;


///////////////////////////////////////////////////////////////////////////////
class function TVariationDisc2.GetInstance: TBaseVariation;
begin
  Result := TVariationDisc2.Create;
end;

///////////////////////////////////////////////////////////////////////////////
class function TVariationDisc2.GetName: string;
begin
  Result := 'disc2';
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationDisc2.GetVariableNameAt(const Index: integer): string;
begin
  case Index Of
  0: Result := 'disc2_rot';
  1: Result := 'disc2_twist';
  else
    Result := '';
  end;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationDisc2.SetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
  if Name = 'disc2_rot' then
  begin
    rot := Value;
    Result := True end
  else if Name = 'disc2_twist' then
  begin
    add := Value;
    Result := True;
  end;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationDisc2.GetNrVariables: integer;
begin
  Result := 2;
end;

///////////////////////////////////////////////////////////////////////////////
function TVariationDisc2.GetVariable(const Name: string; var value: double): boolean;
begin
  Result := False;
  if Name = 'disc2_rot' then
  begin
    Value := rot;
    Result := True end
  else if Name = 'disc2_twist' then
  begin
    Value := add;
    Result := True;
  end;
end;

///////////////////////////////////////////////////////////////////////////////
initialization
  RegisterVariation(TVariationClassLoader.Create(TVariationDisc2), false, false);
end.
