//------------------------------------------------------------------------------
//
//  Portal Adventure - 2nd PGD Challenge: The Journey
//  Copyright (C) 2012 by Jim Valavanis
//
//  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., 59 Temple Place - Suite 330, Boston, MA
//  02111-1307, USA.
//
//------------------------------------------------------------------------------
//  E-Mail: jimmyvalavanis@yahoo.gr - jvalavanis@gmail.com
//------------------------------------------------------------------------------

{$I portal.inc}

unit bz_main;

interface

uses
  d_delphi,
  m_stack,
  m_fixed;

procedure BZ_Init;

procedure BZ_Done;

procedure BZ_Clear;

procedure BZ_SetViewPoint(const viewx, viewy, viewz: fixed_t);

procedure BZ_GetViewPoint(var viewx, viewy, viewz: fixed_t);

implementation

uses
  r_intrpl;

type
  TBezierEval = class
  private
    stack: array[0..3] of double;
    flag: boolean;
  public
    constructor Create; virtual;
    procedure Clear; virtual;
    procedure Add(const x: fixed_t);
    function Calc(const t: double): fixed_t;
  end;

constructor TBezierEval.Create;
begin
  Clear;
end;

procedure TBezierEval.Clear;
begin
  flag := false;
  ZeroMemory(@stack, SizeOf(stack));
end;

procedure TBezierEval.Add(const x: fixed_t);
begin
  if not flag then
  begin
    stack[0] := x / FRACUNIT;
    stack[1] := x / FRACUNIT;
    stack[2] := x / FRACUNIT;
    stack[3] := x / FRACUNIT;
    flag := True;
  end
  else
  begin
    stack[0] := stack[1];
    stack[1] := stack[2];
    stack[2] := stack[3];
    stack[3] := x / FRACUNIT;
  end;
end;

function TBezierEval.Calc(const t: double): fixed_t;
var
  u: float;
  ret: double;
begin
  u := 1 - t;
  ret := stack[3] * u * u * u +
         stack[2] * 3 * u * u * t +
         stack[1] * 3 * u * t * t +
         stack[0] * t * t * t;
  result := Round(ret * FRACUNIT);
end;

var
  bz_viewx: TBezierEval;
  bz_viewy: TBezierEval;
  bz_viewz: TBezierEval;

procedure BZ_Init;
begin
  bz_viewx := TBezierEval.Create;
  bz_viewy := TBezierEval.Create;
  bz_viewz := TBezierEval.Create;
end;

procedure BZ_Done;
begin
  bz_viewx.Free;
  bz_viewy.Free;
  bz_viewz.Free;
end;

procedure BZ_Clear;
begin
  bz_viewx.Clear;
  bz_viewy.Clear;
  bz_viewz.Clear;
end;

procedure BZ_SetViewPoint(const viewx, viewy, viewz: fixed_t);
begin
  bz_viewx.Add(viewx);
  bz_viewy.Add(viewy);
  bz_viewz.Add(viewz);
end;

procedure BZ_GetViewPoint(var viewx, viewy, viewz: fixed_t);
var
  t: Double;
begin
  t := (ticfrac / FRACUNIT) / 4;
  
  viewx := bz_viewx.Calc(t);
  viewy := bz_viewy.Calc(t);
  viewz := bz_viewz.Calc(t);
end;

end.
