//
//오픈캡쳐(OpenCapture)에서 사용하는 소스, 약간수정 하거나 함수 한곳으로 추가,
//델파이7에서 주석(유니코드 인코딩?)들이 깨져 나옴. 편집기 사용불가로 원 소스의 깨진 주석들 제거
//G32_Interface 도 주석 일부 제거. 델7에서 치명적 오류 발생
//라이센스는 "심플스 라이센스"

unit OpenDrawShape;

interface

uses Windows, Graphics, Types, SysUtils, GR32, GR32_Polygons, G32_Interface;

procedure AlphaBlend(DstBitmap32, SrcBitmap32: TBitmap32;
                     OldPt, nPt: TPoint;
                     Alpha: Byte);

procedure open_Line(Bitmap32: TBitmap32;
                    OldPt, nPt: TPoint;
                    Alpha: Byte;
                    Antialiased: Boolean);

procedure open_Rectangle(Bitmap32 :TBitmap32;
                        OldPt, nPt: TPoint;
                        Antialiased :Boolean;
                        Alpha: Byte;
                        BackBuffer32: TBitmap32 = nil);

procedure open_Ellipse(Bitmap32 :TBitmap32;
                       OldPt, nPt: TPoint;
                       Antialiased :Boolean;
                       Alpha: Byte;
                       BackBuffer32: TBitmap32 = nil);

procedure open_RoundRectangle(Bitmap32 :TBitmap32;
                              OldPt, nPt: TPoint;
                              Antialiased :Boolean;
                              Alpha: Byte;
                              BackBuffer32: TBitmap32 = nil);

procedure open_Arrow(Bitmap32: TBitmap32;
                     OldPt, nPt: TPoint;
                     Alpha: Byte;
                     Antialiased: Boolean);

implementation

uses Math;

procedure NormalizePoint(var FirstPt, EndPt: TPoint);
var
  Pt, Pt1: TPoint;
begin

  if FirstPt.X - EndPt.X > 0 then
  begin
    Pt.X := FirstPt.X;
    Pt1.X := EndPt.X;
    FirstPt.X := Pt1.X;
    EndPt.X := Pt.X;
  end;

  if FirstPt.Y - EndPt.Y > 0 then
  begin
    Pt.Y := FirstPt.Y;
    Pt1.Y := EndPt.Y;
    FirstPt.Y := Pt1.Y;
    EndPt.Y := Pt.Y;
  end;

end;

procedure MinMaxInteger(Const Min, Max: Integer; var AInteger: Integer);
begin
  if AInteger < Min then
    AInteger := 0;
  if AInteger > Max then
    AInteger := Max;
end;

procedure MinMaxRect(Const MinX, MaxX, MinY, MaxY: Integer; var lpRect: TRect);
begin
  MinMaxInteger(MinX, MaxX, lpRect.Left);
  MinMaxInteger(MinY, MaxY, lpRect.Top);
  MinMaxInteger(MinX, MaxX, lpRect.Right);
  MinMaxInteger(MinY, MaxY, lpRect.Bottom);
end;

procedure AlphaBlend(DstBitmap32, SrcBitmap32: TBitmap32;
                     OldPt, nPt: TPoint;
                     Alpha: Byte);
var
 Margin: Integer;
 DstRect: TRect;
begin
  if Alpha = 255 then
   Exit;

  NormalizePoint(OldPt, nPt);

  Margin := DstBitmap32.Canvas.Pen.Width;

  DstRect := Rect(OldPt.X - Margin, OldPt.Y - Margin,
                  nPt.X + Margin, nPt.Y + Margin);

  SrcBitmap32.DrawMode := dmBlend;
  SrcBitmap32.MasterAlpha := 255 - Alpha;

  MinMaxRect(0, DstBitmap32.Width, 0 , DstBitmap32.Height, DstRect);

  SrcBitmap32.DrawTo(DstBitmap32, DstRect, DstRect);
  SrcBitmap32.DrawMode := dmOpaque;
end;

function EqualPoint(Const Pt, Pt1: TPoint): Boolean;
begin
  Result := (Pt.X = Pt1.X) and (Pt.Y = Pt1.Y);
end;

procedure open_Line(Bitmap32: TBitmap32;
                    OldPt, nPt: TPoint;
                    Alpha: Byte;
                    Antialiased: Boolean);
