MainUnit.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  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. {$include GR32.inc}
  38. uses
  39. {$IFNDEF FPC} Windows, {$ELSE} LCLIntf, LCLType, 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. Types,
  173. GR32_LowLevel,
  174. GR32.ImageFormats.JPG;
  175. {$R *.dfm}
  176. procedure WarpDummy(var D, R: Single; Param: Single);
  177. begin
  178. // do nothing
  179. end;
  180. procedure ZoomIn(var D, R: Single; Param: Single);
  181. begin
  182. D := D - 0.1 * (1 - (1 - D) * Param);
  183. end;
  184. procedure ZoomOut(var D, R: Single; Param: Single);
  185. begin
  186. D := D + 0.1 * (1 - (1 - D) * Param);
  187. end;
  188. procedure TwirlCW(var D, R: Single; Param: Single);
  189. begin
  190. R := R + Param;
  191. end;
  192. procedure TwirlCCW(var D, R: Single; Param: Single);
  193. begin
  194. R := R - Param;
  195. end;
  196. procedure FlowerOut(var D, R: Single; Param: Single);
  197. begin
  198. D := D * Sin(R * Param);
  199. end;
  200. procedure FlowerIn(var D, R: Single; Param: Single);
  201. begin
  202. D := D * Max(Sin(R * Param), 0);
  203. end;
  204. procedure TMainForm.FormCreate(Sender: TObject);
  205. var
  206. I : TBrushToolMode;
  207. J: Integer;
  208. Item: TMenuItem;
  209. begin
  210. // load example image
  211. Src := TBitmap32.Create;
  212. Src.LoadFromResourceName(HInstance, 'MonaLisa', RT_RCDATA);
  213. Src.OuterColor := 0;
  214. Src.DrawMode := dmBlend;
  215. Src.CombineMode := cmMerge;
  216. SetBorderTransparent(Src, Src.BoundsRect);
  217. with DstImg do
  218. begin
  219. Bitmap.Assign(Src);
  220. Cursor := crNone;
  221. with PaintStages[0]^ do //Set up custom paintstage to draw checkerboard
  222. begin
  223. Stage := PST_CUSTOM;
  224. Parameter := 1; // use parameter to tag the stage, we inspect this in OnPaintStage
  225. end;
  226. end;
  227. Remapper := TRemapTransformation.Create;
  228. Remapper.VectorMap.SetSizeFrom(Src);
  229. Remapper.SrcRect := FloatRect(Src.BoundsRect);
  230. Remapper.MappingRect := FloatRect(DstImg.Bitmap.BoundsRect);
  231. for I := btmLeft to btmRight do
  232. CurrentBrush[I] := TVectorMap.Create;
  233. TempMap := TVectorMap.Create;
  234. for J := 0 to High(KERNELS) do
  235. begin
  236. Item := TMenuItem.Create(Self);
  237. Item.Caption := KERNELS[J].ClassName;
  238. Item.Tag := J;
  239. Item.OnClick := KernelChanged;
  240. Item.AutoCheck := True;
  241. Item.RadioItem := True;
  242. if J = KernelIndex then Item.Checked := True;
  243. MnuSamplingKernel.Add(Item);
  244. end;
  245. KernelMode := kmTableLinear;
  246. GenericBrush := TGenericBrush.Create;
  247. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  248. BrushLayer := TBrushLayer.Create(DstImg.Layers);
  249. SampleClipRect := Rect(MaxInt, MaxInt, -MaxInt, -MaxInt);
  250. SamplingGridSize := 3;
  251. PressureBarChange(Self);
  252. UpdateBrush;
  253. end;
  254. procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
  255. var
  256. I : TBrushToolMode;
  257. begin
  258. Src.Free;
  259. Remapper.Free;
  260. GenericBrush.Free;
  261. for I := btmLeft to btmRight do
  262. CurrentBrush[I].Free;
  263. TempMap.Free;
  264. BrushLayer.Free;
  265. end;
  266. function TMainForm.SetBrushMode(Shift: TShiftState): Boolean;
  267. begin
  268. Result := False;
  269. if [ssRight, ssLeft] * Shift <> [] then
  270. begin
  271. Result := True;
  272. if ssLeft in Shift then
  273. BrushMode := btmLeft //Higher priority
  274. else
  275. BrushMode := btmRight;
  276. end;
  277. end;
  278. procedure TMainForm.DstImgMouseMove(Sender: TObject; Shift: TShiftState; X,
  279. Y: Integer; Layer: TCustomLayer);
  280. function Color32ToStr(C: TColor32): string;
  281. begin
  282. Result := 'A: ' + IntToStr(C shr 24);
  283. Result := Result + ' R: ' + IntToStr(C shr 16 and $FF);
  284. Result := Result + ' G: ' + IntToStr(C shr 8 and $FF);
  285. Result := Result + ' B: ' + IntToStr(C and $FF);
  286. end;
  287. begin
  288. BrushLayer.Center := GR32.Point(X, Y);
  289. with DstImg.ControlToBitmap(GR32.Point(X, Y)) do Caption := cAppName + ' [' + Color32ToStr(DstImg.Bitmap.PixelS[X,Y]) + ']';
  290. if SetBrushMode(Shift) then
  291. with DstImg.ControlToBitmap(GR32.Point(X, Y)) do
  292. DrawMappedBrush(GR32.Point(X - CurrentBrush[BrushMode].Width div 2, Y - CurrentBrush[BrushMode].Height div 2));
  293. end;
  294. procedure TMainForm.RateBarChange(Sender: TObject);
  295. begin
  296. if RateBar.Position = 0 then
  297. UpdateTimer.Enabled := False
  298. else
  299. begin
  300. UpdateTimer.Enabled := True;
  301. UpdateTimer.Interval := Round(400 - RateBar.Position);
  302. end;
  303. end;
  304. procedure TMainForm.UpdateTimerTimer(Sender: TObject);
  305. begin
  306. if MouseDown then
  307. DrawMappedBrush(LastPos);
  308. end;
  309. procedure TMainForm.DstImgMouseUp(Sender: TObject; Button: TMouseButton;
  310. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  311. begin
  312. MouseDown := False;
  313. end;
  314. procedure TMainForm.DstImgMouseDown(Sender: TObject; Button: TMouseButton;
  315. Shift: TShiftState; X, Y: Integer; Layer: TCustomLayer);
  316. var
  317. P, Q : Integer;
  318. begin
  319. MouseDown := True;
  320. if SetBrushMode(Shift) then
  321. with DstImg.ControlToBitmap(GR32.Point(X, Y)) do
  322. begin
  323. P := CurrentBrush[BrushMode].Width div 2;
  324. Q := CurrentBrush[BrushMode].Height div 2;
  325. LastPos := GR32.Point(X - P, Y - Q);
  326. LastDelta := FixedPoint(0,0);
  327. with LastPos do
  328. GR32.UnionRect(SampleClipRect, SampleClipRect, Rect(X, Y, X + P, Y + Q));
  329. end;
  330. end;
  331. procedure TMainForm.DrawMappedBrush(Pos: TPoint);
  332. const
  333. PI2 = PI * 2;
  334. var
  335. SrcR, SrcB, X, Y, I, J, ClipLeft, ClipTop, ClipRight, ClipBottom: Integer;
  336. Vertex: TFixedPoint;
  337. Dst: TVectorMap;
  338. DeltaX, DeltaY, Zx, Zy: TFixed;
  339. P: TFixedPoint;
  340. DstClip: TRect;
  341. begin
  342. X := Pos.X;
  343. Y := Pos.Y;
  344. SrcR := CurrentBrush[BrushMode].Width - 1;
  345. SrcB := CurrentBrush[BrushMode].Height - 1;
  346. Dst := Remapper.VectorMap;
  347. ClipLeft := Abs(Min(0, X));
  348. ClipRight := Min(SrcR + X, Dst.Width - 1) - X;
  349. ClipTop := Abs(Min(0, Y));
  350. ClipBottom := Min(SrcB + Y, Dst.Height - 1) - Y;
  351. if ToolGroup.ItemIndex = 0 then
  352. begin
  353. DeltaX := Round((Fixed(Integer(LastPos.X - X)) + LastDelta.X) * 0.5);
  354. DeltaY := Round((Fixed(Integer(LastPos.Y - Y)) + LastDelta.Y) * 0.5);
  355. LastDelta.X := DeltaX;
  356. LastDelta.Y := DeltaY;
  357. end
  358. else
  359. begin
  360. DeltaX := FIXEDONE;
  361. DeltaY := FIXEDONE;
  362. end;
  363. for J := ClipTop to ClipBottom do
  364. for I := ClipLeft to ClipRight do
  365. begin
  366. Zx := Fixed(Integer(X + I));
  367. Zy := Fixed(Integer(Y + J));
  368. P := CurrentBrush[BrushMode].FixedVector[I, J];
  369. P.X := FixedMul(DeltaX, P.X);
  370. P.Y := FixedMul(DeltaY, P.Y);
  371. Vertex := Dst.FixedVectorXS[Zx + P.X, Zy + P.Y];
  372. Inc(Vertex.X, P.X);
  373. Inc(Vertex.Y, P.Y);
  374. TempMap.FixedVector[I, J] := Vertex;
  375. end;
  376. for J := ClipTop to ClipBottom do
  377. for I := ClipLeft to ClipRight do
  378. Dst.FixedVector[X + I, Y + J] := TempMap.FixedVector[I, J];
  379. DstClip := Rect(X, Y, X + CurrentBrush[BrushMode].Width,
  380. Y + CurrentBrush[BrushMode].Height);
  381. DstImg.Bitmap.FillRectS(DstClip, 0);
  382. Transform(DstImg.Bitmap, Src, Remapper, DstClip);
  383. DstImg.Repaint;
  384. GR32.UnionRect(SampleClipRect, SampleClipRect, DstClip);
  385. LastPos := GR32.Point(X, Y);
  386. end;
  387. procedure TMainForm.PrecalcCurrentBrush;
  388. // Precalculate transformation factors and/or integrate brush weights
  389. const
  390. TOOLPROCS: array [TBrushToolMode, TBrushTool] of TToolProc = ((nil, ZoomIn,
  391. TwirlCW, FlowerOut),(nil, ZoomOut, TwirlCCW, FlowerIn));
  392. var
  393. I,J: Integer;
  394. w, rx, ry, nrx, nry, x, y, d, r, Param: Single;
  395. Tool: TBrushTool;
  396. ToolMode: TBrushToolMode;
  397. Proc: TToolProc;
  398. begin
  399. Tool := TBrushTool(ToolGroup.ItemIndex);
  400. for ToolMode := btmLeft to btmRight do with CurrentBrush[ToolMode] do
  401. begin
  402. rx := Width - 1;
  403. ry := Height - 1;
  404. nrx := 2 / rx;
  405. nry := 2 / ry;
  406. Proc := TOOLPROCS[ToolMode, Tool];
  407. case Tool of
  408. btWarp:
  409. begin
  410. for J := 0 to Height - 1 do
  411. for I := 0 to Width - 1 do
  412. begin
  413. x := I * nrx - 1;
  414. y := J * nry - 1;
  415. w := GenericBrush.Weight(x, y);
  416. FixedVector[I, J] := FixedPoint(w, w);
  417. end;
  418. Exit;
  419. end;
  420. end;
  421. Param := GetParam;
  422. for J := 0 to Height - 1 do
  423. for I := 0 to Width - 1 do
  424. begin
  425. x := I * nrx - 1;
  426. y := J * nry - 1;
  427. w := GenericBrush.Weight(x, y);
  428. d := GR32_Math.Hypot(x, y);
  429. r := ArcTan2(y, x);
  430. Proc(d, r, Param);
  431. SinCos(r, d, y, x);
  432. x := (x + 1) * rx * 0.5 - I;
  433. y := (y + 1) * ry * 0.5 - J;
  434. FixedVector[I, J] := FixedPoint(x * w, y * w);
  435. end;
  436. end;
  437. end;
  438. procedure TMainForm.ToolGroupClick(Sender: TObject);
  439. begin
  440. case ToolGroup.ItemIndex of
  441. 0:
  442. begin
  443. LblParam.Enabled := False;
  444. ParamBar.Enabled := False;
  445. RateLabel.Enabled := False;
  446. RateBar.Enabled := False;
  447. UpdateTimer.Enabled := False;
  448. end;
  449. 1,2,3:
  450. begin
  451. LblParam.Enabled := True;
  452. ParamBar.Enabled := True;
  453. RateLabel.Enabled := True;
  454. RateBar.Enabled := True;
  455. UpdateTimer.Enabled := True;
  456. end;
  457. end;
  458. case ToolGroup.ItemIndex of
  459. 1: LblParam.Caption := 'Softness';
  460. 2: LblParam.Caption := 'Strength';
  461. 3: LblParam.Caption := 'Leaves Count';
  462. end;
  463. UpdateBrush;
  464. end;
  465. procedure TMainForm.GaugeMouseUp(Sender: TObject; Button: TMouseButton;
  466. Shift: TShiftState; X, Y: Integer);
  467. begin
  468. UpdateBrush;
  469. end;
  470. procedure TMainForm.UpdateBrush;
  471. var
  472. I: TBrushToolMode;
  473. begin
  474. for I := btmLeft to btmRight do
  475. CurrentBrush[I].SetSize(SizeBar.Position, SizeBar.Position);
  476. TempMap.SetSizeFrom(CurrentBrush[btmLeft]);
  477. PrecalcCurrentBrush;
  478. BrushLayer.Radius := SizeBar.Position div 2;
  479. DrawBrushMeshPreview;
  480. end;
  481. procedure TMainForm.DrawBrushMeshPreview;
  482. // Render some sort of preview of the brush mesh...
  483. var
  484. I, J, rx, ry: Integer;
  485. Proc: TToolProc;
  486. Tool: TBrushTool;
  487. D, R, x, y, Param,Sx, Sy, w: Single;
  488. const
  489. Colors: array [Boolean] of TColor32 = ($FFE0E0E0, $FF000000);
  490. TOOLPROCS: array [TBrushToolMode, TBrushTool] of TToolProc =
  491. ((WarpDummy, ZoomIn, TwirlCW, FlowerOut),
  492. (WarpDummy, ZoomOut, TwirlCCW, FlowerIn));
  493. GridSize = 8;
  494. begin
  495. if BrushMeshPreview.Buffer.Empty then Exit;
  496. Tool := TBrushTool(ToolGroup.ItemIndex);
  497. Proc := TOOLPROCS[BrushMode, Tool];
  498. with BrushMeshPreview do
  499. begin
  500. Param := GetParam;
  501. Buffer.Clear($FF000000);
  502. rx := Width - 1;
  503. ry := (Height - 1) div GridSize;
  504. Sx := 2 / rx;
  505. Sy := 2 / ((Height - 1) / GridSize);
  506. for J := 0 to ry do
  507. begin
  508. Buffer.MoveToF(0, J * GridSize);
  509. for I := 0 to rx do
  510. begin
  511. x := I * Sx - 1;
  512. y := J * Sy - 1;
  513. d := GR32_Math.Hypot(x, y);
  514. r := ArcTan2(y, x);
  515. Proc(d, r, Param);
  516. w := GenericBrush.Weight(x,y);
  517. SinCos(r, d, y, x);
  518. x := I - ((x + 1) * rx * 0.5 - I) * w;
  519. y := J - ((y + 1) * ry * 0.5 - J) * w;
  520. y := y * GridSize;
  521. Buffer.PenColor := Gray32(15 + Round(240 * (1 - Sqr(1 - w))));
  522. Buffer.LineToFS(x, y);
  523. end;
  524. end;
  525. rx := (Width - 1) div GridSize;
  526. ry := Height - 1;
  527. Sx := 2 / ((Width - 1) / GridSize);
  528. Sy := 2 / ry;
  529. for I := 0 to rx do
  530. begin
  531. Buffer.MoveToF(I * GridSize, 0);
  532. for J := 0 to ry do
  533. begin
  534. x := I * Sx - 1;
  535. y := J * Sy - 1;
  536. d := GR32_Math.Hypot(x, y);
  537. r := ArcTan2(y, x);
  538. Proc(d, r, Param);
  539. w := GenericBrush.Weight(x,y);
  540. SinCos(r, d, y, x);
  541. x := I - ((x + 1) * rx * 0.5 - I) * w;
  542. x := x * GridSize;
  543. y := J - ((y + 1) * ry * 0.5 - J) * w;
  544. Buffer.PenColor := Gray32(15 + Round(240 * (1 - Sqr(1 - w))) );
  545. Buffer.LineToFS(x, y);
  546. end;
  547. end;
  548. Buffer.FrameRectS(GetViewPortRect , $FFFFFFFF); //Draw Frame
  549. Repaint;
  550. end;
  551. end;
  552. procedure TMainForm.ScaleBarMouseUp(Sender: TObject; Button: TMouseButton;
  553. Shift: TShiftState; X, Y: Integer);
  554. var
  555. S: Single;
  556. begin
  557. S := ScaleBar.Position * 0.01;
  558. Remapper.Scale(S, S);
  559. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  560. Transform(DstImg.Bitmap, Src, Remapper);
  561. end;
  562. function TMainForm.GetParam: Single;
  563. begin
  564. case TBrushTool(ToolGroup.ItemIndex) of
  565. btFlower: Result := Round(ParamBar.Position * 0.16 + 1);
  566. btZoom: Result := 1 - ParamBar.Position * 0.01;
  567. else Result := ParamBar.Position * 0.01
  568. end
  569. end;
  570. procedure TMainForm.PressureBarChange(Sender: TObject);
  571. begin
  572. GenericBrush.Pressure := PressureBar.Position * 0.01;
  573. GenericBrush.Pinch := PinchBar.Position * 0.01;
  574. GenericBrush.Feather := FeatherBar.Position * 0.01;
  575. UpdateBrush;
  576. end;
  577. procedure TMainForm.MnuFileOpenImageClick(Sender: TObject);
  578. begin
  579. if OpenPictureDialog.Execute then
  580. begin
  581. Src.LoadFromFile(OpenPictureDialog.Filename);
  582. SetBorderTransparent(Src, Src.BoundsRect); //Fix against border issues
  583. DstImg.Bitmap.Assign(Src);
  584. Remapper.VectorMap.SetSizeFrom(Src);
  585. Remapper.SrcRect := FloatRect(Src.BoundsRect);
  586. Remapper.MappingRect := FloatRect(DstImg.Bitmap.BoundsRect);
  587. end;
  588. end;
  589. procedure TMainForm.MnuFileSaveImageClick(Sender: TObject);
  590. begin
  591. with SavePictureDialog do if Execute then
  592. begin
  593. if Lowercase(ExtractFileExt(Filename)) <> '.bmp' then
  594. Filename:= Filename + '.bmp';
  595. DstImg.Bitmap.SaveToFile(Filename);
  596. end
  597. end;
  598. procedure TMainForm.MnuResetMeshClick(Sender: TObject);
  599. begin
  600. Remapper.VectorMap.Clear;
  601. DstImg.Bitmap.Assign(Src);
  602. ScaleBar.Position := 100;
  603. Remapper.Scale(1, 1);
  604. end;
  605. procedure TMainForm.MnuFileSaveMeshClick(Sender: TObject);
  606. begin
  607. with SaveMeshDialog do if Execute then
  608. begin
  609. if Lowercase(ExtractFileExt(Filename)) <> '.msh' then
  610. Filename:= Filename + '.msh';
  611. Remapper.VectorMap.SaveToFile(Filename);
  612. end
  613. end;
  614. procedure TMainForm.MnuFileOpenMeshClick(Sender: TObject);
  615. begin
  616. with OpenMeshDialog do if Execute then begin
  617. Remapper.VectorMap.LoadFromFile(Filename);
  618. Transform(DstImg.Bitmap, Src, Remapper);
  619. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  620. DstImg.Repaint;
  621. end;
  622. end;
  623. procedure TMainForm.MnuSupersampleNowClick(Sender: TObject);
  624. var
  625. Rasterizer: TRasterizer;
  626. Transformer: TTransformer;
  627. SuperSampler: TSuperSampler;
  628. KernelResampler : TKernelResampler;
  629. begin
  630. Screen.Cursor := crHourGlass;
  631. KernelResampler := TKernelResampler.Create(Src);
  632. KernelResampler.KernelMode := KernelMode;
  633. // Normally this should be set higher.
  634. // It is set low here to display perceptual consequences
  635. KernelResampler.TableSize := 4;
  636. KernelResampler.Kernel := KERNELS[KernelIndex].Create;
  637. Transformer := TTransformer.Create(Src.Resampler, Remapper);
  638. SuperSampler := TSuperSampler.Create(Transformer);
  639. Rasterizer := TRegularRasterizer.Create;
  640. try
  641. Rasterizer.Sampler := SuperSampler;
  642. SuperSampler.SamplingX := SamplingGridSize;
  643. SuperSampler.SamplingY := SamplingGridSize;
  644. DstImg.Bitmap.FillRectS(SampleClipRect, 0);
  645. Rasterizer.Rasterize(DstImg.Bitmap, SampleClipRect, Src);
  646. SampleClipRect := Rect(MaxInt, MaxInt, -MaxInt, -MaxInt);
  647. finally
  648. Rasterizer.Free;
  649. SuperSampler.Free;
  650. Transformer.Free;
  651. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  652. Screen.Cursor := crDefault;
  653. DstImg.Repaint;
  654. end;
  655. end;
  656. procedure TMainForm.MnuBilinearWarpClick(Sender: TObject);
  657. begin
  658. RESAMPLERS[MnuBilinearWarp.Checked].Create(Src);
  659. Transform(DstImg.Bitmap, Src, Remapper);
  660. end;
  661. procedure TMainForm.MnuSamplingGridClick(Sender: TObject);
  662. begin
  663. if Sender is TMenuItem then
  664. SamplingGridSize := TMenuItem(Sender).Tag;
  665. end;
  666. procedure TMainForm.KernelChanged(Sender: TObject);
  667. begin
  668. if Sender is TMenuItem then
  669. begin
  670. KernelIndex := TMenuItem(Sender).Tag;
  671. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  672. MnuSuperSampleNowClick(Self);
  673. end;
  674. end;
  675. procedure TMainForm.BrushMeshPreviewResize(Sender: TObject);
  676. begin
  677. UpdateBrush;
  678. end;
  679. procedure TMainForm.SizeBarChange(Sender: TObject);
  680. begin
  681. DstImg.Repaint;
  682. BrushLayer.Radius := SizeBar.Position div 2;
  683. BrushLayer.Center := GR32.Point(DstImg.Width div 2, DstImg.Height div 2);
  684. end;
  685. procedure TMainForm.ImgButtonClick(Sender: TObject);
  686. begin
  687. if Sender is TToolbutton then
  688. TToolButton(Sender).DropdownMenu.Popup(Mouse.CursorPos.X,
  689. Mouse.CursorPos.Y);
  690. end;
  691. procedure TMainForm.DstImgPaintStage(Sender: TObject; Buffer: TBitmap32;
  692. StageNum: Cardinal);
  693. const //0..1
  694. Colors: array [Boolean] of TColor32 = ($FFFFFFFF, $FFB0B0B0);
  695. var
  696. R: TRect;
  697. I, J: Integer;
  698. OddY: Integer;
  699. TilesHorz, TilesVert: Integer;
  700. TileX, TileY: Integer;
  701. TileHeight, TileWidth: Integer;
  702. begin
  703. with TImgView32(Sender) do
  704. begin
  705. BeginUpdate;
  706. R := GetViewportRect;
  707. TileHeight := 8;
  708. TileWidth := 8;
  709. TilesHorz := (R.Right - R.Left) div TileWidth;
  710. TilesVert := (R.Bottom - R.Top) div TileHeight;
  711. TileY := 0;
  712. for J := 0 to TilesVert do
  713. begin
  714. TileX := 0;
  715. OddY := J and $1;
  716. for I := 0 to TilesHorz do
  717. begin
  718. Buffer.FillRectS(TileX, TileY, TileX + TileWidth, TileY +
  719. TileHeight,Colors[I and $1 = OddY]);
  720. Inc(TileX, TileWidth);
  721. end;
  722. Inc(TileY, TileHeight);
  723. end;
  724. EndUpdate;
  725. end;
  726. end;
  727. procedure TMainForm.MnuKernelModeClick(Sender: TObject);
  728. begin
  729. if Sender is TMenuItem then
  730. begin
  731. KernelMode := TKernelMode(TMenuItem(Sender).Tag);
  732. SampleClipRect := Remapper.VectorMap.GetTrimmedBounds;
  733. MnuSuperSampleNowClick(Self);
  734. end;
  735. end;
  736. procedure TMainForm.MnuFileExitClick(Sender: TObject);
  737. begin
  738. Close;
  739. end;
  740. end.