GuiShapes.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:18k
源码类别:

2D图形编程

开发平台:

Delphi

  1. unit GuiShapes;
  2. //---------------------------------------------------------------------------
  3. // GuiShapes.pas                                        Modified: 16-Feb-2007
  4. // Polygonal shape utility classes for Asphyre GUI foundation     Version 1.0
  5. //---------------------------------------------------------------------------
  6. // Important Notice:
  7. //
  8. // If you modify/use this code or one of its parts either in original or
  9. // modified form, you must comply with Mozilla Public License v1.1,
  10. // specifically section 3, "Distribution Obligations". Failure to do so will
  11. // result in the license breach, which will be resolved in the court.
  12. // Remember that violating author's rights is considered a serious crime in
  13. // many countries. Thank you!
  14. //
  15. // !! Please *read* Mozilla Public License 1.1 document located at:
  16. //  http://www.mozilla.org/MPL/
  17. //
  18. // If you require any clarifications about the license, feel free to contact
  19. // us or post your question on our forums at: http://www.afterwarp.net
  20. //---------------------------------------------------------------------------
  21. // The contents of this file are subject to the Mozilla Public License
  22. // Version 1.1 (the "License"); you may not use this file except in
  23. // compliance with the License. You may obtain a copy of the License at
  24. // http://www.mozilla.org/MPL/
  25. //
  26. // Software distributed under the License is distributed on an "AS IS"
  27. // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
  28. // License for the specific language governing rights and limitations
  29. // under the License.
  30. //
  31. // The Original Code is GuiShapes.pas.
  32. //
  33. // The Initial Developer of the Original Code is M. Sc. Yuriy Kotsarenko.
  34. // Portions created by M. Sc. Yuriy Kotsarenko are Copyright (C) 2007,
  35. // Afterwarp Interactive. All Rights Reserved.
  36. //---------------------------------------------------------------------------
  37. interface
  38. //---------------------------------------------------------------------------
  39. uses
  40.  Types, SysUtils, Vectors2px, AsphyreXML, AsphyreClasses;
  41. //---------------------------------------------------------------------------
  42. type
  43.  TGeometryShape = class
  44.  public
  45.   function PointInside(const Point: TPoint2px): Boolean; virtual; abstract;
  46.   function BoundingBox(): TRect; virtual; abstract;
  47.   procedure MoveBy(const Shift: TPoint2px); virtual; abstract;
  48.   procedure Rescale(const Delta: TPoint2px); virtual; abstract;
  49.   procedure LoadFromXML(Node: TXMLNode); virtual; abstract;
  50.  end;
  51. //---------------------------------------------------------------------------
  52.  TPolygonShape = class(TGeometryShape)
  53.  private
  54.   Vertices: array of TPoint2px;
  55.   function GetVertex(Num: Integer): PPoint2px;
  56.   function GetVertexCount(): Integer;
  57.  public
  58.   property VertexCount: Integer read GetVertexCount;
  59.   property Vertex[Num: Integer]: PPoint2px read GetVertex; default;
  60.   function PointInside(const Point: TPoint2px): Boolean; override;
  61.   function BoundingBox(): TRect; override;
  62.   procedure MoveBy(const Shift: TPoint2px); override;
  63.   procedure Rescale(const Delta: TPoint2px); override;
  64.   procedure LoadFromXML(Node: TXMLNode); override;
  65.   function Add(const Point: TPoint2px): Integer; overload;
  66.   function Add(x, y: Integer): Integer; overload;
  67.   procedure Remove(Num: Integer);
  68.   procedure Clear();
  69.  end;
  70. //---------------------------------------------------------------------------
  71.  TGuiShape = class
  72.  private
  73.   FName : string;
  74.   Shapes2: array of TGeometryShape;
  75.   Shapes: array of TPolygonShape;
  76.   function Insert(Shape: TGeometryShape): Integer;
  77.   function GetCount(): Integer;
  78.   function GetShape(Num: Integer): TPolygonShape;
  79.   function GetBoundingBox(): TRect;
  80.   function GetPointInside(const Point: TPoint2px): Boolean;
  81.  public
  82.   property Name: string read FName;
  83.   property Count: Integer read GetCount;
  84.   property Shape[Num: Integer]: TPolygonShape read GetShape; default;
  85.   property BoundingBox: TRect read GetBoundingBox;
  86.   property PointInside[const Point: TPoint2px]: Boolean read GetPointInside;
  87.   function Add(): TPolygonShape;
  88.   procedure AddPoly(Coords: array of Integer);
  89.   procedure Remove(Num: Integer);
  90.   procedure Clear();
  91.   procedure MakeRect(x, y, Width, Height: Integer);
  92.   procedure MoveBy(const Shift: TPoint2px); overload;
  93.   procedure MoveBy(dx, dy: Integer); overload;
  94.   procedure LoadFromXML(Node: TXMLNode);
  95.   constructor Create(const AName: string);
  96.   destructor Destroy(); override;
  97.  end;
  98. //---------------------------------------------------------------------------
  99.  TGuiShapes = class
  100.  private
  101.   List: TAsphyreList;
  102.   function GetCount(): Integer;
  103.   function GetItem(Index: Integer): TGuiShape;
  104.   procedure FreeItem(List: TAsphyreList; Item: Pointer);
  105.   function SortItem(List: TAsphyreList; Item1, Item2: Pointer): Integer;
  106.   function FindItem(List: TAsphyreList; Item, User: Pointer): Integer;
  107.   function GetShape(const Name: string): TGuiShape;
  108.  public
  109.   property Count: Integer read GetCount;
  110.   property Items[Index: Integer]: TGuiShape read GetItem; default;
  111.   property Shape[const Name: string]: TGuiShape read GetShape;
  112.   function Insert(const Name: string): TGuiShape;
  113.   function IndexOf(Shape: TGuiShape): Integer; overload;
  114.   function IndexOf(const Name: string): Integer; overload;
  115.   procedure Remove(Index: Integer);
  116.   procedure Clear();
  117.   procedure ParseLink(const Link: string);
  118.   constructor Create();
  119.   destructor Destroy(); override;
  120.  end;
  121. //---------------------------------------------------------------------------
  122. implementation
  123. //---------------------------------------------------------------------------
  124. uses
  125.  AsphyreUtils, MediaUtils;
  126. //---------------------------------------------------------------------------
  127. procedure TPolygonShape.LoadFromXML(Node: TXMLNode);
  128. var
  129.  VNode: TXMLNode;
  130.  i, Index: Integer;
  131. begin
  132.  SetLength(Vertices, ParseInt(Node.FieldValue['vertices'], 0));
  133.  for i:= 0 to Node.ChildCount - 1 do
  134.   if (LowerCase(Node.Child[i].Name) = 'vertex') then
  135.    begin
  136.     VNode:= Node.Child[i];
  137.     Index:= ParseInt(Node.FieldValue['index'], -1);
  138.     if (Index >= 0)and(Index < Length(Vertices)) then
  139.      begin
  140.       Vertices[Index].x:= ParseInt(VNode.FieldValue['x'], 0);
  141.       Vertices[Index].y:= ParseInt(VNode.FieldValue['y'], 0);
  142.      end;
  143.    end;
  144. end;
  145. //---------------------------------------------------------------------------
  146. function TPolygonShape.GetVertexCount(): Integer;
  147. begin
  148.  Result:= Length(Vertices);
  149. end;
  150. //---------------------------------------------------------------------------
  151. function TPolygonShape.GetVertex(Num: Integer): PPoint2px;
  152. begin
  153.  if (Num >= 0)and(Num < Length(Vertices)) then
  154.   Result:= @Vertices[Num] else Result:= nil;
  155. end;
  156. //---------------------------------------------------------------------------
  157. function TPolygonShape.Add(const Point: TPoint2px): Integer;
  158. var
  159.  Num: Integer;
  160. begin
  161.  Num:= Length(Vertices);
  162.  SetLength(Vertices, Num + 1);
  163.  Vertices[Num]:= Point;
  164.  Result:= Num;
  165. end;
  166. //---------------------------------------------------------------------------
  167. function TPolygonShape.Add(x, y: Integer): Integer;
  168. begin
  169.  Result:= Add(Point2px(x, y));
  170. end;
  171. //---------------------------------------------------------------------------
  172. procedure TPolygonShape.Remove(Num: Integer);
  173. var
  174.  i: Integer;
  175. begin
  176.  if (Num < 0)or(Num >= Length(Vertices)) then Exit;
  177.  for i:= Num to Length(Vertices) - 2 do
  178.   Vertices[i]:= Vertices[i + 1];
  179.  SetLength(Vertices, Length(Vertices) - 1);
  180. end;
  181. //---------------------------------------------------------------------------
  182. procedure TPolygonShape.Clear();
  183. begin
  184.  SetLength(Vertices, 0);
  185. end;
  186. //---------------------------------------------------------------------------
  187. function TPolygonShape.BoundingBox(): TRect;
  188. var
  189.  i: Integer;
  190. begin
  191.  Result.Left  := High(Integer);
  192.  Result.Right := Low(Integer);
  193.  Result.Top   := High(Integer);
  194.  Result.Bottom:= Low(Integer);
  195.  for i:= 0 to Length(Vertices) - 1 do
  196.   begin
  197.    Result.Left  := Min2(Result.Left, Vertices[i].x);
  198.    Result.Right := Max2(Result.Right, Vertices[i].x + 1);
  199.    Result.Top   := Min2(Result.Top, Vertices[i].y);
  200.    Result.Bottom:= Max2(Result.Bottom, Vertices[i].y + 1);
  201.   end;
  202. end;
  203. //---------------------------------------------------------------------------
  204. function TPolygonShape.PointInside(const Point: TPoint2px): Boolean;
  205. var
  206.  i, VertexCount: Integer;
  207.  p1, p2: PPoint2px;
  208. begin
  209.  Result:= False;
  210.  if (Length(Vertices) < 3)  then Exit;
  211.  VertexCount:= Length(Vertices);
  212.  p1:= @Vertices[0];
  213.  for i:= 0 to VertexCount - 1 do
  214.   begin
  215.    p2:= @Vertices[(i + 1) mod VertexCount];
  216.    if (Point.y > Min2(p1.y, p2.y)) then
  217.      if (Point.y <= Max2(p1.y, p2.y)) then
  218.        if (Point.x <= Max2(p1.x, p2.x)) then
  219.          if (p1.y <> p2.y) then
  220.           begin
  221.            if (p1.x = p2.x)or(Point.x <= (Point.y - p1.y) * (p2.x - p1.x) div
  222.             (p2.y - p1.y) + p1.x) then Result:= not Result;
  223.           end;
  224.    p1:= p2;
  225.   end;
  226. end;
  227. //---------------------------------------------------------------------------
  228. procedure TPolygonShape.MoveBy(const Shift: TPoint2px);
  229. var
  230.  i: Integer;
  231. begin
  232.  for i:= 0 to Length(Vertices) - 1 do
  233.   Vertices[i]:= Vertices[i] + Shift;
  234. end;
  235. //---------------------------------------------------------------------------
  236. procedure TPolygonShape.Rescale(const Delta: TPoint2px);
  237. var
  238.  i: Integer;
  239. begin
  240.  for i:= 0 to Length(Vertices) - 1 do
  241.   begin
  242.    Vertices[i].x:= iMul16(Vertices[i].x, Delta.x);
  243.    Vertices[i].y:= iMul16(Vertices[i].y, Delta.y);
  244.   end;
  245. end;
  246. //---------------------------------------------------------------------------
  247. constructor TGuiShape.Create(const AName: string);
  248. begin
  249.  inherited Create();
  250.  FName:= AName;
  251. end;
  252. //---------------------------------------------------------------------------
  253. destructor TGuiShape.Destroy();
  254. begin
  255.  Clear();
  256.  inherited;
  257. end;
  258. //---------------------------------------------------------------------------
  259. function TGuiShape.GetCount(): Integer;
  260. begin
  261.  Result:= Length(Shapes);
  262. end;
  263. //---------------------------------------------------------------------------
  264. function TGuiShape.GetShape(Num: Integer): TPolygonShape;
  265. begin
  266.  if (Num >= 0)and(Num < Length(Shapes)) then
  267.   Result:= Shapes[Num] else Result:= nil;
  268. end;
  269. //---------------------------------------------------------------------------
  270. function TGuiShape.Add(): TPolygonShape;
  271. var
  272.  Num: Integer;
  273. begin
  274.  Num:= Length(Shapes);
  275.  SetLength(Shapes, Num + 1);
  276.  Shapes[Num]:= TPolygonShape.Create();
  277.  Result:= Shapes[Num];
  278. end;
  279. //---------------------------------------------------------------------------
  280. procedure TGuiShape.Remove(Num: Integer);
  281. var
  282.  i: Integer;
  283. begin
  284.  if (Num < 0)or(Num >= Length(Shapes)) then Exit;
  285.  Shapes[Num].Free();
  286.  for i:= Num to Length(Shapes) - 2 do
  287.   Shapes[i]:= Shapes[i + 1];
  288.  SetLength(Shapes, Length(Shapes) - 1);
  289. end;
  290. //---------------------------------------------------------------------------
  291. procedure TGuiShape.Clear();
  292. var
  293.  i: Integer;
  294. begin
  295.  for i:= 0 to Length(Shapes) - 1 do
  296.   Shapes[i].Free();
  297.  SetLength(Shapes, 0); 
  298. end;
  299. //---------------------------------------------------------------------------
  300. function TGuiShape.GetBoundingBox(): TRect;
  301. var
  302.  i: Integer;
  303.  ShapeRect: TRect;
  304. begin
  305.  Result.Left  := High(Integer);
  306.  Result.Right := Low(Integer);
  307.  Result.Top   := High(Integer);
  308.  Result.Bottom:= Low(Integer);
  309.  for i:= 0 to Length(Shapes) - 1 do
  310.   begin
  311.    ShapeRect:= Shapes[i].BoundingBox;
  312.    Result.Left  := Min2(Result.Left, ShapeRect.Left);
  313.    Result.Right := Max2(Result.Right, ShapeRect.Right);
  314.    Result.Top   := Min2(Result.Top, ShapeRect.Top);
  315.    Result.Bottom:= Max2(Result.Bottom, ShapeRect.Bottom);
  316.   end;
  317. end;
  318. //---------------------------------------------------------------------------
  319. function TGuiShape.GetPointInside(const Point: TPoint2px): Boolean;
  320. var
  321.  i: Integer;
  322. begin
  323.  Result:= False;
  324.  for i:= 0 to Length(Shapes) - 1 do
  325.   begin
  326.    Result:= Result or Shapes[i].PointInside(Point);
  327.    if (Result) then Break;
  328.   end;
  329. end;
  330. //---------------------------------------------------------------------------
  331. procedure TGuiShape.MakeRect(x, y, Width, Height: Integer);
  332. var
  333.  Poly: TPolygonShape;
  334. begin
  335.  Clear();
  336.  Poly:= Add();
  337.  Poly.Add(x, y);
  338.  Poly.Add(x + Width - 1, y);
  339.  Poly.Add(x + Width - 1, y + Height - 1);
  340.  Poly.Add(x, y + Height - 1);
  341. end;
  342. //---------------------------------------------------------------------------
  343. procedure TGuiShape.MoveBy(const Shift: TPoint2px);
  344. var
  345.  i: Integer;
  346. begin
  347.  for i:= 0 to Length(Shapes) - 1 do
  348.   Shapes[i].MoveBy(Shift);
  349. end;
  350. //---------------------------------------------------------------------------
  351. procedure TGuiShape.MoveBy(dx, dy: Integer);
  352. begin
  353.  MoveBy(Point2px(dx, dy));
  354. end;
  355. //---------------------------------------------------------------------------
  356. procedure TGuiShape.AddPoly(Coords: array of Integer);
  357. var
  358.  Poly  : TPolygonShape;
  359.  Vertex: TPoint2px;
  360.  i     : Integer;
  361. begin
  362.  Poly:= Add();
  363.  Vertex:= ZeroPoint2px;
  364.  for i:= Low(Coords) to High(Coords) do
  365.   begin
  366.    if (i and $01 = $00) then
  367.     Vertex.x:= Coords[i] else Vertex.y:= Coords[i];
  368.    if (i and $01 = $01) then
  369.    Poly.Add(Vertex);
  370.   end;
  371. end;
  372. //---------------------------------------------------------------------------
  373. function TGuiShape.Insert(Shape: TGeometryShape): Integer;
  374. var
  375.  Index: Integer;
  376. begin
  377.  Index:= Length(Shapes2);
  378.  SetLength(Shapes2, Index + 1);
  379.  Shapes2[Index]:= Shape;
  380.  Result:= Index;
  381. end;
  382. //---------------------------------------------------------------------------
  383. procedure TGuiShape.LoadFromXML(Node: TXMLNode);
  384. var
  385.  i: Integer;
  386.  Shape: TGeometryShape;
  387.  Child: TXMLNode;
  388.  Move : TPoint2px;
  389.  Scale: TPoint2px;
  390. begin
  391.  FName:= Node.FieldValue['name'];
  392.  // load shapes
  393.  for i:= 0 to Node.ChildCount - 1 do
  394.   if (LowerCase(Node.Child[i].Name) = 'polygon') then
  395.    begin
  396.     Shape:= TPolygonShape.Create();
  397.     Insert(Shape);
  398.     Shape.LoadFromXML(Node.Child[i]);
  399.    end;
  400.  // -> "moveby" node
  401.  Child:= Node.ChildNode['moveby'];
  402.  if (Child <> nil) then
  403.   begin
  404.    Move.x:= ParseInt(Child.FieldValue['x'], 0);
  405.    Move.y:= ParseInt(Child.FieldValue['y'], 0);
  406.   end else Move:= ZeroPoint2px;
  407.  // -> "rescale" node
  408.  Child:= Node.ChildNode['rescale'];
  409.  if (Child <> nil) then
  410.   begin
  411.    Scale.x:= ParseInt(Child.FieldValue['x'], 65536);
  412.    Scale.y:= ParseInt(Child.FieldValue['y'], 65536);
  413.   end else Scale:= Point2px(65536, 65536);
  414.  // move and rescale shapes
  415.  for i:= 0 to Length(Shapes) - 1 do
  416.   begin
  417.    Shapes[i].MoveBy(Move);
  418.    Shapes[i].Rescale(Scale);
  419.   end;
  420. end;
  421. //---------------------------------------------------------------------------
  422. constructor TGuiShapes.Create();
  423. begin
  424.  inherited;
  425.  List:= TAsphyreList.Create();
  426.  List.OnFreeItem:= FreeItem;
  427.  List.OnSortItem:= SortItem;
  428.  List.OnFindItem:= FindItem;
  429. end;
  430. //---------------------------------------------------------------------------
  431. destructor TGuiShapes.Destroy();
  432. begin
  433.  List.Free();
  434.  inherited;
  435. end;
  436. //---------------------------------------------------------------------------
  437. procedure TGuiShapes.FreeItem(List: TAsphyreList; Item: Pointer);
  438. begin
  439.  TGuiShape(Item).Free();
  440. end;
  441. //---------------------------------------------------------------------------
  442. function TGuiShapes.SortItem(List: TAsphyreList; Item1,
  443.  Item2: Pointer): Integer;
  444. begin
  445.  Result:= CompareText(TGuiShape(Item1).Name, TGuiShape(Item2).Name);
  446. end;
  447. //---------------------------------------------------------------------------
  448. function TGuiShapes.FindItem(List: TAsphyreList; Item, User: Pointer): Integer;
  449. begin
  450.  Result:= CompareText(TGuiShape(Item).Name, PChar(User));
  451. end;
  452. //---------------------------------------------------------------------------
  453. function TGuiShapes.GetCount(): Integer;
  454. begin
  455.  Result:= List.Count;
  456. end;
  457. //---------------------------------------------------------------------------
  458. function TGuiShapes.GetItem(Index: Integer): TGuiShape;
  459. begin
  460.  Result:= TGuiShape(List[Index]);
  461. end;
  462. //---------------------------------------------------------------------------
  463. function TGuiShapes.Insert(const Name: string): TGuiShape;
  464. begin
  465.  Result:= TGuiShape.Create(Name);
  466.  List.Insert(Result);
  467. end;
  468. //---------------------------------------------------------------------------
  469. function TGuiShapes.IndexOf(Shape: TGuiShape): Integer;
  470. begin
  471.  Result:= List.IndexOf(Shape);
  472. end;
  473. //---------------------------------------------------------------------------
  474. procedure TGuiShapes.Remove(Index: Integer);
  475. begin
  476.  List.Remove(Index);
  477. end;
  478. //---------------------------------------------------------------------------
  479. procedure TGuiShapes.Clear();
  480. begin
  481.  List.Clear();
  482. end;
  483. //---------------------------------------------------------------------------
  484. function TGuiShapes.IndexOf(const Name: string): Integer;
  485. begin
  486.  Result:= List.FindBy(PChar(Name));
  487. end;
  488. //---------------------------------------------------------------------------
  489. function TGuiShapes.GetShape(const Name: string): TGuiShape;
  490. var
  491.  Index: Integer;
  492. begin
  493.  Index:= IndexOf(Name);
  494.  if (Index <> -1) then Result:= TGuiShape(List[Index]) else Result:= nil;
  495. end;
  496. //---------------------------------------------------------------------------
  497. procedure TGuiShapes.ParseLink(const Link: string);
  498. var
  499.  nName: string;
  500.  Root : TXMLNode;
  501.  sName: string;
  502.  Shape: TGuiShape;
  503.  Text : string;
  504.  i: Integer;
  505. begin
  506.  Root:= LoadLinkXML(Link);
  507.  if (Root = nil) then Exit;
  508.  if (LowerCase(Root.Name) <> 'unires')  then
  509.   begin
  510.    Root.Free();
  511.    Exit;
  512.   end;
  513.  for i:= 0 to Root.ChildCount - 1 do
  514.   begin
  515.    nName:= LowerCase(Root.Child[i].Name);
  516.    if (nName = 'shape') then
  517.     begin
  518.      sName:= LowerCase(Root.Child[i].FieldValue['name']);
  519.      if (Length(sName) > 0) then
  520.       begin
  521.        Shape:= GetShape(sName);
  522.        if (Shape = nil) then Shape:= Insert(sName);
  523.        Shape.LoadFromXML(Root.Child[i]);
  524.       end;
  525.     end;
  526.    if (nName = 'resource') then
  527.     begin
  528.      Text:= Root.Child[i].FieldValue['source'];
  529.      if (Length(Text) > 0) then ParseLink(Text);
  530.     end;
  531.   end;
  532.  Root.Free();
  533. end;
  534. //---------------------------------------------------------------------------
  535. end.