var
 SrcPolygon, DstPolygon, TmpPolygon: TPolygon32;
 LineSize: Integer;
 LineColor: TColor32;
begin
 if EqualPoint(OldPt, nPt) = True then Exit;

 LineSize := Bitmap32.Canvas.Pen.Width;
 LineColor := SetAlpha(Color32(Bitmap32.Canvas.Pen.Color), Alpha);

 if LineSize = 1 then begin
  Bitmap32.LineFS(OldPt.X, OldPt.Y, nPt.X, nPt.Y, LineColor);
  
  Exit;
 end;

 TmpPolygon := TPolygon32.Create;
 DstPolygon := nil;
 SrcPolygon := nil;

 try
  TmpPolygon.Add(FixedPoint(OldPt));
  TmpPolygon.Add(FixedPoint(nPt));

  SrcPolygon := TmpPolygon.Outline;

  DstPolygon := SrcPolygon.Grow(Fixed(LineSize / 2), 0.5);

  DstPolygon.FillMode := pfWinding;

  if Antialiased = True then begin
   DstPolygon.AntialiasMode := am16times;
   DstPolygon.Antialiased := True;
  end;

  DstPolygon.DrawFill(Bitmap32, LineColor);

 finally
  TmpPolygon.Free;
  if SrcPolygon <> nil then
   SrcPolygon.Free;
  if DstPolygon <> nil then
   DstPolygon.Free;
 end;

end;

procedure open_Rectangle(Bitmap32 :TBitmap32;
                        OldPt, nPt: TPoint;
                        Antialiased :Boolean;
                        Alpha: Byte;
                        BackBuffer32: TBitmap32 = nil);
var
 DstPolygon, SrcPolygon, TmpPolygon :TPolygon32;
 LineSize: Integer;
 LineColor, BrushColor: TColor32;
 xPenData :TPen32Data;
 xBrushData :TBrush32Data;
begin
 if EqualPoint(OldPt, nPt) = True then Exit;

 LineSize := Bitmap32.Canvas.Pen.Width;

 DstPolygon := nil;
 SrcPolygon := nil;
 TmpPolygon := nil;

 TmpPolygon := TPolygon32.Create;
  try

   with TmpPolygon do begin
    Add(FixedPoint(OldPt));
    Add(FixedPoint(nPt.X, OldPt.Y));
    Add(FixedPoint(nPt));
    Add(FixedPoint(OldPt.X, nPt.Y));
   end;

   if Bitmap32.Canvas.Brush.Style = bsSolid then begin
    BrushColor := Color32(Bitmap32.Canvas.Brush.Color);

    TmpPolygon.Antialiased := Antialiased;
    TmpPolygon.FillMode := pfWinding;
    TmpPolygon.DrawFill(Bitmap32, BrushColor);
   end;

   if LineSize > 1 then begin
    SrcPolygon := TmpPolygon.Outline;
    DstPolygon := SrcPolygon.Grow(Fixed(LineSize / 2), 0.5);
    end else DstPolygon := TmpPolygon.Outline;

   if Bitmap32.Canvas.Pen.Style = psSolid then begin
    LineColor := Color32(Bitmap32.Canvas.Pen.Color);

    DstPolygon.Antialiased := Antialiased;
    DstPolygon.FillMode := pfWinding;

    if LineSize > 1 then
     DstPolygon.DrawFill(Bitmap32, LineColor)
      else
       DstPolygon.DrawEdge(Bitmap32, LineColor);
   end;

  finally
   if TmpPolygon <> nil then
    TmpPolygon.Free;
   if SrcPolygon <> nil then
    SrcPolygon.Free;
   if DstPolygon <> nil then
    DstPolygon.Free;
  end;

//  AlphaBlend(Bitmap32, BackBuffer32, OldPt, nPt, Alpha);

end;

procedure open_Ellipse(Bitmap32 :TBitmap32;
                       OldPt, nPt: TPoint;
                       Antialiased :Boolean;
                       Alpha: Byte;
                       BackBuffer32: TBitmap32 = nil);
var
 xPenData: TPen32Data;
 xBrushData: TBrush32Data;
