{$mode objfpc}
unit dvector3f;

interface

uses
  dmath;

type
TFloat = Single;

PVec3f = ^TVec3f;
TVec3f = packed record
case Integer of
  0: (X, Y, Z: TFloat);
  1: (Arr: array[0..2] of TFloat);
end;

const
  Zero3f: TVec3f = (X: 0; Y: 0; Z: 0);

function Vec3f(X, Y, Z: TFloat): TVec3f; inline;
function Add3f(const A, B: TVec3f): TVec3f; inline;
function Sub3f(const A, B: TVec3f): TVec3f; inline;
function Neg3f(const V: TVec3f): TVec3f; inline;
function Mul3f(const A, B: TVec3f): TVec3f; inline;
function Mul3f(const V: TVec3f; F: TFloat): TVec3f; inline;
function Dot3f(const A, B: TVec3f): TFloat; inline;
function Cross3f(const A, B: TVec3f): TVec3f; inline;
function QLen3f(const V: TVec3f): TFloat; inline;
function Len3f(const V: TVec3f): TFloat; inline;
function QDist3f(const A, B: TVec3f): TFloat; inline;
function Dist3f(const A, B: TVec3f): TFloat; inline;
function Norm3f(const V: TVec3f): TVec3f; inline;
function Mir3f(const V, D: TVec3f): TVec3f; inline;
function Rand3f(L, R: TFloat): TVec3f; inline;
function Rand3f(D: TFloat): TVec3f; inline;
function Lerp3f(const A, B: TVec3f; F: TFloat): TVec3f;

implementation

function Vec3f(X, Y, Z: TFloat): TVec3f;
begin
  Result.X := X;
  Result.Y := Y;
  Result.Z := Z;
end;

function Add3f(const A, B: TVec3f): TVec3f;
begin
  Result.X := A.X + B.X;
  Result.Y := A.Y + B.Y;
  Result.Z := A.Z + B.Z;
end;

function Sub3f(const A, B: TVec3f): TVec3f;
begin
  Result.X := A.X - B.X;
  Result.Y := A.Y - B.Y;
  Result.Z := A.Z - B.Z;
end;

function Neg3f(const V: TVec3f): TVec3f;
begin
  Result.X := - V.X;
  Result.Y := - V.Y;
  Result.Z := - V.Z;
end;

function Mul3f(const A, B: TVec3f): TVec3f;
begin
  Result.X := A.X * B.X;
  Result.Y := A.Y * B.Y;
  Result.Z := A.Z * B.Z;
end;

function Mul3f(const V: TVec3f; F: TFloat): TVec3f;
begin
  Result.X := V.X * F;
  Result.Y := V.Y * F;
  Result.Z := V.Z * F;
end;

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

function Cross3f(const A, B: TVec3f): TVec3f;
begin
  Result.X := A.Y * B.Z - A.Z * B.Y;
  Result.Y := A.Z * B.X - A.X * B.Z;
  Result.Z := A.X * B.Y - A.Y * B.X;
end;

function QLen3f(const V: TVec3f): TFloat;
begin
  Result := V.X * V.X + V.Y * V.Y + V.Z * V.Z;
end;

function Len3f(const V: TVec3f): TFloat;
begin
  Result := sqrt(V.X * V.X + V.Y * V.Y + V.Z * V.Z);
end;

function QDist3f(const A, B: TVec3f): TFloat;
begin
  Result := QLen3f(Sub3f(A, B));
end;

function Dist3f(const A, B: TVec3f): TFloat;
begin
  Result := Len3f(Sub3f(A, B));
end;

function Norm3f(const V: TVec3f): TVec3f;
var
  L: TFloat;
begin
  L := Len3f(V);
  if (Abs(L) < EPS) then begin
    Result := Zero3f
  end else
    Result := Mul3f(V, 1/L);
end;

function Mir3f(const V, D: TVec3f): TVec3f;
begin
  Result := Sub3f(V, Mul3f(D, Dot3f(V, D)));
  Result := Sub3f(V, Mul3f(Result, 2));
end;

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

function Rand3f(D: TFloat): TVec3f;
begin
  Result.X := (1 - 2 * Random) * D;
  Result.Y := (1 - 2 * Random) * D;
  Result.Z := (1 - 2 * Random) * D;
end;

function Lerp3f(const A, B: TVec3f; F: TFloat): TVec3f;
begin
  Result.X := A.X + F * (B.X - A.X);
  Result.Y := A.Y + F * (B.Y - A.Y);
  Result.Z := A.Z + F * (B.Z - A.Z);
end;

end.
