unit uzglMyPart;

{=============================================
  Particle system by the Exile
  for ZenGL v.0.1
  theExile015@gmail.com
==============================================}

interface

uses zglHeader;

const
  PM_RANDOM = 0;
  PM_FIXED  = 1;

type
  TParticle = record
    exist       : boolean;
    tex         : zglPTexture;
    x, y        : single; // текущее положение
    w, h        : single; // высота и ширина
    scale       : single; // масштаб
    ang         : single; // текущий угол
    m_x, m_y    : single; // смещение по х, у
    s_ang       : single; // вращение
    c_scale     : single; // изменение масштаба
    L_Time      : integer;// время жизни в циклах движка
    C_Time      : integer;// текущее время жизни
  end;

  TPartSample = record   // прототип партикла
    tex : zglPTexture;

   // size_type : byte;
    s_w, s_h  : single;

    sc_type   : byte;
    s_scale   : single;

    move_type : byte;
    m_speed   : single;
    dir_type  : byte;
    m_angle   : single;

    spin_type : byte;
    s_ang     : single;

    scale_type: byte;
    c_scale   : single;

    live_type : byte;
    L_Time    : integer;
  end;

  TEmitter = class
    private
      e_x, e_y      : single;

      particles : array of TParticle;
      m_part    : word;
      p_count   : integer;
      p_samp    : TPartSample;

      e_count     : integer;
      e_loop_time : integer;  // частота испускания. если = 0 то единажды
      e_counter   : integer;
      looped      : boolean;
    public
    constructor Create(MaxParticles, EmittCount, EmittTime : word);
    procedure SetPartSample(Sample : TPartSample);
    procedure SetPosition(_x, _y : single);
    procedure SetEmitParams(em_count, em_Time : word);
    function  GetPartCount: cardinal;

    procedure Draw();
    procedure Update();
  end;

{  TPartEng = class
    private

    public

  end; }

implementation

constructor TEmitter.Create(MaxParticles: Word; EmittCount: Word; EmittTime: Word);
begin
  m_part      := MaxParticles;
  e_count     := EmittCount;
  e_loop_time := EmittTime;
  setlength(particles, m_part);
end;

procedure TEmitter.SetPartSample(Sample: TPartSample);
begin
  p_samp := Sample;
end;

procedure TEmitter.SetPosition(_x: Single; _y: Single);
begin
  e_x := _x;
  e_y := _y;
end;

procedure TEmitter.SetEmitParams(em_count: Word; em_Time: Word);
begin
  e_count     := em_Count;
  e_loop_time := em_Time;
end;

function  TEmitter.GetPartCount: cardinal;
begin
  result := p_count;
end;

procedure TEmitter.Draw;
var i: integer;
begin
  for I := 0 to m_part - 1 do
    if particles[i].exist then
       with particles[i] do
         SSprite2D_draw(tex, x, y, w*scale, h*scale, ang, 255 - round(255 * C_TIME/ L_TIME));
end;

procedure TEmitter.Update;
var i, j  : integer;
    added : boolean;
begin
  if (e_counter = 0) and (not looped) then
    begin
      for j := 0 to e_count - 1 do
      begin
        added  := false;
        looped := true;
        for i := 0 to m_part - 1 do
          if (not particles[i].exist) and (not added) then
             begin
               particles[i].tex := p_samp.tex;
               particles[i].x   := e_x;
               particles[i].y   := e_y;
               particles[i].w   := p_samp.s_w;
               particles[i].h   := p_samp.s_h;
               particles[i].ang := 0;

               if p_samp.sc_type = 0 then
                  particles[i].scale := random(round(p_samp.s_scale * 1000)) / 1000
               else
                  particles[i].scale := p_samp.s_scale;

               if p_samp.move_type = 0 then
                  begin
                    if p_samp.dir_type = 0 then
                       begin
                         particles[i].m_x := random(round(p_samp.m_speed*1000)) / 1000 * m_cos(round(rad2deg*(random(round(p_samp.m_angle*1000)) / 1000)));
                         particles[i].m_y := random(round(p_samp.m_speed*1000)) / 1000 * m_sin(round(rad2deg*(random(round(p_samp.m_angle*1000)) / 1000)));
                       end
                       else
                       begin
                          particles[i].m_x := random(round(p_samp.m_speed*1000)) / 1000 * m_cos(round(rad2deg*p_samp.m_angle*1000));
                          particles[i].m_y := random(round(p_samp.m_speed*1000)) / 1000 * m_sin(round(rad2deg*p_samp.m_angle*1000));
                       end;
                  end
               else
               begin
                  if p_samp.dir_type = 1 then
                    begin
                      particles[i].m_x := p_samp.m_speed * m_cos(round(rad2deg*p_samp.m_angle));
                      particles[i].m_y := p_samp.m_speed * m_sin(round(rad2deg*p_samp.m_angle));
                    end
                    else
                    begin
                      particles[i].m_x := p_samp.m_speed * m_cos(round(rad2deg*(random(round(p_samp.m_angle*1000)) / 1000)));
                      particles[i].m_y := p_samp.m_speed * m_sin(round(rad2deg*(random(round(p_samp.m_angle*1000)) / 1000)));
                    end;
               end;

               if p_samp.spin_type = 0 then
                  particles[i].s_ang := random(round(p_samp.s_ang * 1000)) / 1000
               else
                  particles[i].s_ang := p_samp.s_ang;

               if p_samp.live_type = 0 then
                  particles[i].L_Time := random(p_samp.L_Time)
               else
                  particles[i].L_Time := p_samp.L_Time;

               particles[i].exist := true;
               particles[i].C_Time:= 0;

               added := true;
             end;
      end;
    end;

  p_count := 0;

  for i := 0 to m_part - 1 do
    if (particles[i].exist) then
    begin
      inc(p_count);
      with particles[i] do
      begin
        x    :=  x     + m_x;
        y    :=  y     + m_y;
        ang  :=  ang   + s_ang;
        scale:=  scale + c_scale;
        inc(C_Time);
        if C_Time >= L_Time then
          begin
            exist := false;
            dec(p_count);
          end;
      end;
    end;

  if e_loop_time <> 0 then
  begin
    inc(e_counter);
    looped := false;
    if e_counter >= e_loop_time then e_counter := 0;
  end;
end;

end.