begin
 if EqualPoint(OldPt, nPt) = True then Exit;

 xPenData.Style := gr_psSolid;
 xPenData.EdgeSharpness := 0.5;

 xBrushData.Bitmap := nil;

 if Bitmap32.Canvas.Pen.Style = psClear then begin
  xPenData.Width := Fixed(0);
  xPenData.Color := Color32(Bitmap32.Canvas.Brush.Color);
  end else begin
            xPenData.Color := Color32(Bitmap32.Canvas.Pen.Color);
            xPenData.Width := Fixed((Bitmap32.Canvas.Pen.Width / 2));
           end;

  xBrushData.Color := Color32(Bitmap32.Canvas.Brush.Color);

  if Bitmap32.Canvas.Brush.Style = bsSolid then
   xBrushData.Style := gr_bsSolid
    else xBrushData.Style := gr_bsClear;

  gEllipse_Styled(Bitmap32,
                  FixedRect(Fixed(OldPt.X),Fixed(OldPt.Y),
                            Fixed(nPt.X),Fixed(nPt.Y)),
                  xPenData,xBrushData,Antialiased);

//  AlphaBlend(Bitmap32, BackBuffer32, OldPt, nPt, Alpha);

end;


procedure open_RoundRectangle(Bitmap32 :TBitmap32;
                              OldPt, nPt: TPoint;
                              Antialiased :Boolean;
                              Alpha: Byte;
                              BackBuffer32: TBitmap32 = nil);
Const
 Margin = 2;
var
 PP :TArrayOfFixedPoint;
 dR, xR :GR32.TFixed;
 MinX, MinY, MinR :Integer;
 xRect :TFixedRect;
 xPenData: TPen32Data;
 xBrushData: TBrush32Data;
 A:Integer;
begin
 if EqualPoint(OldPt, nPt) = True then Exit;

 NormalizePoint(OldPt, nPt);

 if EqualPoint(OldPt, nPt) or
    (Margin > nPt.X - OldPt.X) or
    (Margin > nPt.Y - OldPt.Y) then Exit;

 MinX := 0;
 MinY := 0;
 MinR := 0;

 MinX := nPt.X - OldPt.X;
 MinY := nPt.Y - OldPt.Y;

 MinR := Min(MInX, MinY);

 xr := Fixed(MinR) div 2;


 dR := Round(G32_Interface.EllipseToCurveCoeff_2inv * 0);

 SetLength(PP, 22);

 xRect := FixedRect(Fixed(OldPt.X), Fixed(OldPt.Y), Fixed(nPt.X), Fixed(nPt.Y));

 PP[0].x := xRect.Right - xR;    PP[0].y := xRect.Top;
 PP[1].x := xRect.Right - dR;    PP[1].y := xRect.Top;
 PP[2].x := xRect.Right;         PP[2].y := xRect.Top + dR;
 PP[3].x := xRect.Right;         PP[3].y := xRect.Top + xR;
 PP[4].x := xRect.Right;         PP[4].y := pp[3].y;

 PP[5].x := xRect.Right;         PP[5].y := xRect.Bottom  - xR;
 PP[6].x := xRect.Right;         PP[6].y := PP[5].y;
 PP[7].x := xRect.Right;         PP[7].y := xRect.Bottom  - dR;
 PP[8].x := PP[1].x;             PP[8].y := xRect.Bottom;
 PP[9].x := PP[0].x;             PP[9].y := xRect.Bottom;
 PP[10].x := PP[0].x;            PP[10].y := xRect.Bottom;

 PP[11].x := xRect.Left + xR;  PP[11].y := xRect.Bottom;
 PP[12].x := PP[11].x;         PP[12].y := xRect.Bottom;
 PP[13].x := xRect.Left + dR;  PP[13].y := xRect.Bottom;
 PP[14].x := xRect.Left;       PP[14].y := PP[7].y;
 PP[15].x := xRect.Left;       PP[15].y := PP[5].y;
 PP[16].x := xRect.Left;       PP[16].y := PP[5].y;

 PP[17].x := xRect.Left;       PP[17].y := PP[3].y;
 PP[18].x := xRect.Left;       PP[18].y := PP[3].y;
 PP[19].x := xRect.Left;       PP[19].y := PP[2].y;
 PP[20].x := PP[13].x;         PP[20].y := xRect.Top;
 PP[21].x := PP[11].x;         PP[21].y := xRect.Top;

 xPenData.Style := gr_psSolid;
 xPenData.EdgeSharpness := 0.5;

 xBrushData.Bitmap := nil;

 if Bitmap32.Canvas.Pen.Style = psClear then begin
  xPenData.Width := Fixed(0);
  xPenData.Color := Color32(Bitmap32.Canvas.Brush.Color);
  end else begin
            xPenData.Color := Color32(Bitmap32.Canvas.Pen.Color);
            xPenData.Width := Fixed((Bitmap32.Canvas.Pen.Width / 2));
           end;

 xBrushData.Color := Color32(Bitmap32.Canvas.Brush.Color);

 if BItmap32.Canvas.Brush.Style = bsSolid then
  xBrushData.Style := gr_bsSolid
   else xBrushData.Style := gr_bsClear;

 gPolyBezier_Styled(Bitmap32, PP, True, xPenData, xBrushData,
                    Antialiased);

 PP := nil;

