unit particles;

interface

uses constants, OpenGL, variables, records;

type
  RParticle = record
    x, y, z, sz, ez : single;
    speed, length : single;
  end;

  TParticles = class
    active, fade_out, fade_in : boolean;
    x, y, start_z, end_z : single;
    color : RColor;
    total_speed : single;
    r, total_particles, need_particles : integer;
    fade_out_speed, fade_in_speed : single;
    width : single;
    v : array[1..max_particles] of RParticle;
  public
    procedure ResetParticle(n : integer; change_position : boolean);
    procedure SetNumberParticles(n : integer);
    constructor Create(px, py, pstart_z, pend_z : single; pr, n : integer);
    procedure Move;
    procedure Redraw;
  end;

var rain : TParticles;

implementation

procedure TParticles.ResetParticle(n : integer; change_position : boolean);
begin
v[n].sz := start_z;
v[n].ez := end_z;   
v[n].x := x + random(r) - random(r);
v[n].y := y + random(r) - random(r);
v[n].z := v[n].sz;
v[n].speed := -(random(3) + 5) * total_speed;
v[n].length := random(20) + 30;
end;

procedure TParticles.SetNumberParticles(n : integer);
var
i : integer;
begin
if n > max_particles then n := max_particles;
need_particles := n;
for i := 1 to need_particles do ResetParticle(i, true);
end;

constructor TParticles.Create(px, py, pstart_z, pend_z : single; pr, n : integer);
begin
x := px; y := py; start_z := pstart_z; end_z := pend_z; r := pr;

with color do begin r := 0.5; g := 0.6; b := 1; a := 0.3; end;
total_speed := 0.029; width := 3;

SetNumberParticles(n);
total_particles := 0;
end;

procedure TParticles.Move;
var
i : integer;
begin
if fade_in then active := true;
if not active then exit;

if fade_in then total_particles := total_particles + round(fade_in_speed * count_time);
if fade_out then total_particles := total_particles - round(fade_out_speed * count_time);
if total_particles < 0 then
  begin total_particles := 0; fade_out := false; active := false; end;
if total_particles > need_particles then
  begin total_particles := need_particles; fade_in := false; end;

for i := 1 to total_particles do
  with v[i] do
    begin
      z := z + speed * count_time;
      if z < end_z then ResetParticle(i, false);
    end;
end;

procedure TParticles.Redraw;
var
i : integer;
alpha : single;
begin
if not active then exit;

glDisable(GL_TEXTURE_2D);

glLineWidth(width);
glBegin(GL_LINES);

for i := 1 to total_particles do
  with v[i] do with color do
    begin
      alpha := a - sqr(fog_destination_density * (y - eye_pos_y) +
                       fog_height_density * abs(eye_pos_z - z));
      if alpha > 0 then
        begin
          glColor4f(r, g, b, alpha - 0.15);
          glVertex3f(x, y, z);
          glColor4f(r, g, b, alpha);
          glVertex3f(x, y, z - length);
        end;
    end;
glEnd;
end;

end.
