MainUnit.pas 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. unit MainUnit;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Vectorial Polygon Rasterizer for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Christian-W. Budde
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$I GR32.inc}
  35. uses
  36. {$IFDEF FPC}LCLIntf, {$ELSE}Windows, {$ENDIF} SysUtils, Classes, Graphics,
  37. Controls, Forms, Dialogs, GR32, GR32_Image, GR32_Polygons, GR32_Paths;
  38. type
  39. TFormBezier = class(TForm)
  40. PaintBox32: TPaintBox32;
  41. procedure FormCreate(Sender: TObject);
  42. procedure FormDestroy(Sender: TObject);
  43. procedure PaintBox32PaintBuffer(Sender: TObject);
  44. procedure PaintBox32DblClick(Sender: TObject);
  45. procedure PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
  46. Shift: TShiftState; X, Y: Integer);
  47. procedure PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
  48. Shift: TShiftState; X, Y: Integer);
  49. procedure PaintBox32MouseMove(Sender: TObject; Shift: TShiftState;
  50. X, Y: Integer);
  51. procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  52. private
  53. FRenderer: TPolygonRenderer32VPR;
  54. FCurrentIndex: Integer;
  55. FVertices: TArrayOfFloatPoint;
  56. procedure RandomizeVertices;
  57. end;
  58. var
  59. FormBezier: TFormBezier;
  60. implementation
  61. {$IFDEF FPC}
  62. {$R *.lfm}
  63. {$ELSE}
  64. {$R *.dfm}
  65. {$ENDIF}
  66. uses
  67. Math, GR32_LowLevel, GR32_VectorUtils;
  68. // TFormBezier
  69. procedure TFormBezier.FormCreate(Sender: TObject);
  70. begin
  71. FRenderer := TPolygonRenderer32VPR.Create(PaintBox32.Buffer);
  72. SetLength(FVertices, 6);
  73. RandomizeVertices;
  74. FCurrentIndex := -1;
  75. end;
  76. procedure TFormBezier.FormDestroy(Sender: TObject);
  77. begin
  78. FRenderer.Free;
  79. end;
  80. procedure TFormBezier.FormKeyDown(Sender: TObject; var Key: Word;
  81. Shift: TShiftState);
  82. begin
  83. case Key of
  84. 27:
  85. Close;
  86. 13:
  87. begin
  88. RandomizeVertices;
  89. PaintBox32.Invalidate;
  90. end;
  91. 187:
  92. begin
  93. SetLength(FVertices, Length(FVertices) + 1);
  94. with PaintBox32 do
  95. FVertices[Length(FVertices) - 1] := FloatPoint(Random * Width,
  96. Random * Height);
  97. PaintBox32.Invalidate;
  98. end;
  99. 189:
  100. if Length(FVertices) > 5 then
  101. begin
  102. SetLength(FVertices, Length(FVertices) - 1);
  103. PaintBox32.Invalidate;
  104. end;
  105. end;
  106. end;
  107. function CubicInterpolation(const Fractional: TFloat;
  108. const Data0, Data1, Data2, Data3: TFloat): TFloat;
  109. begin
  110. Result := Data1 + 0.5 * Fractional *
  111. (Data2 - Data0 + Fractional * (4 * Data2 + 2 * Data0 - 5 * Data1 - Data3 +
  112. Fractional * (3 * (Data1 - Data2) - Data0 + Data3)));
  113. end;
  114. procedure TFormBezier.RandomizeVertices;
  115. var
  116. Index: Integer;
  117. begin
  118. with PaintBox32 do
  119. for Index := 0 to High(FVertices) do
  120. FVertices[Index] := FloatPoint(Random * Width, Random * Height);
  121. end;
  122. procedure TFormBezier.PaintBox32DblClick(Sender: TObject);
  123. begin
  124. RandomizeVertices;
  125. PaintBox32.Invalidate;
  126. end;
  127. procedure TFormBezier.PaintBox32MouseDown(Sender: TObject; Button: TMouseButton;
  128. Shift: TShiftState; X, Y: Integer);
  129. var
  130. Index: Integer;
  131. Dist, MinDist: TFloat;
  132. MinDistIndex: Integer;
  133. begin
  134. FCurrentIndex := -1;
  135. for Index := 0 to Length(FVertices) - 1 do
  136. if Sqr(FVertices[Index].X - X) + Sqr(FVertices[Index].Y - Y) < 25 then
  137. begin
  138. if (Length(FVertices) > 5) and (Button = mbRight) then
  139. begin
  140. if Index < Length(FVertices) - 1 then
  141. Move(FVertices[Index + 1], FVertices[Index],
  142. (Length(FVertices) - Index - 1) * SizeOf(TFloatPoint));
  143. SetLength(FVertices, Length(FVertices) - 1);
  144. PaintBox32.Invalidate;
  145. end
  146. else
  147. FCurrentIndex := Index;
  148. Exit;
  149. end;
  150. if Button = mbLeft then
  151. begin
  152. MinDistIndex := 0;
  153. MinDist := Sqr(X - FVertices[0].X) + Sqr(Y - FVertices[0].Y);
  154. for Index := 1 to High(FVertices) do
  155. begin
  156. Dist := Sqr(X - FVertices[Index].X) + Sqr(Y - FVertices[Index].Y);
  157. if Dist < MinDist then
  158. begin
  159. MinDistIndex := Index;
  160. MinDist := Dist;
  161. end;
  162. end;
  163. SetLength(FVertices, Length(FVertices) + 1);
  164. Move(FVertices[MinDistIndex], FVertices[MinDistIndex + 1],
  165. (Length(FVertices) - MinDistIndex) * SizeOf(TFloatPoint));
  166. FCurrentIndex := MinDistIndex;
  167. FVertices[FCurrentIndex] := FloatPoint(X, Y);
  168. PaintBox32.Invalidate;
  169. end;
  170. end;
  171. procedure TFormBezier.PaintBox32MouseMove(Sender: TObject; Shift: TShiftState;
  172. X, Y: Integer);
  173. begin
  174. if FCurrentIndex >= 0 then
  175. begin
  176. FVertices[FCurrentIndex] := FloatPoint(X, Y);
  177. PaintBox32.Invalidate;
  178. end;
  179. end;
  180. procedure TFormBezier.PaintBox32MouseUp(Sender: TObject; Button: TMouseButton;
  181. Shift: TShiftState; X, Y: Integer);
  182. begin
  183. if FCurrentIndex >= 0 then
  184. with PaintBox32 do
  185. begin
  186. FVertices[FCurrentIndex].X := EnsureRange(FVertices[FCurrentIndex].X,
  187. 0, Width);
  188. FVertices[FCurrentIndex].Y := EnsureRange(FVertices[FCurrentIndex].Y,
  189. 0, Height);
  190. end;
  191. FCurrentIndex := -1;
  192. PaintBox32.Invalidate;
  193. end;
  194. procedure TFormBezier.PaintBox32PaintBuffer(Sender: TObject);
  195. var
  196. Index: Integer;
  197. Val: Double;
  198. Fractional: Double;
  199. Indices: array [0 .. 3] of Integer;
  200. PolyCount: Integer;
  201. Outline: TArrayOfArrayOfFloatPoint;
  202. const
  203. CVertexCountStep = 64;
  204. begin
  205. PaintBox32.Buffer.Clear($FFFFFFFF);
  206. Outline := BuildPolyPolyLine(PolyPolygon(FVertices), True, 2);
  207. PolyCount := Length(Outline);
  208. SetLength(Outline, PolyCount + Length(FVertices));
  209. for Index := 0 to Length(FVertices) - 1 do
  210. Outline[PolyCount + Index] := Circle(FVertices[Index].X,
  211. FVertices[Index].Y, 5, 32);
  212. FRenderer.Color := $80000080;
  213. FRenderer.PolyPolygonFS(Outline);
  214. SetLength(Outline, 1, CVertexCountStep);
  215. Outline[0, 0] := FVertices[0];
  216. Index := 0;
  217. Val := 0;
  218. while Val < Length(FVertices) do
  219. begin
  220. Indices[0] := (Length(FVertices) + Trunc(Val) - 2 + 1)
  221. mod Length(FVertices);
  222. Indices[1] := (Indices[0] + 1) mod Length(FVertices);
  223. Indices[2] := (Indices[1] + 1) mod Length(FVertices);
  224. Indices[3] := (Indices[2] + 1) mod Length(FVertices);
  225. Fractional := Frac(Val);
  226. Inc(Index);
  227. if Index = Length(Outline[0]) then
  228. SetLength(Outline[0], Length(Outline[0]) + CVertexCountStep);
  229. Outline[0, Index] := FloatPoint(CubicInterpolation(Fractional,
  230. FVertices[Indices[0]].X, FVertices[Indices[1]].X, FVertices[Indices[2]].X,
  231. FVertices[Indices[3]].X), CubicInterpolation(Fractional,
  232. FVertices[Indices[0]].Y, FVertices[Indices[1]].Y, FVertices[Indices[2]].Y,
  233. FVertices[Indices[3]].Y));
  234. Val := Val + 0.03;
  235. end;
  236. SetLength(Outline[0], Index + 1);
  237. FRenderer.Color := $FF000000;
  238. FRenderer.PolyPolygonFS(BuildPolyPolyLine(Outline, True, 2));
  239. end;
  240. end.