{
     Apophysis Copyright (C) 2001-2004 Mark Townsend
     Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov
     Apophysis Copyright (C) 2007-2008 Piotr Borys, Peter Sdobnov
     
     Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov
     Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne
     Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina

     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}

unit XFormMan;

interface

uses
  BaseVariation, SysUtils, System.Generics.Collections;

const
  NRLOCVAR = 36;
var
  NumBuiltinVars: integer;

function NrVar: integer;
function Varnames(const index: integer): String;
procedure RegisterVariation(Variation: TVariationLoader; supports3D, supportsDC : boolean);
function GetNrRegisteredVariations: integer;
function GetRegisteredVariation(const Index: integer): TVariationLoader;
function GetNrVariableNames: integer;
function GetVariableNameAt(const Index: integer): string;
function GetVariationIndex(const str: string): integer;
function GetVariationIndexFromVariableNameIndex(const Index: integer): integer;
function VarSupports3D(index: smallint): boolean;   // AV
function VarSupportsDC(index: smallint): boolean;   // AV
procedure FillVarNamesList;  // AV

implementation

uses
  Classes;

var
  VariationList: TList<TVariationLoader>;  // AV: changed to generic type
  VariationNames: TStringList;  // AV
  VariableNames: TStringList;
  Variable2VariationIndex : array of integer;
  Vars3D: array of boolean;
  VarsDC: array of boolean;

procedure InitializeXFormMan;
begin
  VariationList := TList<TVariationLoader>.Create; // AV: changed to generic type
  VariationNames := TStringList.Create;  // AV
  VariableNames := TStringList.create;
  SetLength(Variable2VariationIndex,0);
end;

procedure FillVarsSupport;  // AV
const
  supports3D_arr: array[0..NRLOCVAR-1] of boolean = (
    true, //'linear',
    true, //'flatten',
    true, //'pre_blur3D',
    true, //'spherical',
    true, //'swirl',
    true, //'horseshoe',
    true, //'polar',
    true, //'disc',
    true, //'spiral',
    true, //'hyperbolic',
    true, //'diamond',
    true, //'eyefish',
    true, //'bubble',
    true, //'cylinder',
    true, //'noise',
    true, //'blur',
    false, //'gaussian_blur',
    true, //'zblur',
    true, //'blur3D',
    false, //'pre_blur',
    true, //'pre_zscale',
    true, //'pre_ztranslate',
    true, //'pre_rotate_x',
    true, //'pre_rotate_y',
    true, //'zscale',
    true, //'ztranslate',
    true, //'zcone',
    true, //'post_rotate_x',
    true, //'post_rotate_y',
    false, //'post_mirror_x',
    false, //'post_mirror_y',
    true, //'post_mirror_z',
    true, //'hemisphere',
    true, //'cross',
    true, //'pyramid'
    true  // polar2
    );
 supportsDC_arr: array[0..NRLOCVAR-1] of boolean = (
    false, //'linear',
    false, //'flatten',
    false, //'pre_blur3D',
    false, //'spherical',
    false, //'swirl',
    false, //'horseshoe',
    false, //'polar',

    false, //'disc',
    false, //'spiral',
    false, //'hyperbolic',
    false, //'diamond',

    false, //'eyefish',
    false, //'bubble',
    false, //'cylinder',
    false, //'noise',
    false, //'blur',
    false, //'gaussian_blur',
    false, //'zblur',
    false, //'blur3D',

    false, //'pre_blur',
    false, //'pre_zscale',
    false, //'pre_ztranslate',
    false, //'pre_rotate_x',
    false, //'pre_rotate_y',

    false, //'zscale',
    false, //'ztranslate',
    false, //'zcone',

    false, //'post_rotate_x',
    false, //'post_rotate_y'

    false, //'post_mirror_x',
    false, //'post_mirror_y',
    false, //'post_mirror_z',

    false, //'hemisphere',
    false, //'cross',
    false, //'pyramid'
    false //  polar2
    );
var i: word;
begin
  SetLength(Vars3D, VariationNames.Count);
  SetLength(VarsDC, VariationNames.Count);
  for i := 0 to NRLOCVAR-1 do
  begin
    Vars3D[i] := supports3D_arr[i];
    VarsDC[i] := supportsDC_arr[i];
  end;
  for i := 0 to VariationList.Count - 1 do
  begin
    Vars3D[i + NRLOCVAR] := VariationList[i].Supports3D;
    VarsDC[i + NRLOCVAR] := VariationList[i].SupportsDC;
  end;
end;

function VarSupports3D(index: smallint): boolean;
begin
    Result := Vars3D[index];  // AV: added precalc
end;

function VarSupportsDC(index: smallint): boolean;
begin
    Result := VarsDC[index];  // AV: added precalc
