unit spheres;

{$I init.inc}

{*Unit Spheres***********************************************************

 Sphere rountines [no kidding!]

 Created            : 05/02/93
 Last Change        : 02/05/93
 Revisions          : none

 ************************************************************************}

interface

uses globals;

type
  PSphere = ^TSphere;
  TSphere = Object(TPrim)
    Center : Point;
    Rad : Flt;
    Rad2 : Flt;
    constructor Init(Cen : Point; R : Flt);
    function Intersect(Ray : TRay; var Hitlist : PHitlist) : byte; virtual;
    procedure Normal(P : Point; var N : Vec); virtual;
    destructor Done; virtual;
  end;

implementation

{$I vectors.inc }

{*Sphere Routines**********************************************************}

constructor TSphere.Init;

begin
  TPrim.Init;
  Center :=  Cen;                 { Initialize variables }
  Rad := R;
  Rad2 := sqr(rad);              { Rad2 = Rad^2 for later use }

  {$IFDEF Debug}
    Writeln(con,'Initialised Sphere at ',center[0]:7:3,center[1]:7:3,center[2]:7:3);
    Writeln(con,'            radius    ',rad:7:3); writeln;
  {$ENDIF}
end;

function TSphere.Intersect;

var
  OC : Point;
  L2_OC,
  Tca,
  T2_HC,
  t_hc,
  t0,
  t1    : Flt;
  roots : word;

begin

  {$IFDEF Debug}
     Printvec('Intersecting Sphere: ',center);
     Writeln(con,'             radius: ',rad:3:3);
     writeln(con);
  {$ENDIF}

  roots := 0;

  stats.sphintersects := stats.sphintersects + 1;

  VecSub(Center, Ray.P, OC);
  L2_OC := VecDot(OC, OC);
  Tca := VecDot(OC, Ray.D);
  T2_HC := rad2-L2_OC+sqr(Tca);

  if T2_HC<=0.0 then begin intersect := 0; exit; end;

  t_hc := sqrt(t2_hc);          { Optimization }

  t1 := tca+t_hc;
  if t1>rayeps then
  begin
    Hitlist^.Add(New(PHititem,Init(t1,0,@self)));
    {$IFDEF Debug}
      writeln(con, 'Found intersection t1 ',t1:7:3); writeln(con);
    {$ENDIF Debug}
    inc(roots);
  end;

  t0 := tca-t_hc;
  if t0>rayeps then
  begin
    Hitlist^.Add(New(PHititem,Init(t0,0,@self)));  { Add the smallest last!}
    {$IFDEF Debug}
       writeln(con, 'Found intersection t0 ',t0:7:3); writeln(con);
    {$ENDIF}
    inc(roots);
    stats.sphintersectssucceeded := stats.sphintersectssucceeded + 1;
  end;

  intersect:=roots;
end;

procedure TSphere.Normal;    { Compute Normal N given Point P }

begin
  VecSub(P, Center, N);
  VecUnit(N);
end;

destructor TSphere.Done;

begin
end;

end.
