{$mode objfpc}
unit dvector4f;

interface

uses
  dmath;

type
TFloat = Single;

PVec4f = ^TVec4f;
TVec4f = packed record
case Integer of
  0: (X, Y, Z, W: TFloat);
  1: (Arr: array[0..3] of TFloat);
end;

const
  Zero4f: TVec4f = (X: 0; Y: 0; Z: 0; W: 0);

function Vec4f(X, Y, Z, W: TFloat): TVec4f; inline;
function Add4f(const A, B: TVec4f): TVec4f; inline;
function Sub4f(const A, B: TVec4f): TVec4f; inline;
function Neg4f(const V: TVec4f): TVec4f; inline;
function Mul4f(const A, B: TVec4f): TVec4f; inline;
function Mul4f(const V: TVec4f; F: TFloat): TVec4f; inline;
function Dot4f(const A, B: TVec4f): TFloat; inline;
function QLen4f(const V: TVec4f): TFloat; inline;
function Len4f(const V: TVec4f): TFloat; inline;
function QDist4f(const A, B: TVec4f): TFloat; inline;
function Dist4f(const A, B: TVec4f): TFloat; inline;
function Norm4f(const V: TVec4f): TVec4f; inline;
function Mir4f(const V, D: TVec4f): TVec4f; inline;
function Rand4f(L, R: TFloat): TVec4f; inline;
function Rand4f(D: TFloat): TVec4f; inline;

implementation

function Vec4f(X, Y, Z, W: TFloat): TVec4f;
begin
  Result.X := X;
  Result.Y := Y;
  Result.Z := Z;
  Result.W := W;
end;

function Add4f(const A, B: TVec4f): TVec4f;
begin
  Result.X := A.X + B.X;
  Result.Y := A.Y + B.Y;
  Result.Z := A.Z + B.Z;
  Result.W := A.W + B.W;
end;

function Sub4f(const A, B: TVec4f): TVec4f;
begin
  Result.X := A.X - B.X;
  Result.Y := A.Y - B.Y;
  Result.Z := A.Z - B.Z;
  Result.W := A.W - B.W;
end;

function Neg4f(const V: TVec4f): TVec4f;
begin
  Result.X := - V.X;
  Result.Y := - V.Y;
  Result.Z := - V.Z;
  Result.W := - V.W;
end;

function Mul4f(const A, B: TVec4f): TVec4f;
begin
  Result.X := A.X * B.X;
  Result.Y := A.Y * B.Y;
  Result.Z := A.Z * B.Z;
  Result.W := A.W * B.W;
end;

function Mul4f(const V: TVec4f; F: TFloat): TVec4f;
begin
  Result.X := V.X * F;
  Result.Y := V.Y * F;
  Result.Z := V.Z * F;
  Result.W := V.W * F;
end;

function Dot4f(const A, B: TVec4f): TFloat;
begin
  Result := A.X * B.X + A.Y * B.Y + A.Z * B.Z + A.W * B.W;
end;

function QLen4f(const V: TVec4f): TFloat;
begin
  Result := V.X * V.X + V.Y * V.Y + V.Z * V.Z + V.W * V.W;
end;

function Len4f(const V: TVec4f): TFloat;
begin
  Result := sqrt(V.X * V.X + V.Y * V.Y + V.Z * V.Z + V.W * V.W);
end;

function QDist4f(const A, B: TVec4f): TFloat;
begin
  Result := QLen4f(Sub4f(A, B));
end;

function Dist4f(const A, B: TVec4f): TFloat;
begin
  Result := Len4f(Sub4f(A, B));
end;

function Norm4f(const V: TVec4f): TVec4f;
var
  L: TFloat;
begin
  L := Len4f(V);
  if (Abs(L) < EPS) then
      Result := Zero4f
  else
      Result := Mul4f(V, 1/L);
end;

function Mir4f(const V, D: TVec4f): TVec4f;
begin
  Result := Sub4f(V, Mul4f(D, Dot4f(V, D)));
  Result := Sub4f(V, Mul4f(Result, 2));
end;

function Rand4f(L, R: TFloat): TVec4f;
begin
  Result.X := Random * (R - L) + L;
  Result.Y := Random * (R - L) + L;
  Result.Z := Random * (R - L) + L;
  Result.W := Random * (R - L) + L;
end;

function Rand4f(D: TFloat): TVec4f;
begin
  // TODO
  Result := Zero4f;
end;

end.