end;

{ ///////////////////////////////////////////////////////////////////////// }

procedure DestroyXFormMan;
var i: integer;
begin
  VariationNames.Free;  // AV
  VariableNames.Free;

  // The registered variation loaders are owned here, so we must free them.
  for i := 0 to VariationList.Count-1 do
    VariationList[i].Free;
  VariationList.Free;
end;

///////////////////////////////////////////////////////////////////////////////
function NrVar: integer; // AV: reduce Nr of calc since we use it thousand times
begin
  Result := VariationNames.Count; // NRLOCVAR + VariationList.Count;
end;

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

function GetVariationIndexFromVariableNameIndex(const Index: integer): integer;
begin
  if (Index < 0) or (Index > High(Variable2VariationIndex)) then
    Result := -1
  else
    Result := Variable2VariationIndex[Index];
end;

{ ////////////////////////////////////////////////////////////////////////// }

procedure FillVarNamesList;  // AV: this method used once at startup
const
  cvarnames: array[0..NRLOCVAR-1] of string = (
    'linear',
    'flatten',
    'pre_blur3D',
    'spherical',
    'swirl',
    'horseshoe',
    'polar',
    'disc',
    'spiral',
    'hyperbolic',
    'diamond',
    'eyefish',
    'bubble',
    'cylinder',
    'noise',
    'blur',
    'gaussian_blur',
    'zblur',
    'blur3D',
    'pre_blur',
    'pre_zscale',
    'pre_ztranslate',
    'pre_rotate_x',
    'pre_rotate_y',
    'zscale',
    'ztranslate',
    'zcone',
    'post_rotate_x',
    'post_rotate_y',
    'post_mirror_x',
    'post_mirror_y',
    'post_mirror_z',
    'hemisphere',
    'cross',
    'pyramid',
    'polar2'
    );
var i: integer;
begin
  for i := 0 to High(cvarnames) do
    VariationNames.Add(cvarnames[i]);
  for i := 0 to VariationList.Count - 1 do
    VariationNames.Add(VariationList[i].GetName);

  VariationList.TrimExcess;

  FillVarsSupport;  // 3D and DC
end;

function Varnames(const index: integer): string;  // AV: totally rewritten
begin
  if (index >= 0) and (index < VariationNames.Count) then
    Result := VariationNames[index]
  else
    Result := '';
end;

function GetVariationIndex(const str: string): integer; // AV: totally rewritten
begin
  Result := VariationNames.IndexOf(str);
end;

///////////////////////////////////////////////////////////////////////////////
(*
procedure RegisterVariationFile(filename, name: string);
begin
  FNToVNCount := FNToVNCount + 1;
  SetLength(FNToVNList, FNToVNCount);
  FNToVNList[FNToVNCount - 1].FileName := filename;
  FNToVNList[FNToVNCount - 1].VarName := name;
end;

function GetFileNameOfVariation(name: string): string;
var i: integer;
begin
  for i := 0 to FNToVNCount - 1 do begin
    if FNToVNList[i].VarName = name then begin
      Result := FNToVNList[i].FileName;
      Exit;
    end;
  end;
  Result := '';
end;
*)

procedure RegisterVariation(Variation: TVariationLoader; supports3D, supportsDC : boolean);
var
  i: integer;
  prevNumVariables:integer;
begin
  // OutputDebugString(PChar(Variation.GetName));

  VariationList.Add(Variation);
  Variation.Supports3D := supports3D;
  Variation.SupportsDC := supportsDC;

  prevNumVariables := GetNrVariableNames;
  setLength(Variable2VariationIndex, prevNumVariables + Variation.GetNrVariables);
  for i := 0 to Variation.GetNrVariables - 1 do begin
    VariableNames.Add(Variation.GetVariableNameAt(i));
    Variable2VariationIndex[prevNumVariables + i] := NRLOCVAR + VariationList.Count - 1; //NrVar-1;
  end;
end;

///////////////////////////////////////////////////////////////////////////////
function GetNrRegisteredVariations: integer;
begin
  Result := VariationList.count;
end;

///////////////////////////////////////////////////////////////////////////////
function GetRegisteredVariation(const Index: integer): TVariationLoader;
begin
  // AV: no more unsafe type casting here since we use generics!
  Result := VariationList[Index];
end;

///////////////////////////////////////////////////////////////////////////////
function GetNrVariableNames: integer;
begin
  Result := VariableNames.Count;
end;

///////////////////////////////////////////////////////////////////////////////
function GetVariableNameAt(const Index: integer): string;
begin
  Result := VariableNames[Index];
end;

///////////////////////////////////////////////////////////////////////////////
initialization
  InitializeXFormMan;
  
finalization
  DestroyXFormMan;

end.
