{$MODE OBJFPC}
unit dgen_operators;

interface

uses
  dgenerator,
  dcolors,
  dvector2f,
  dvector4f,
  dscreenbuffer,
  dtexture2d_generator;

type
TTransformGen = class(TTexGen)
  Source: TTexGen;
  Scale: TVec2f;
  Translate: TVec2f;
  Rotate: TVec2f;
  function Get(const V: TVec2f): TColor; override;
end;

TBinaryGen = class(TTexGen)
  Left, Right: TTexGen;
  constructor Create(L, R: TTexGen);
end;

TAddGen = class(TBinaryGen)
  function Get(const V: TVec2f): TColor; override;
end;

TUnaryGen = class(TTexGen)
  Source: TTexGen;
  constructor Create(Gen: TTexGen);
end;

TMulGen = class(TUnaryGen)
  Scale: TVec4f;
  function Get(const V: TVec2f): TColor; override;
end;

{TSinGen = class(TMonoGen)
  Factor: TVec2f;
  Freq: Single;
  function GetMono(const V: TVec2f): Single; override;
end;}

TTexGenAdd4f = class(NTexGen4f.TBinary)
  function Binary(const L, R: TVec4f): TVec4f; override;
end;
TTexGenSub4f = class(NTexGen4f.TBinary)
  function Binary(const L, R: TVec4f): TVec4f; override;
end;
TTexGenMul4f = class(NTexGen4f.TBinary)
  function Binary(const L, R: TVec4f): TVec4f; override;
end;
TTexGenAdd4b = class(NTexGen4b.TBinary)
  function Binary(const L, R: TColor): TColor; override;
end;

TTexGenUnary4f = NTexGen4f.TUnary;
TTexGenUAdd4f = class(NTexGen4f.TUnary)
  FValue: TVec4f;
  //function Unary(const Value: Vec4f): TVec4f; override;
end;
TTexGenUSub4f = class(NTexGen4f.TUnary)
  FValue: TVec4f;
  //function Unary(const Value: Vec4f): TVec4f; override;
end;
TTexGenUMul4f = class(NTexGen4f.TUnary)
  FValue: TVec4f;
  //function Unary(const Value: Vec4f): TVec4f; override;
end;

function Scale(Gen: TTexGen; const S: TVec2f): TTransformGen;
function Scale(Gen: TTexGen; const S: Single): TTransformGen;
function Translate(Gen: TTexGen; const D: TVec2f): TTransformGen;
function Rotate(Gen: TTexGen; A: Single): TTransformGen;
//operator * (const S: TVec2f; Gen: TTexGen): TTransformGen;
operator * (const S: TVec4f; Gen: TTexGen): TMulGen;
operator * (const S: Single; Gen: TTexGen): TMulGen;
operator + (G, H: TTexGen): TAddGen;

operator + (L, R: TTexGen4f): TTexGen4f;
operator - (L, R: TTexGen4f): TTexGen4f;
operator * (L, R: TTexGen4f): TTexGen4f;

operator + (L, R: TTexGen4b): TTexGen4b;

implementation

function TTransformGen.Get(const V: TVec2f): TColor;
begin
  Result := Source.Get(Add2f(Translate, Mul2f(Scale,
    Vec2f(Rotate.X * V.X + Rotate.Y * V.Y, Rotate.X * V.Y - Rotate.Y * V.x))));
end;

constructor TBinaryGen.Create(L, R: TTexGen);
begin
  inherited Create;
  Left := L;
  Right := R;
end;

function TAddGen.Get(const V: TVec2f): TColor;
begin
  Result := ColorAdd(Left.Get(V), Right.Get(V));
end;

constructor TUnaryGen.Create(Gen: TTexGen);
begin
  inherited Create;
  Link(Source, Gen);
end;

function TMulGen.Get(const V: TVec2f): TColor;
begin
  Result := ColorMul(Source.Get(V), Scale);
end;

{function TSinGen.GetMono(const V: TVec2f): Single;
begin
  Result := Sin();
end;}

function TTexGenAdd4f.Binary(const L, R: TVec4f): TVec4f;
begin
  Result := Add4f(L, R);
end;

function TTexGenSub4f.Binary(const L, R: TVec4f): TVec4f;
begin
  Result := Sub4f(L, R);
end;

function TTexGenMul4f.Binary(const L, R: TVec4f): TVec4f;
begin
  Result := Mul4f(L, R);
end;

function TTexGenAdd4b.Binary(const L, R: TColor): TColor;
begin
  Result := L + R;
end;

function Scale(Gen: TTexGen; const S: TVec2f): TTransformGen;
begin
  Result := TTransformGen.Create;
  Result.Scale := Vec2f(1 / S.X, 1 / S.Y);
  Result.Translate := Vec2f(0, 0);
  Result.Rotate := Vec2f(1, 0);
  Result.Link(Result.Source, Gen);
end;

function Scale(Gen: TTexGen; const S: Single): TTransformGen;
begin
  Result := Scale(Gen, Vec2f(S, S));
end;

function Translate(Gen: TTexGen; const D: TVec2f): TTransformGen;
begin
  Result := TTransformGen.Create;
  Result.Scale := Vec2f(1, 1);
  Result.Translate := D;
  Result.Rotate := Vec2f(1, 0);
  Result.Link(Result.Source, Gen);
end;

function Rotate(Gen: TTexGen; A: Single): TTransformGen;
begin
  Result := TTransformGen.Create;
  Result.Scale := Vec2f(1, 1);
  Result.Translate := Vec2f(0, 0);
  Result.Rotate := Vec2f(Cos(A), Sin(A));
  Result.Link(Result.Source, Gen);
end;

{operator * (const S: TVec2f; Gen: TTexGen): TTransformGen;
begin
  Result := TTransformGen.Create;
  Result.Scale := S;
  Result.Link(Result.Source, Gen);
end;}

operator * (const S: TVec4f; Gen: TTexGen): TMulGen;
begin
  Result := TMulGen.Create(Gen);
  Result.Scale := S;
end;

operator * (const S: Single; Gen: TTexGen): TMulGen;
begin
  Result := (Vec4f(S, S, S, 1) * Gen);
end;

operator + (G, H: TTexGen): TAddGen;
begin
  Result := TAddGen.Create(G, H);
end;

operator + (L, R: TTexGen4f): TTexGen4f;
begin
  Result := TTexGenAdd4f.Create(L, R);
end;

operator - (L, R: TTexGen4f): TTexGen4f;
begin
  Result := TTexGenSub4f.Create(L, R);
end;

operator * (L, R: TTexGen4f): TTexGen4f;
begin
  Result := TTexGenMul4f.Create(L, R);
end;

operator + (L, R: TTexGen4b): TTexGen4b;
begin
  Result := TTexGen4b(TTexGenAdd4b.Create(L, R));
end;

end.
