unit uAdd;

//  Данный модуль - солянка различных полезных, чаще всего математических
//  функций, которые упрощают работу с zenGL
//  Кое-что моего авторства, кое-что взято из примеров Andru.
//  Большой блок адаптирован из кода VisualDoj'а
//

interface

uses zglHeader,
     uVar;

Const
  EPS = 10e-5;

type
  TORect = record
    vert : array [0..3] of zglTpoint2d;
  end;

function r(x, y, w, h : single) : zglTRect; inline;
function c(x, y, r : single) : zglTCircle; inline;
function pt(x, y : single) : zglTPoint2d; inline;

function CalcX2D( const X : Single ) : Single; inline;
function CalcY2D( const Y : Single ) : Single; inline;

function CvsC(c1, c2 : zglTCircle): boolean;

function oRect(pos : zglTPoint2d; width, height, angle : single) : TORect;
Function ColORectVsORect(A, B: TORect): Boolean;
procedure DrawORect(ORect : TORect);

procedure Blur(tex : zglPTexture; passes : byte);

implementation

Function Less(v1, v2 : real) : boolean; inline;
begin
  result := true;
  if (v1 >= v2) then result := false;
end;

function r(x, y, w, h : single) : zglTRect; inline;
begin
  result.X := x;
  result.Y := y;
  result.W := w;
  result.H := h;
end;

function c(x, y, r : single) : zglTCircle; inline;
begin
  result.cX := x;
  result.cY := y;
  result.Radius := r;
end;

function pt(x, y : single) : zglTPoint2d; inline;
begin
  result.X := x;
  result.Y := y;
end;

function CalcX2D( const X : Single ) : Single; inline;
begin
  Result := ( X - SCREEN_WIDTH / 2 ) * ( 1 / SCREEN_WIDTH / 2 );
end;

function CalcY2D( const Y : Single ) : Single; inline;
begin
  Result := ( Y - SCREEN_HEIGHT / 2 ) * ( 1 / SCREEN_HEIGHT / 2 );
end;

function CvsC(c1, c2 : zglTCircle): boolean;
var d : single;
begin
  result := false;
  d := m_Distance(c1.cX, c1.cY, c2.cX, c2.cY);
  if d <= (c1.Radius + c2.Radius) then result := true;
end;

// Этот код позаимствован у VisulaDoj'а и адаптирован чуток под zen

Function QLen2D(V: zglTPoint2d): Double;
begin
  Result := Sqr(V.X) + Sqr(V.Y);
end;

Function Len2D(V: zglTPoint2D): Double;
begin
  Result := Sqrt(QLen2D(V));
end;

Function Mul2D(V: zglTPoint2d; D: Double): zglTPoint2d;
begin
  Result.X := V.X * D;
  Result.Y := V.Y * D;
end;

Function Norm2D(V: zglTPoint2d): zglTPoint2d;
  Var
    L: Double;
begin
  L := Len2D(V);
    If L < EPS then
      Result := pt(0, 0)
    else
      Result := Mul2D(V, 1/L);
end;

Procedure CalcABC(V1, V2: zglTPoint2d; Var A, B, C: Single);
  Var
    N: zglTPoint2d;
begin
  // 1. Вычисляем вектор, перпендикулярный прямой
  N := pt(V1.Y - V2.Y, V2.X - V1.X);
  // 2. Нормализуем его
  N := Norm2D(N);
  // 3. Записываем результат и вычисляем C по формуле C = - A*X - B*Y
  A := N.X;
  B := N.Y;
  C := - V1.X*A - V1.Y*B;
end;

Function GetDistToLine(X: zglTPoint2d; S, F: zglTPoint2d): Single;
  Var
    A, B, C: Single;
begin
  CalcABC(S, F, A, B, C);
  Result := A*X.X + B*X.Y + C;
end;

Function ClassifyORect(S, F: zglTPoint2d; ORect: TORect): Integer;
  Var
    I: Integer;
    InFront: Boolean;
    InBack: Boolean;
    D: Single;
begin
  InFront := False;
  InBack := False;
    For I := 0 to 3 do begin
      D := GetDistToLine(ORect.vert[I], S, F);
        If D > EPS then
          InFront := True;
        If D < -EPS then
          InBack := True;
    end;
    If InFront And InBack then
      Result := 0
    else
    If InFront then
      Result := 1
    else
      Result := -1;
end;

function oRect(pos : zglTPoint2d; width, height, angle : single) : TORect;
var i: integer;
begin
  Result.vert[0] := pt( Width/2,  Height/2);
  Result.vert[1] := pt(-Width/2,  Height/2);
  Result.vert[2] := pt(-Width/2, -Height/2);
  Result.vert[3] := pt( Width/2, -Height/2);
  For I := 0 to 3 do
      begin
        Result.vert[I] := pt(Result.vert[I].X * m_Cos(round(Angle)) - Result.vert[I].Y * m_Sin(round(Angle)),
                                Result.vert[I].X * m_Sin(round(Angle)) + Result.vert[I].Y * m_Cos(round(Angle)));
        Result.vert[I].X := result.vert[i].X + pos.X;
        Result.vert[I].Y := result.vert[i].Y + pos.Y;
      end;
end;

Function ColORectVsORect(A, B: TORect): Boolean;
  Var
    I: Integer;
begin
  Result := True;
    For I := 0 to 3 do
      If ClassifyORect(A.vert[I], A.vert[(I + 1) mod 4], A)*
         ClassifyORect(A.vert[I], A.vert[(I + 1) mod 4], B) < 0 then
        Result := False;
    For I := 0 to 3 do
      If ClassifyORect(B.vert[I], B.vert[(I + 1) mod 4], A)*
         ClassifyORect(B.vert[I], B.vert[(I + 1) mod 4], B) < 0 then
        Result := False;
end;

procedure DrawORect(ORect : TORect);
begin
  pr2d_Line(ORect.vert[0].X,
            ORect.vert[0].Y,
            ORect.vert[1].X,
            ORect.vert[1].Y);
  pr2d_Line(ORect.vert[2].X,
            ORect.vert[2].Y,
            ORect.vert[1].X,
            ORect.vert[1].Y);
  pr2d_Line(ORect.vert[2].X,
            ORect.vert[2].Y,
            ORect.vert[3].X,
            ORect.vert[3].Y);
  pr2d_Line(ORect.vert[0].X,
            ORect.vert[0].Y,
            ORect.vert[3].X,
            ORect.vert[3].Y);
end;

/////////// VD end =)

procedure Blur(tex : zglPTexture; passes : byte);
var texCoords : array[0..3] of zglTPoint2d;
    x, y, i   : integer;
begin
  for I := 0 to passes - 1 do
    for x := 0 to 2 do
      begin
      for y := 0 to 2 do
        begin
          texCoords[3].X := 0 + (x-0.5)/800;
          texCoords[3].Y := 0 + (y-0.5)/600;
          texCoords[2].X := 1 + (x-0.5)/800;
          texCoords[2].Y := 0 + (y-0.5)/600;
          texCoords[1].X := 1 + (x-0.5)/800;
          texCoords[1].Y := 1 + (y-0.5)/600;
          texCoords[0].X := 0 + (x-0.5)/800;
          texCoords[0].Y := 1 + (y-0.5)/600;


       //   pr2d_triList(tex, @trilist[0], @texcoords[0], 0, 3, $00ff00, 255,pr2d_fill);

          texture2d_draw(tex, texCoords, 0, -424, 1024, 1024, 0,round(255/(x + y + 3)), FX_BLEND );
        end;
      end;
end;

end.
