unit uStarsFon;

interface

uses  uSMath,
      uStar;

const
  DELTA_Y       = 60;
  MIN_DELTA_X   = 100;
  MAX_DELTA_X   = 300;
  MIN_DELTA_LY  = 150;
  MAX_DELTA_LY  = 250;

  STARS_SPEED_COF = 0.15;

var
  sHead : pStar = nil;
  sTail : pStar = nil;

var
  spaceRect     : rRect;
  currentSpeed  : rVec2f;

procedure GenerateFullSpace( horizontalLines: Boolean = True );
procedure DrawAllStars;
procedure UpdateAllStars( dt: Double; horizontalLines: Boolean = True );
procedure UpdateAllFrames( dt: Double );
procedure AddNewLine( horizontalLines: Boolean = True );
procedure DeleteAllStars;

implementation

uses uVar;

const
  MAX_FRAME = 6;
  FRAME_UPDATE_DT = 0.15;

var lastLineY   : Single;
    nextDeltaLY : Single;
    lastFrameUpdate : Double;

procedure GenerateFullSpace( horizontalLines: Boolean = True );
var nDY   : Single;
    nDX   : Single;
    nDLY  : Single;
    lPos  : rVec2f;
begin
  if horizontalLines then begin
    nDLY    := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
    lPos.Y  := spaceRect.Y - nDLY;
    lastLineY := lPos.Y;

    while True do begin
      if lPos.Y > spaceRect.Y + spaceRect.Height then break;

      lPos.X  := spaceRect.X;
      nDLY    := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
      while lPos.X <= spaceRect.X + spaceRect.Width do begin
        nDX := MIN_DELTA_X + ( MAX_DELTA_X - MIN_DELTA_X ) * Random;
        nDY := DELTA_Y - 2 * DELTA_Y * Random;
        lPos.X := lPos.X + nDX;
        sTail.AddToTail( Vec2f( lPos.X, lPos.Y + nDY ), Random( MAX_FRAME ), 1.0, sHead, sTail );
      end;
      lPos.Y := lPos.Y + nDLY;
    end;
    nextDeltaLY := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
  end;

  lastFrameUpdate := 0;
end;

procedure DrawAllStars;
var buf : pStar;
begin
  buf := sHead;
  while buf <> nil do begin
    buf.Draw( Star );
    buf := buf.NextStar;
  end;
end;

procedure UpdateAllStars( dt: Double; horizontalLines: Boolean = True );
var buf, del : pStar;
begin
  buf := sHead;
  while buf <> nil do begin
    buf.Update( currentSpeed, dt );
    del := buf;
    buf := buf.NextStar;
    if horizontalLines then begin
      if currentSpeed.Y < 0 then begin
        if del.Pos.Y < spaceRect.Y then del.Delete( sHead, sTail );
      end else begin
        if del.Pos.Y > spaceRect.Y + spaceRect.Height then del.Delete( sHead, sTail );
      end;
    end else begin
      if currentSpeed.X < 0 then begin
        if del.Pos.X < spaceRect.X then del.Delete( sHead, sTail );
      end else begin
        if del.Pos.X > spaceRect.X + spaceRect.Width then del.Delete( sHead, sTail );
      end;
    end;
  end;
  if horizontalLines then begin
    lastLineY := lastLineY + currentSpeed.Y * dt;
    if currentSpeed.Y < 0 then begin
      if lastLineY <= spaceRect.Y + spaceRect.Height then AddNewLine;
    end else begin
      if lastLineY >= spaceRect.Y then AddNewLine;
    end;
  end else begin
    lastLineY := lastLineY + currentSpeed.X * dt;
    if currentSpeed.X < 0 then begin
      if lastLineY <= spaceRect.X + spaceRect.Width then AddNewLine( False );
    end else begin
      if lastLineY >= spaceRect.X then AddNewLine( False );
    end;
  end;
end;

procedure UpdateAllFrames( dt: Double );
var buf : pStar;
begin
  lastFrameUpdate := lastFrameUpdate + dt;
  if lastFrameUpdate >= FRAME_UPDATE_DT then begin
    buf := sHead;
    while buf <> nil do begin
      buf.FrameUpdate( MAX_FRAME );
      buf := buf.NextStar;
    end;
    lastFrameUpdate := 0;
  end;
end;

procedure AddNewLine( horizontalLines: Boolean = True );
var nDY   : Single;
    nDX   : Single;
    nDLY  : Single;
    lPos  : rVec2f;
begin
  if horizontalLines then begin
    if currentSpeed.Y < 0 then begin
      lPos.Y  := spaceRect.Y + spaceRect.Height + nextDeltaLY;
    end else begin
      lPos.Y  := spaceRect.Y - nextDeltaLY;
    end;
    nextDeltaLY := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
    lastLineY := lPos.Y;

    lPos.X  := spaceRect.X;
    while lPos.X <= spaceRect.X + spaceRect.Width do begin
      nDX := MIN_DELTA_X + ( MAX_DELTA_X - MIN_DELTA_X ) * Random;
      nDY := DELTA_Y - 2 * DELTA_Y * Random;
      lPos.X := lPos.X + nDX;
      sTail.AddToTail( Vec2f( lPos.X, lPos.Y + nDY ), Random( MAX_FRAME ), 1.0, sHead, sTail );
    end;
    nextDeltaLY := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
  end else begin
    if currentSpeed.X < 0 then begin
      lPos.X  := spaceRect.X + spaceRect.Width + nextDeltaLY;
    end else begin
      lPos.X  := spaceRect.X - nextDeltaLY;
    end;
    nextDeltaLY := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
    lastLineY := lPos.X;

    lPos.Y  := spaceRect.Y;
    while lPos.Y <= spaceRect.Y + spaceRect.Height do begin
      nDX := MIN_DELTA_X + ( MAX_DELTA_X - MIN_DELTA_X ) * Random;
      nDY := DELTA_Y - 2 * DELTA_Y * Random;
      lPos.Y := lPos.Y + nDX;
      sTail.AddToTail( Vec2f( lPos.X + nDY, lPos.Y ), Random( MAX_FRAME ), 1.0, sHead, sTail );
    end;
    nextDeltaLY := MIN_DELTA_LY + ( MAX_DELTA_LY - MIN_DELTA_LY ) * Random;
  end;
end;

procedure DeleteAllStars;
var buf : pStar;
    del : pStar;
begin
  buf := sHead;
  while buf <> nil do begin
    del := buf;
    buf := buf.NextStar;
    Dispose( del );
  end;
end;

end.
