MainUnit.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  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 Image Warping Example
  23. *
  24. * The Initial Developers of the Original Code is:
  25. *
  26. * Michael Hansen <[email protected]>
  27. * Mattias Andersson <[email protected]>
  28. *
  29. * Portions created by the Initial Developer are Copyright (C) 2005
  30. * the Initial Developer. All Rights Reserved.
  31. *
  32. * Contributor(s):
  33. *
  34. *
  35. * ***** END LICENSE BLOCK ***** *)
  36. interface
  37. {$I GR32.inc}
  38. uses
  39. {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LResources, {$ENDIF}
  40. SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls,
  41. StdCtrls, ExtDlgs, Menus, ToolWin, Math, Variants, GR32, GR32_Image,
  42. GR32_Transforms, GR32_VectorMaps, GR32_Layers, GR32_Blend, GR32_RangeBars,
  43. GR32_Rasterizers, GR32_Resamplers, GR32_Math, BrushAuxiliaries;
  44. const
  45. cAppName = 'Image Warping Example';
  46. type
  47. TBrushTool = (btWarp, btZoom, btTwirl, btFlower);
  48. TBrushToolMode = (btmLeft, btmRight);
  49. TToolProc = procedure(var D, R: Single; Param: Single);
  50. TMainForm = class(TForm)
  51. BrushMeshPreview: TPaintBox32;
  52. DstImg: TImgView32;
  53. FeatherBar: TGaugeBar;
  54. LblBrush: TLabel;
  55. LblBrushFeather: TLabel;
  56. LblBrushMesh: TLabel;
  57. LblBrushPinch: TLabel;
  58. LblBrushPressure: TLabel;
  59. LblBrushSize: TLabel;
  60. LblGeneral: TLabel;
  61. LblRemapScale: TLabel;
  62. LblWaroTool: TLabel;
  63. MainMenu: TMainMenu;
  64. MnuSamplingGrid2x2: TMenuItem;
  65. MnuSamplingGrid3x3: TMenuItem;
  66. MnuSamplingGrid5x5: TMenuItem;
  67. MnuSamplingGrid7x7: TMenuItem;
  68. MnuBilinearWarp: TMenuItem;
  69. MnuFileExit: TMenuItem;
  70. MnuFile: TMenuItem;
  71. MnuKernelMode: TMenuItem;
  72. MnuKernelModeDefault: TMenuItem;
  73. MnuKernelModeTableLinear: TMenuItem;
  74. MnuKernelModeTableNearest: TMenuItem;
  75. MnuFileOpenImage: TMenuItem;
  76. MnuFileOpenMesh: TMenuItem;
  77. MnuResetMesh: TMenuItem;
  78. MnuSampling: TMenuItem;
  79. MnuSamplingGrid: TMenuItem;
  80. MnuSamplingKernel: TMenuItem;
  81. MnuFileSaveImage: TMenuItem;
  82. MnuFileSaveMesh: TMenuItem;
  83. MnuSupersampleNow: TMenuItem;
  84. N1: TMenuItem;
  85. N2: TMenuItem;
  86. N3: TMenuItem;
  87. N4: TMenuItem;
  88. OpenMeshDialog: TOpenDialog;
  89. OpenPictureDialog: TOpenPictureDialog;
  90. ParamBar: TGaugeBar;
  91. LblParam: TLabel;
  92. PinchBar: TGaugeBar;
  93. PnlBrush: TPanel;
  94. PnlGeneral: TPanel;
  95. PnlMain: TPanel;
  96. PressureBar: TGaugeBar;
  97. RateBar: TGaugeBar;
  98. RateLabel: TLabel;
  99. SaveMeshDialog: TSaveDialog;
  100. SavePictureDialog: TSavePictureDialog;
  101. ScaleBar: TGaugeBar;
  102. SizeBar: TGaugeBar;
  103. ToolGroup: TRadioGroup;
  104. ToolPanel: TPanel;
  105. UpdateTimer: TTimer;
  106. procedure FormCreate(Sender: TObject);
  107. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  108. procedure BrushMeshPreviewResize(Sender: TObject);
  109. procedure DstImgMouseDown(Sender: TObject; Button: TMouseButton;
  110. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  111. procedure DstImgMouseMove(Sender: TObject; Shift: TShiftState; X,
  112. Y: Integer; Layer: TCustomLayer);
  113. procedure DstImgMouseUp(Sender: TObject; Button: TMouseButton;
  114. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  115. procedure DstImgPaintStage(Sender: TObject; Buffer: TBitmap32;
  116. StageNum: Cardinal);
  117. procedure GaugeMouseUp(Sender: TObject; Button: TMouseButton;
  118. Shift: TShiftState; X, Y: Integer);
  119. procedure ImgButtonClick(Sender: TObject);
  120. procedure MnuBilinearWarpClick(Sender: TObject);
  121. procedure MnuFileExitClick(Sender: TObject);
  122. procedure MnuFileOpenImageClick(Sender: TObject);
  123. procedure MnuFileOpenMeshClick(Sender: TObject);
  124. procedure MnuFileSaveImageClick(Sender: TObject);
  125. procedure MnuFileSaveMeshClick(Sender: TObject);
  126. procedure MnuKernelModeClick(Sender: TObject);
  127. procedure MnuResetMeshClick(Sender: TObject);
  128. procedure MnuSamplingGridClick(Sender: TObject);
  129. procedure MnuSupersampleNowClick(Sender: TObject);
  130. procedure PressureBarChange(Sender: TObject);
  131. procedure RateBarChange(Sender: TObject);
  132. procedure ScaleBarMouseUp(Sender: TObject; Button: TMouseButton;
  133. Shift: TShiftState; X, Y: Integer);
  134. procedure SizeBarChange(Sender: TObject);
  135. procedure ToolGroupClick(Sender: TObject);
  136. procedure UpdateTimerTimer(Sender: TObject);
  137. public
  138. Src: TBitmap32;
  139. Remapper: TRemapTransformation;
  140. GenericBrush: TGenericBrush;
  141. CurrentBrush: array [TBrushToolMode] of TVectorMap;
  142. BrushMode: TBrushToolMode;
  143. TempMap: TVectorMap;
  144. MouseDown: Boolean;
  145. LastPos: TPoint;
  146. LastDelta: TFixedPoint;
  147. BrushLayer: TBrushLayer;
  148. SampleClipRect: TRect;
  149. SamplingGridSize: Byte;
  150. KernelMode: TKernelMode;
  151. procedure DrawMappedBrush(Pos: TPoint);
  152. procedure PrecalcCurrentBrush;
  153. procedure UpdateBrush;
  154. procedure DrawBrushMeshPreview;
  155. function SetBrushMode(Shift: TShiftState): Boolean;
  156. function GetParam: Single;
  157. procedure KernelChanged(Sender: TObject);
  158. end;
  159. var
  160. MainForm: TMainForm;
  161. const
  162. // Provide two attractive fast resampling modes for the realtime brush warping
  163. RESAMPLERS: array [Boolean] of TCustomResamplerClass =(TNearestResampler,
  164. TLinearResampler);
  165. // Pick some attractive kernels for the antialiasing methods
  166. KERNELS: array [0..6] of TCustomKernelClass = (TBoxKernel, TLinearKernel,
  167. TSplineKernel, TMitchellKernel, TSinshKernel, TGaussianKernel, TCubicKernel);
  168. var
  169. KernelIndex : 0..6 = 6; //TCubicKernel
  170. implementation
  171. uses
  172. {$IFNDEF FPC}
  173. JPEG,
  174. {$ELSE}
  175. LazJPG,
  176. {$ENDIF}
  177. GR32_LowLevel;
  178. {$IFDEF FPC}
  179. {$R *.lfm}
  180. {$ELSE}
  181. {$R *.dfm}
  182. {$ENDIF}
  183. procedure WarpDummy(var D, R: Single; Param: Single);
  184. begin
  185. // do nothing
  186. end;
  187. procedure ZoomIn(var D, R: Single; Param: Single);
  188. begin
  189. D := D - 0.1 * (1 - (1 - D) * Param);
  190. end;
  191. procedure ZoomOut(var D, R: Single; Param: Single);
  192. begin
  193. D := D + 0.1 * (1 - (1 - D) * Param);
  194. end;
  195. procedure TwirlCW(var D, R: Single; Param: Single);
  196. begin
  197. R := R + Param;
  198. end;
  199. procedure TwirlCCW(var D, R: Single; Param: Single);
  200. begin
  201. R := R - Param;
  202. end;
  203. procedure FlowerOut(var D, R: Single; Param: Single);
  204. begin
  205. D := D * Sin(R * Param);
  206. end;
  207. procedure FlowerIn(var D, R: Single; Param: Single);
  208. begin
  209. D := D * Max(Sin(R * Param), 0);
  210. end;
  211. procedure TMainForm.FormCreate(Sender: TObject);
  212. var
  213. I : TBrushToolMode;
  214. J: Integer;
  215. Item: TMenuItem;
  216. ResStream: TResourceStream;
  217. JPEG: TJPEGImage;
  218. begin
  219. Src := TBitmap32.Create;
  220. // load example image
  221. JPEG := TJPEGImage.Create;
  222. try
  223. ResStream := TResourceStream.Create(HInstance, 'MonaLisa', RT_RCDATA);
  224. try
  225. JPEG.LoadFromStream(ResStream);
  226. finally
  227. ResStream.Free;
  228. end;
  229. Src.Assign(JPEG);
  230. finally
  231. JPEG.Free;
  232. end;
  233. Src.OuterColor := 0;
  234. Src.DrawMode := dmBlend;
  235. Src.CombineMode := cmMerge;
  236. SetBorderTransparent(Src, Src.BoundsRect);
  237. with DstImg do
  238. begin
  239. Bitmap.Assign(Src);
  240. Cursor := crNone;
  241. with PaintStages[0]^ do //Set up custom paintstage to draw checkerboard
  242. begin
  243. Stage := PST_CUSTOM;
  244. Parameter := 1; // use parameter to tag the stage, we inspect this in OnPaintStage
  245. end;
  246. end;
  247. Remapper := TRemapTransformation.Create;
  248. Remapper.VectorMap.SetSizeFrom(Src);
  249. Remapper.SrcRect := FloatRect(Src.BoundsRect);
  250. Remapper.MappingRect := FloatRect(DstImg.Bitmap.BoundsRect);
  251. for I := btmLeft to btmRight do
  252. CurrentBrush[I] := TVectorMap.Create;
  253. TempMap := TVectorMap.Create;
  254. for J := 0 to High(KERNELS) do
  255. begin
  256. Item := TMenuItem.Create(Self);
  257. Item.Caption := KERNELS[J].ClassName;
  258. Item.Tag := J;
  259. Item.OnClick := KernelChanged;
  260. Item.AutoCheck := True;
  261. Item.RadioItem := True;
  262. if J = KernelIndex then Item.Checked := True;
  263. MnuSamplingKernel.Add(Item);
  264. end;
  265. KernelMode := kmTableLinear;
  266. GenericBrush := TGenericBrush.Create;
  267. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  268. BrushLayer := TBrushLayer.Create(DstImg.Layers);
  269. SampleClipRect := Rect(MaxInt, MaxInt, -MaxInt, -MaxInt);
  270. SamplingGridSize := 3;
  271. PressureBarChange(Self);
  272. UpdateBrush;
  273. end;
  274. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
  275. var
  276. I : TBrushToolMode;
  277. begin
  278. Src.Free;
  279. Remapper.Free;
  280. GenericBrush.Free;
  281. for I := btmLeft to btmRight do
  282. CurrentBrush[I].Free;
  283. TempMap.Free;
  284. BrushLayer.Free;
  285. end;
  286. function TMainForm.SetBrushMode(Shift: TShiftState): Boolean;
  287. begin
  288. Result := False;
  289. if [ssRight, ssLeft] * Shift <> [] then
  290. begin
  291. Result := True;
  292. if ssLeft in Shift then
  293. BrushMode := btmLeft //Higher priority
  294. else
  295. BrushMode := btmRight;
  296. end;
  297. end;
  298. procedure TMainForm.DstImgMouseMove(Sender: TObject; Shift: TShiftState; X,
  299. Y: Integer; Layer: TCustomLayer);
  300. function Color32ToStr(C: TColor32): string;
  301. begin
  302. Result := 'A: ' + IntToStr(C shr 24);
  303. Result := Result + ' R: ' + IntToStr(C shr 16 and $FF);
  304. Result := Result + ' G: ' + IntToStr(C shr 8 and $FF);
  305. Result := Result + ' B: ' + IntToStr(C and $FF);
  306. end;
  307. begin
  308. BrushLayer.Center := Point(X, Y);
  309. with DstImg.ControlToBitmap(Point(X, Y)) do Caption := cAppName + ' [' + Color32ToStr(DstImg.Bitmap.PixelS[X,Y]) + ']';
  310. if SetBrushMode(Shift) then
  311. with DstImg.ControlToBitmap(Point(X, Y)) do
  312. DrawMappedBrush(Point(X - CurrentBrush[BrushMode].Width div 2,
  313. Y - CurrentBrush[BrushMode].Height div 2));
  314. end;
  315. procedure TMainForm.RateBarChange(Sender: TObject);
  316. begin
  317. if RateBar.Position = 0 then
  318. UpdateTimer.Enabled := False
  319. else
  320. begin
  321. UpdateTimer.Enabled := True;
  322. UpdateTimer.Interval := Round(400 - RateBar.Position);
  323. end;
  324. end;
  325. procedure TMainForm.UpdateTimerTimer(Sender: TObject);
  326. begin
  327. if MouseDown then
  328. DrawMappedBrush(LastPos);
  329. end;
  330. procedure TMainForm.DstImgMouseUp(Sender: TObject; Button: TMouseButton;
  331. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  332. begin
  333. MouseDown := False;
  334. end;
  335. procedure TMainForm.DstImgMouseDown(Sender: TObject; Button: TMouseButton;
  336. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  337. var
  338. P, Q : Integer;
  339. begin
  340. MouseDown := True;
  341. if SetBrushMode(Shift) then
  342. with DstImg.ControlToBitmap(Point(X, Y)) do
  343. begin
  344. P := CurrentBrush[BrushMode].Width div 2;
  345. Q := CurrentBrush[BrushMode].Height div 2;
  346. LastPos := Point(X - P, Y - Q);
  347. LastDelta := FixedPoint(0,0);
  348. with LastPos do
  349. UnionRect(SampleClipRect, SampleClipRect, Rect(X, Y, X + P, Y + Q));
  350. end;
  351. end;
  352. procedure TMainForm.DrawMappedBrush(Pos: TPoint);
  353. const
  354. PI2 = PI * 2;
  355. var
  356. SrcR, SrcB, X, Y, I, J, ClipLeft, ClipTop, ClipRight, ClipBottom: Integer;
  357. Vertex: TFixedPoint;
  358. Dst: TVectorMap;
  359. DeltaX, DeltaY, Zx, Zy: TFixed;
  360. P: TFixedPoint;
  361. DstClip: TRect;
  362. begin
  363. X := Pos.X;
  364. Y := Pos.Y;
  365. SrcR := CurrentBrush[BrushMode].Width - 1;
  366. SrcB := CurrentBrush[BrushMode].Height - 1;
  367. Dst := Remapper.VectorMap;
  368. ClipLeft := Abs(Min(0, X));
  369. ClipRight := Min(SrcR + X, Dst.Width - 1) - X;
  370. ClipTop := Abs(Min(0, Y));
  371. ClipBottom := Min(SrcB + Y, Dst.Height - 1) - Y;
  372. if ToolGroup.ItemIndex = 0 then
  373. begin
  374. DeltaX := Round((Fixed(Integer(LastPos.X - X)) + LastDelta.X) * 0.5);
  375. DeltaY := Round((Fixed(Integer(LastPos.Y - Y)) + LastDelta.Y) * 0.5);
  376. LastDelta.X := DeltaX;
  377. LastDelta.Y := DeltaY;
  378. end
  379. else
  380. begin
  381. DeltaX := FIXEDONE;
  382. DeltaY := FIXEDONE;
  383. end;
  384. for J := ClipTop to ClipBottom do
  385. for I := ClipLeft to ClipRight do
  386. begin
  387. Zx := Fixed(Integer(X + I));
  388. Zy := Fixed(Integer(Y + J));
  389. P := CurrentBrush[BrushMode].FixedVector[I, J];
  390. P.X := FixedMul(DeltaX, P.X);
  391. P.Y := FixedMul(DeltaY, P.Y);
  392. Vertex := Dst.FixedVectorXS[Zx + P.X, Zy + P.Y];
  393. Inc(Vertex.X, P.X);
  394. Inc(Vertex.Y, P.Y);
  395. TempMap.FixedVector[I, J] := Vertex;
  396. end;
  397. for J := ClipTop to ClipBottom do
  398. for I := ClipLeft to ClipRight do
  399. Dst.FixedVector[X + I, Y + J] := TempMap.FixedVector[I, J];
  400. DstClip := Rect(X, Y, X + CurrentBrush[BrushMode].Width,
  401. Y + CurrentBrush[BrushMode].Height);
  402. DstImg.Bitmap.FillRectS(DstClip, 0);
  403. Transform(DstImg.Bitmap, Src, Remapper, DstClip);
  404. DstImg.Repaint;
  405. UnionRect(SampleClipRect, SampleClipRect, DstClip);
  406. LastPos := Point(X, Y);
  407. end;
  408. procedure TMainForm.PrecalcCurrentBrush;
  409. // Precalculate transformation factors and/or integrate brush weights
  410. const
  411. TOOLPROCS: array [TBrushToolMode, TBrushTool] of TToolProc = ((nil, ZoomIn,
  412. TwirlCW, FlowerOut),(nil, ZoomOut, TwirlCCW, FlowerIn));
  413. var
  414. I,J: Integer;
  415. w, rx, ry, nrx, nry, x, y, d, r, Param: Single;
  416. Tool: TBrushTool;
  417. ToolMode: TBrushToolMode;
  418. Proc: TToolProc;
  419. begin
  420. Tool := TBrushTool(ToolGroup.ItemIndex);
  421. for ToolMode := btmLeft to btmRight do with CurrentBrush[ToolMode] do
  422. begin
  423. rx := Width - 1;
  424. ry := Height - 1;
  425. nrx := 2 / rx;
  426. nry := 2 / ry;
  427. Proc := TOOLPROCS[ToolMode, Tool];
  428. case Tool of
  429. btWarp:
  430. begin
  431. for J := 0 to Height - 1 do
  432. for I := 0 to Width - 1 do
  433. begin
  434. x := I * nrx - 1;
  435. y := J * nry - 1;
  436. w := GenericBrush.Weight(x, y);
  437. FixedVector[I, J] := FixedPoint(w, w);
  438. end;
  439. Exit;
  440. end;
  441. end;
  442. Param := GetParam;
  443. for J := 0 to Height - 1 do
  444. for I := 0 to Width - 1 do
  445. begin
  446. x := I * nrx - 1;
  447. y := J * nry - 1;
  448. w := GenericBrush.Weight(x, y);
  449. d := GR32_Math.Hypot(x, y);
  450. r := ArcTan2(y, x);
  451. Proc(d, r, Param);
  452. SinCos(r, d, y, x);
  453. x := (x + 1) * rx * 0.5 - I;
  454. y := (y + 1) * ry * 0.5 - J;
  455. FixedVector[I, J] := FixedPoint(x * w, y * w);
  456. end;
  457. end;
  458. end;
  459. procedure TMainForm.ToolGroupClick(Sender: TObject);
  460. begin
  461. case ToolGroup.ItemIndex of
  462. 0:
  463. begin
  464. LblParam.Enabled := False;
  465. ParamBar.Enabled := False;
  466. RateLabel.Enabled := False;
  467. RateBar.Enabled := False;
  468. UpdateTimer.Enabled := False;
  469. end;
  470. 1,2,3:
  471. begin
  472. LblParam.Enabled := True;
  473. ParamBar.Enabled := True;
  474. RateLabel.Enabled := True;
  475. RateBar.Enabled := True;
  476. UpdateTimer.Enabled := True;
  477. end;
  478. end;
  479. case ToolGroup.ItemIndex of
  480. 1: LblParam.Caption := 'Softness';
  481. 2: LblParam.Caption := 'Strength';
  482. 3: LblParam.Caption := 'Leaves Count';
  483. end;
  484. UpdateBrush;
  485. end;
  486. procedure TMainForm.GaugeMouseUp(Sender: TObject; Button: TMouseButton;
  487. Shift: TShiftState; X, Y: Integer);
  488. begin
  489. UpdateBrush;
  490. end;
  491. procedure TMainForm.UpdateBrush;
  492. var
  493. I: TBrushToolMode;
  494. begin
  495. for I := btmLeft to btmRight do
  496. CurrentBrush[I].SetSize(SizeBar.Position, SizeBar.Position);
  497. TempMap.SetSizeFrom(CurrentBrush[btmLeft]);
  498. PrecalcCurrentBrush;
  499. BrushLayer.Radius := SizeBar.Position div 2;
  500. DrawBrushMeshPreview;
  501. end;
  502. procedure TMainForm.DrawBrushMeshPreview;
  503. // Render some sort of preview of the brush mesh...
  504. var
  505. I, J, rx, ry: Integer;
  506. Proc: TToolProc;
  507. Tool: TBrushTool;
  508. D, R, x, y, Param,Sx, Sy, w: Single;
  509. const
  510. Colors: array [Boolean] of TColor32 = ($FFE0E0E0, $FF000000);
  511. TOOLPROCS: array [TBrushToolMode, TBrushTool] of TToolProc =
  512. ((WarpDummy, ZoomIn, TwirlCW, FlowerOut),
  513. (WarpDummy, ZoomOut, TwirlCCW, FlowerIn));
  514. GridSize = 8;
  515. begin
  516. if BrushMeshPreview.Buffer.Empty then Exit;
  517. Tool := TBrushTool(ToolGroup.ItemIndex);
  518. Proc := TOOLPROCS[BrushMode, Tool];
  519. with BrushMeshPreview do
  520. begin
  521. Param := GetParam;
  522. Buffer.Clear($FF000000);
  523. rx := Width - 1;
  524. ry := (Height - 1) div GridSize;
  525. Sx := 2 / rx;
  526. Sy := 2 / ((Height - 1) / GridSize);
  527. for J := 0 to ry do
  528. begin
  529. Buffer.MoveToF(0, J * GridSize);
  530. for I := 0 to rx do
  531. begin
  532. x := I * Sx - 1;
  533. y := J * Sy - 1;
  534. d := GR32_Math.Hypot(x, y);
  535. r := ArcTan2(y, x);
  536. Proc(d, r, Param);
  537. w := GenericBrush.Weight(x,y);
  538. SinCos(r, d, y, x);
  539. x := I - ((x + 1) * rx * 0.5 - I) * w;
  540. y := J - ((y + 1) * ry * 0.5 - J) * w;
  541. y := y * GridSize;
  542. Buffer.PenColor := Gray32(15 + Round(240 * (1 - Sqr(1 - w))));
  543. Buffer.LineToFS(x, y);
  544. end;
  545. end;
  546. rx := (Width - 1) div GridSize;
  547. ry := Height - 1;
  548. Sx := 2 / ((Width - 1) / GridSize);
  549. Sy := 2 / ry;
  550. for I := 0 to rx do
  551. begin
  552. Buffer.MoveToF(I * GridSize, 0);
  553. for J := 0 to ry do
  554. begin
  555. x := I * Sx - 1;
  556. y := J * Sy - 1;
  557. d := GR32_Math.Hypot(x, y);
  558. r := ArcTan2(y, x);
  559. Proc(d, r, Param);
  560. w := GenericBrush.Weight(x,y);
  561. SinCos(r, d, y, x);
  562. x := I - ((x + 1) * rx * 0.5 - I) * w;
  563. x := x * GridSize;
  564. y := J - ((y + 1) * ry * 0.5 - J) * w;
  565. Buffer.PenColor := Gray32(15 + Round(240 * (1 - Sqr(1 - w))) );
  566. Buffer.LineToFS(x, y);
  567. end;
  568. end;
  569. Buffer.FrameRectS(GetViewPortRect , $FFFFFFFF); //Draw Frame
  570. Repaint;
  571. end;
  572. end;
  573. procedure TMainForm.ScaleBarMouseUp(Sender: TObject; Button: TMouseButton;
  574. Shift: TShiftState; X, Y: Integer);
  575. var
  576. S: Single;
  577. begin
  578. S := ScaleBar.Position * 0.01;
  579. Remapper.Scale(S, S);
  580. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  581. Transform(DstImg.Bitmap, Src, Remapper);
  582. end;
  583. function TMainForm.GetParam: Single;
  584. begin
  585. case TBrushTool(ToolGroup.ItemIndex) of
  586. btFlower: Result := Round(ParamBar.Position * 0.16 + 1);
  587. btZoom: Result := 1 - ParamBar.Position * 0.01;
  588. else Result := ParamBar.Position * 0.01
  589. end
  590. end;
  591. procedure TMainForm.PressureBarChange(Sender: TObject);
  592. begin
  593. GenericBrush.Pressure := PressureBar.Position * 0.01;
  594. GenericBrush.Pinch := PinchBar.Position * 0.01;
  595. GenericBrush.Feather := FeatherBar.Position * 0.01;
  596. UpdateBrush;
  597. end;
  598. procedure TMainForm.MnuFileOpenImageClick(Sender: TObject);
  599. begin
  600. if OpenPictureDialog.Execute then
  601. begin
  602. Src.LoadFromFile(OpenPictureDialog.Filename);
  603. SetBorderTransparent(Src, Src.BoundsRect); //Fix against border issues
  604. DstImg.Bitmap.Assign(Src);
  605. Remapper.VectorMap.SetSizeFrom(Src);
  606. Remapper.SrcRect := FloatRect(Src.BoundsRect);
  607. Remapper.MappingRect := FloatRect(DstImg.Bitmap.BoundsRect);
  608. end;
  609. end;
  610. procedure TMainForm.MnuFileSaveImageClick(Sender: TObject);
  611. begin
  612. with SavePictureDialog do if Execute then
  613. begin
  614. if Lowercase(ExtractFileExt(Filename)) <> '.bmp' then
  615. Filename:= Filename + '.bmp';
  616. DstImg.Bitmap.SaveToFile(Filename);
  617. end
  618. end;
  619. procedure TMainForm.MnuResetMeshClick(Sender: TObject);
  620. begin
  621. Remapper.VectorMap.Clear;
  622. DstImg.Bitmap.Assign(Src);
  623. ScaleBar.Position := 100;
  624. Remapper.Scale(1, 1);
  625. end;
  626. procedure TMainForm.MnuFileSaveMeshClick(Sender: TObject);
  627. begin
  628. with SaveMeshDialog do if Execute then
  629. begin
  630. if Lowercase(ExtractFileExt(Filename)) <> '.msh' then
  631. Filename:= Filename + '.msh';
  632. Remapper.VectorMap.SaveToFile(Filename);
  633. end
  634. end;
  635. procedure TMainForm.MnuFileOpenMeshClick(Sender: TObject);
  636. begin
  637. with OpenMeshDialog do if Execute then begin
  638. Remapper.VectorMap.LoadFromFile(Filename);
  639. Transform(DstImg.Bitmap, Src, Remapper);
  640. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  641. DstImg.Repaint;
  642. end;
  643. end;
  644. procedure TMainForm.MnuSupersampleNowClick(Sender: TObject);
  645. var
  646. Rasterizer: TRasterizer;
  647. Transformer: TTransformer;
  648. SuperSampler: TSuperSampler;
  649. KernelResampler : TKernelResampler;
  650. begin
  651. Screen.Cursor := crHourGlass;
  652. KernelResampler := TKernelResampler.Create(Src);
  653. KernelResampler.KernelMode := KernelMode;
  654. // Normally this should be set higher.
  655. // It is set low here to display perceptual consequences
  656. KernelResampler.TableSize := 4;
  657. KernelResampler.Kernel := KERNELS[KernelIndex].Create;
  658. Transformer := TTransformer.Create(Src.Resampler, Remapper);
  659. SuperSampler := TSuperSampler.Create(Transformer);
  660. Rasterizer := TRegularRasterizer.Create;
  661. try
  662. Rasterizer.Sampler := SuperSampler;
  663. SuperSampler.SamplingX := SamplingGridSize;
  664. SuperSampler.SamplingY := SamplingGridSize;
  665. DstImg.Bitmap.FillRectS(SampleClipRect, 0);
  666. Rasterizer.Rasterize(DstImg.Bitmap, SampleClipRect, Src);
  667. SampleClipRect := Rect(MaxInt, MaxInt, -MaxInt, -MaxInt);
  668. finally
  669. Rasterizer.Free;
  670. SuperSampler.Free;
  671. Transformer.Free;
  672. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  673. Screen.Cursor := crDefault;
  674. DstImg.Repaint;
  675. end;
  676. end;
  677. procedure TMainForm.MnuBilinearWarpClick(Sender: TObject);
  678. begin
  679. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  680. Transform(DstImg.Bitmap, Src, Remapper);
  681. end;
  682. procedure TMainForm.MnuSamplingGridClick(Sender: TObject);
  683. begin
  684. if Sender is TMenuItem then
  685. SamplingGridSize := TMenuItem(Sender).Tag;
  686. end;
  687. procedure TMainForm.KernelChanged(Sender: TObject);
  688. begin
  689. if Sender is TMenuItem then
  690. begin
  691. KernelIndex := TMenuItem(Sender).Tag;
  692. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  693. MnuSuperSampleNowClick(Self);
  694. end;
  695. end;
  696. procedure TMainForm.BrushMeshPreviewResize(Sender: TObject);
  697. begin
  698. UpdateBrush;
  699. end;
  700. procedure TMainForm.SizeBarChange(Sender: TObject);
  701. begin
  702. DstImg.Repaint;
  703. BrushLayer.Radius := SizeBar.Position div 2;
  704. BrushLayer.Center := Point(DstImg.Width div 2, DstImg.Height div 2);
  705. end;
  706. procedure TMainForm.ImgButtonClick(Sender: TObject);
  707. begin
  708. if Sender is TToolbutton then
  709. TToolButton(Sender).DropdownMenu.Popup(Mouse.CursorPos.X,
  710. Mouse.CursorPos.Y);
  711. end;
  712. procedure TMainForm.DstImgPaintStage(Sender: TObject; Buffer: TBitmap32;
  713. StageNum: Cardinal);
  714. const //0..1
  715. Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
  716. var
  717. R: TRect;
  718. I, J: Integer;
  719. OddY: Integer;
  720. TilesHorz, TilesVert: Integer;
  721. TileX, TileY: Integer;
  722. TileHeight, TileWidth: Integer;
  723. begin
  724. with TImgView32(Sender) do
  725. begin
  726. BeginUpdate;
  727. R := GetViewportRect;
  728. TileHeight := 8;
  729. TileWidth := 8;
  730. TilesHorz := (R.Right - R.Left) div TileWidth;
  731. TilesVert := (R.Bottom - R.Top) div TileHeight;
  732. TileY := 0;
  733. for J := 0 to TilesVert do
  734. begin
  735. TileX := 0;
  736. OddY := J and $1;
  737. for I := 0 to TilesHorz do
  738. begin
  739. Buffer.FillRectS(TileX, TileY, TileX + TileWidth, TileY +
  740. TileHeight,Colors[I and $1 = OddY]);
  741. Inc(TileX, TileWidth);
  742. end;
  743. Inc(TileY, TileHeight);
  744. end;
  745. EndUpdate;
  746. end;
  747. end;
  748. procedure TMainForm.MnuKernelModeClick(Sender: TObject);
  749. begin
  750. if Sender is TMenuItem then
  751. begin
  752. KernelMode := TKernelMode(TMenuItem(Sender).Tag);
  753. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  754. MnuSuperSampleNowClick(Self);
  755. end;
  756. end;
  757. procedure TMainForm.MnuFileExitClick(Sender: TObject);
  758. begin
  759. Close;
  760. end;
  761. end.