// AlphaBlend(Bitmap32, BackBuffer32, OldPt, nPt, Alpha);

end;

procedure open_Arrow(Bitmap32: TBitmap32;
                     OldPt, nPt: TPoint;
                     Alpha: Byte;
                     Antialiased: Boolean);
var
 SrcPolygon, DstPolygon, TmpPolygon: TPolygon32;
 LineSize: Integer;
 LineColor: TColor32;
 a, b :Single;
 d :Single;
 sine, cosine :Extended;
 ArrowPt1, ArrowPt2, ArrowPt3 :TPoint;
begin
 if EqualPoint(OldPt, nPt) = True then Exit;

 LineSize := Bitmap32.Canvas.Pen.Width;
 LineColor := Color32(Bitmap32.Canvas.Pen.Color);

 a := 15 + (LineSize * 2);
 b := 10 + (LineSize * 2);

 SinCos(ArcTan2(nPt.y-OldPt.Y, nPt.x-OldPt.X), sine, cosine);
 d := Sqrt(sqr(nPt.x-OldPt.X) + sqr(nPt.y-OldPt.Y));

 ArrowPt1.X := Round((d-a) * cosine - (b/2) * sine) + OldPt.X;
 ArrowPt1.Y := Round((d-a) * sine + (b/2) * cosine) + OldPt.Y;

 ArrowPt2.X := Round((d-a) * cosine + (b/2) * sine) + OldPt.X;
 ArrowPt2.Y := Round((d-a) * sine - (b/2) * cosine) + OldPt.Y;

 ArrowPt3 := nPt;

 //a := a - 1;
 b := 0;
 nPt.X := Round((d-a) * cosine - (b/2) * sine) + OldPt.X;
 nPt.Y := Round((d-a) * sine + (b/2) * cosine) + OldPt.Y;

 TmpPolygon := nil;
 DstPolygon := nil;
 SrcPolygon := nil;

 try

  if LineSize > 1 then begin
   TmpPolygon := TPolygon32.Create;

   TmpPolygon.Add(FixedPoint(OldPt));
   TmpPolygon.Add(FixedPoint(nPt));

   SrcPolygon := TmpPolygon.Outline;

   DstPolygon := SrcPolygon.Grow(Fixed(LineSize / 2), 0.5);

   DstPolygon.FillMode := pfWinding;
  end else begin
            DstPolygon := TPolygon32.Create;

            Bitmap32.LineFS(OldPt.X, OldPt.Y, nPt.X, nPt.Y,
                           SetAlpha(LineColor, Alpha));

            Bitmap32.PixelFS[nPt.X, nPt.Y] := SetAlpha(LineColor, Alpha);

           end;

  if d < 15 + (LineSize * 2) then
   DstPolygon.Clear;

  DstPolygon.Add(FixedPoint(nPt));
  DstPolygon.Add(FixedPoint(ArrowPt1));
  DstPolygon.Add(FixedPoint(ArrowPt3));
  DstPolygon.Add(FixedPoint(ArrowPt2));

  if Antialiased = True then begin
   DstPolygon.AntialiasMode := am16times;
   DstPolygon.Antialiased := True;
  end;

  DstPolygon.DrawFill(Bitmap32, SetAlpha(LineColor, Alpha));

 finally
  if TmpPolygon <> nil then
   TmpPolygon.Free;
  if SrcPolygon <> nil then
   SrcPolygon.Free;
  if DstPolygon <> nil then
   DstPolygon.Free;
 end;

end;


end.
