utooldeformationgrid.pas 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324
  1. // SPDX-License-Identifier: GPL-3.0-only
  2. unit UToolDeformationGrid;
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, Types, Math, SysUtils, utool, BGRABitmapTypes, BGRABitmap, UImage,
  7. UImageType, ULayerAction, LCVectorialFill;
  8. type
  9. { TToolDeformationGrid }
  10. TToolDeformationGrid = class(TGenericTool)
  11. private
  12. FCurrentBounds,FMergedBounds: TRect;
  13. procedure ReleaseGrid;
  14. function ToolDeformationGridNeeded: boolean;
  15. procedure ValidateDeformationGrid;
  16. protected
  17. class var ReturnHintShown: boolean;
  18. deformationGridNbX,deformationGridNbY,deformationGridX,deformationGridY: integer;
  19. deformationGridMoving: boolean;
  20. deformationOrigin: TPointF;
  21. DoingDeformation: boolean;
  22. deformationGrid: array of array of TPointF;
  23. deformationGridTexCoord: array of array of TPointF;
  24. function GetPointAt(const ptF: TPointF; var x,y: integer): boolean;
  25. function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
  26. {%H-}rightBtn: boolean): TRect; override;
  27. function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): Trect;
  28. override;
  29. function DoToolKeyDown(var key: Word): TRect; override;
  30. function GetIsSelectingTool: boolean; override;
  31. function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
  32. public
  33. class procedure ForgetHintShown;
  34. constructor Create(AManager: TToolManager); override;
  35. function ToolUp: TRect; override;
  36. function GetContextualToolbars: TContextualToolbars; override;
  37. function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; override;
  38. function ToolCommand(ACommand: TToolCommand): boolean; override;
  39. function ToolProvideCommand(ACommand: TToolCommand): boolean; override;
  40. destructor Destroy; override;
  41. end;
  42. { TToolTextureMapping }
  43. TToolTextureMapping = class(TGenericTool)
  44. private
  45. class var ScaleHintShown, ReturnHintShown: boolean;
  46. FCurrentBounds: TRect;
  47. FLastTexture: TBGRABitmap;
  48. FTextureAfterAlpha: TBGRABitmap;
  49. FAdaptedTexture: TBGRABitmap;
  50. FCanReadaptTexture: boolean;
  51. FHighQuality: boolean;
  52. procedure ToolQuadNeeded;
  53. procedure ValidateQuad; virtual;
  54. procedure DrawQuad; virtual;
  55. function GetAdaptedTexture: TBGRABitmap;
  56. procedure UpdateBoundsMode(var ARectResult: TRect);
  57. protected
  58. boundsMode: boolean;
  59. quadDefined: boolean;
  60. definingQuad: boolean;
  61. quad: array of TPointF;
  62. boundsPts: array of TPointF;
  63. quadMovingIndex: integer;
  64. quadMoving,quadMovingBounds: boolean;
  65. quadMovingDelta: TPointF;
  66. function SnapIfNecessary(const ptF: TPointF): TPointF;
  67. function GetClosestPoint(const ptF: TPointF; out pointFound: TPointF): integer;
  68. function DoToolDown({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF;
  69. {%H-}rightBtn: boolean): TRect; override;
  70. function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect;
  71. override;
  72. function DoToolKeyDown(var key: Word): TRect; override;
  73. function DoToolKeyUp(var key: Word): TRect; override;
  74. function GetIsSelectingTool: boolean; override;
  75. function GetTexture: TBGRABitmap; virtual;
  76. function GetTextureRepetition: TTextureRepetition; virtual;
  77. procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
  78. function ComputeBoundsPoints: ArrayOfTPointF;
  79. procedure PrepareBackground({%H-}toolDest: TBGRABitmap; AFirstTime: boolean); virtual;
  80. function DefaultTextureCenter: TPointF; virtual;
  81. function DoToolUpdate({%H-}toolDest: TBGRABitmap): TRect; override;
  82. function GetStatusText: string; override;
  83. function GetAllowedBackFillTypes: TVectorialFillTypes; override;
  84. public
  85. class procedure ForgetHintShown;
  86. constructor Create(AManager: TToolManager); override;
  87. function ToolUp: TRect; override;
  88. function GetContextualToolbars: TContextualToolbars; override;
  89. function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth, {%H-}VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction):TRect; override;
  90. function ToolProvideCommand(ACommand: TToolCommand): boolean; override;
  91. function ToolCommand(ACommand: TToolCommand): boolean; override;
  92. destructor Destroy; override;
  93. end;
  94. { TToolLayerMapping }
  95. TToolLayerMapping = class(TToolTextureMapping)
  96. protected
  97. FTexture: TBGRABitmap;
  98. FDefaultTextureCenter: TPointF;
  99. FAlreadyDrawnOnce: boolean;
  100. procedure PrepareTexture;
  101. procedure PrepareBackground(toolDest: TBGRABitmap; {%H-}AFirstTime: boolean); override;
  102. function GetTexture: TBGRABitmap; override;
  103. function DefaultTextureCenter: TPointF; override;
  104. function GetTextureRepetition: TTextureRepetition; override;
  105. procedure ValidateQuad; override;
  106. function GetAllowedBackFillTypes: TVectorialFillTypes; override;
  107. public
  108. constructor Create(AManager: TToolManager); override;
  109. function GetContextualToolbars: TContextualToolbars; override;
  110. destructor Destroy; override;
  111. end;
  112. implementation
  113. uses LCLType, ugraph, LCScaleDPI, LazPaintType, BGRAFillInfo, BGRATransform, Controls;
  114. { TToolLayerMapping }
  115. procedure TToolLayerMapping.PrepareTexture;
  116. var src: TBGRABitmap;
  117. bounds: TRect;
  118. begin
  119. if FTexture = nil then
  120. begin
  121. src := Action.BackupDrawingLayer;
  122. bounds := src.GetImageBounds;
  123. if IsRectEmpty(bounds) then
  124. bounds := rect(0,0,1,1);
  125. FTexture := src.GetPart(bounds) as TBGRABitmap;
  126. FDefaultTextureCenter := PointF((bounds.Left+bounds.Right)/2-0.5,(bounds.Top+bounds.Bottom)/2-0.5);
  127. end;
  128. end;
  129. procedure TToolLayerMapping.PrepareBackground(toolDest: TBGRABitmap;
  130. AFirstTime: boolean);
  131. var
  132. r: TRect;
  133. begin
  134. if not FAlreadyDrawnOnce then
  135. begin
  136. FAlreadyDrawnOnce := true;
  137. r := toolDest.GetImageBounds;
  138. end else
  139. r := FCurrentBounds;
  140. toolDest.FillRect(r, BGRAPixelTransparent, dmSet);
  141. Action.NotifyChange(toolDest, r);
  142. end;
  143. function TToolLayerMapping.GetTexture: TBGRABitmap;
  144. begin
  145. PrepareTexture;
  146. result := FTexture;
  147. end;
  148. function TToolLayerMapping.DefaultTextureCenter: TPointF;
  149. begin
  150. PrepareTexture;
  151. result := FDefaultTextureCenter;
  152. end;
  153. function TToolLayerMapping.GetTextureRepetition: TTextureRepetition;
  154. begin
  155. if poRepeat in Manager.PerspectiveOptions then
  156. Result:= trRepeatBoth
  157. else
  158. result:= trNone;
  159. end;
  160. procedure TToolLayerMapping.ValidateQuad;
  161. begin
  162. inherited ValidateQuad;
  163. Manager.QueryExitTool;
  164. end;
  165. function TToolLayerMapping.GetAllowedBackFillTypes: TVectorialFillTypes;
  166. begin
  167. Result:= [vftSolid,vftGradient,vftTexture];
  168. end;
  169. constructor TToolLayerMapping.Create(AManager: TToolManager);
  170. begin
  171. inherited Create(AManager);
  172. ToolQuadNeeded;
  173. end;
  174. function TToolLayerMapping.GetContextualToolbars: TContextualToolbars;
  175. begin
  176. Result:= [ctPerspective];
  177. end;
  178. destructor TToolLayerMapping.Destroy;
  179. begin
  180. FreeAndNil(FTexture);
  181. inherited Destroy;
  182. end;
  183. { TToolTextureMapping }
  184. procedure TToolTextureMapping.ToolQuadNeeded;
  185. var
  186. tx,ty: single;
  187. ratio,temp: single;
  188. center: TPointF;
  189. begin
  190. if not quadDefined and (GetTexture <> nil) and (GetTexture.Width > 0) and (GetTexture.Height > 0) then
  191. begin
  192. tx := GetTexture.Width;
  193. ty := GetTexture.Height;
  194. ratio := 1;
  195. if tx > Manager.Image.Width then
  196. ratio := Manager.Image.Width/tx;
  197. if ty > Manager.Image.Height then
  198. begin
  199. temp := Manager.Image.Height/ty;
  200. if temp < ratio then ratio := temp;
  201. end;
  202. if ratio > 0 then
  203. begin
  204. setlength(quad,4);
  205. center := DefaultTextureCenter;
  206. quad[0] := PointF(round(center.x-tx*ratio/2+0.5)-0.5,round(center.y -ty*ratio/2 + 0.5)-0.5);
  207. quad[1] := PointF(quad[0].x + tx*ratio,quad[0].y);
  208. quad[2] := PointF(quad[1].x, quad[1].Y + ty*ratio);
  209. quad[3] := PointF(quad[0].x, quad[2].y);
  210. quadDefined:= true;
  211. PrepareBackground(GetToolDrawingLayer, True);
  212. DrawQuad;
  213. Action.NotifyChange(GetToolDrawingLayer, FCurrentBounds);
  214. end;
  215. end;
  216. end;
  217. procedure TToolTextureMapping.ValidateQuad;
  218. begin
  219. if quadDefined then
  220. begin
  221. if Manager.Image.Width*Manager.Image.Height <= 786432 then
  222. begin
  223. PrepareBackground(GetToolDrawingLayer,False);
  224. FHighQuality := true;
  225. FCanReadaptTexture:= true;
  226. DrawQuad;
  227. FCanReadaptTexture:= false;
  228. FHighQuality := false;
  229. Action.NotifyChange(GetToolDrawingLayer, FCurrentBounds);
  230. end;
  231. ValidateAction;
  232. quadDefined := false;
  233. quad := nil;
  234. FLastTexture.FreeReference;
  235. FLastTexture := nil;
  236. end;
  237. end;
  238. procedure TToolTextureMapping.DrawQuad;
  239. const OversampleQuality = 2;
  240. var
  241. tex: TBGRABitmap;
  242. persp: TBGRAPerspectiveScannerTransform;
  243. dest: TBGRABitmap;
  244. quadHQ: array of TPointF;
  245. i: integer;
  246. scanRepeat: TBGRABitmapScanner;
  247. scan: IBGRAScanner;
  248. function AlmostInt(value: single): boolean;
  249. begin
  250. result := (value-round(value)) < 1e-6;
  251. end;
  252. begin
  253. if quadDefined then
  254. begin
  255. if (quad[1].y = quad[0].y) and (quad[3].x = quad[0].x) and (quad[2].x = quad[1].x) and (quad[3].y = quad[2].y) and
  256. AlmostInt(quad[0].x+0.5) and AlmostInt(quad[0].y+0.5) and AlmostInt(quad[2].x+0.5) and AlmostInt(quad[2].y+0.5) and
  257. (round(quad[2].x-quad[0].x) = GetTexture.Width) and (round(quad[2].y-quad[0].y) = GetTexture.Height) then
  258. FHighQuality := false;
  259. tex := GetAdaptedTexture;
  260. if tex <> nil then
  261. begin
  262. if GetTextureRepetition <> trNone then
  263. FCurrentBounds := rect(0,0,Manager.Image.Width,Manager.Image.Height)
  264. else
  265. FCurrentBounds := GetShapeBounds([quad[0],quad[1],quad[2],quad[3]],1);
  266. if FHighQuality then
  267. begin
  268. dest := TBGRABitmap.Create(FCurrentBounds.Width*OversampleQuality,FCurrentBounds.Height*OversampleQuality);
  269. quadHQ := nil;
  270. setlength(quadHQ, length(quad));
  271. for i := 0 to high(quad) do quadHQ[i] := (quad[i]+PointF(0.5,0.5))*OversampleQuality - PointF(0.5,0.5) - PointF(FCurrentBounds.TopLeft)*OversampleQuality;
  272. end
  273. else
  274. begin
  275. dest := GetToolDrawingLayer;
  276. quadHQ := quad;
  277. dest.ClipRect := FCurrentBounds;
  278. end;
  279. if GetTextureRepetition <> trNone then
  280. begin
  281. if GetTextureRepetition <> trRepeatBoth then
  282. begin
  283. scanRepeat := TBGRABitmapScanner.Create(tex,
  284. GetTextureRepetition in [trRepeatX,trRepeatBoth],
  285. GetTextureRepetition in [trRepeatY,trRepeatBoth], Point(0,0) );
  286. scan := scanRepeat;
  287. end else
  288. begin
  289. scanRepeat := nil;
  290. scan := tex;
  291. end;
  292. persp := TBGRAPerspectiveScannerTransform.Create(scan,[PointF(-0.5,-0.5),PointF(tex.Width-0.5,-0.5),
  293. PointF(tex.Width-0.5,tex.Height-0.5),PointF(-0.5,tex.Height-0.5)],quadHQ);
  294. persp.IncludeOppositePlane := poTwoPlanes in Manager.PerspectiveOptions;
  295. dest.FillRect(0,0,dest.Width,dest.Height,persp,dmDrawWithTransparency);
  296. persp.Free;
  297. scan := nil;
  298. scanRepeat.Free;
  299. end else
  300. begin
  301. dest.FillQuadPerspectiveMappingAntialias(quadHQ[0],quadHQ[1],quadHQ[2],quadHQ[3],tex,PointF(-0.5,-0.5),PointF(tex.Width-0.5,-0.5),
  302. PointF(tex.Width-0.5,tex.Height-0.5),PointF(-0.5,tex.Height-0.5), rect(0,0,tex.Width,tex.Height));
  303. end;
  304. if FHighQuality then
  305. begin
  306. BGRAReplace(dest, dest.Resample(dest.Width div OversampleQuality, dest.Height div OversampleQuality,rmSimpleStretch));
  307. BGRAReplace(dest, dest.FilterSharpen(96/256));
  308. GetToolDrawingLayer.PutImage(FCurrentBounds.Left,FCurrentBounds.Top,dest,dmDrawWithTransparency);
  309. FreeAndNil(dest);
  310. end else
  311. dest.NoClip;
  312. end;
  313. end
  314. else
  315. FCurrentBounds := EmptyRect;
  316. end;
  317. function TToolTextureMapping.GetAdaptedTexture: TBGRABitmap;
  318. var tx,ty: integer;
  319. precisionFactor: single;
  320. begin
  321. if GetTextureRepetition <> trNone then //cannot optimize size
  322. begin
  323. result := GetTexture;
  324. exit;
  325. end;
  326. if GetTexture = nil then
  327. begin
  328. result := nil;
  329. exit;
  330. end else
  331. begin
  332. if FHighQuality then precisionFactor := 3
  333. else precisionFactor:= 1.5;
  334. tx := ceil(Max(VectLen(quad[1]-quad[0]),VectLen(quad[2]-quad[3]))*precisionFactor);
  335. ty := ceil(Max(VectLen(quad[2]-quad[1]),VectLen(quad[3]-quad[0]))*precisionFactor);
  336. if tx < 1 then tx := 1;
  337. if ty < 1 then ty := 1;
  338. if tx > GetTexture.Width then tx := GetTexture.Width;
  339. if ty > GetTexture.Height then ty := GetTexture.Height;
  340. if (tx = GetTexture.Width) and (ty = GetTexture.Height) then
  341. begin
  342. result := GetTexture;
  343. exit;
  344. end;
  345. if (FAdaptedTexture = nil) or FCanReadaptTexture then
  346. begin
  347. if (FAdaptedTexture <> nil) and ((FAdaptedTexture.Width <> tx) or (FAdaptedTexture.Height <> ty)) then
  348. FreeAndNil(FAdaptedTexture);
  349. if FAdaptedTexture = nil then
  350. begin
  351. GetTexture.ResampleFilter := rfLinear;
  352. FAdaptedTexture := GetTexture.Resample(tx,ty,rmFineResample) as TBGRABitmap;
  353. end;
  354. end;
  355. result := FAdaptedTexture;
  356. exit;
  357. end;
  358. end;
  359. procedure TToolTextureMapping.UpdateBoundsMode(var ARectResult: TRect);
  360. begin
  361. if not boundsMode and not quadMoving and ([ssAlt, ssShift]*ShiftState <> []) then
  362. begin
  363. boundsMode := true;
  364. boundsPts := ComputeBoundsPoints;
  365. if IsRectEmpty(ARectResult) then
  366. ARectResult := OnlyRenderChange;
  367. end else
  368. if boundsMode and not quadMoving and ([ssAlt, ssShift]*ShiftState = []) then
  369. begin
  370. boundsMode := false;
  371. boundsPts := ComputeBoundsPoints;
  372. if IsRectEmpty(ARectResult) then
  373. ARectResult := OnlyRenderChange;
  374. end;
  375. end;
  376. function TToolTextureMapping.SnapIfNecessary(const ptF: TPointF): TPointF;
  377. begin
  378. if not (ssSnap in ShiftState) then result := ptF else
  379. result := PointF(round(ptF.X),round(ptF.Y));
  380. end;
  381. function TToolTextureMapping.GetClosestPoint(const ptF: TPointF; out pointFound: TPointF): integer;
  382. var
  383. minDist, curDist: single;
  384. pts: array of TPointF;
  385. n: Integer;
  386. begin
  387. if boundsMode then
  388. pts := boundsPts
  389. else
  390. pts := quad;
  391. result := -1;
  392. pointFound := EmptyPointF;
  393. minDist := sqr(DoScaleX(10,OriginalDPI));
  394. for n := 0 to high(pts) do
  395. begin
  396. curDist := sqr(ptF.x-pts[n].x)+sqr(ptF.y-pts[n].y);
  397. if curDist < minDist then
  398. begin
  399. minDist := curDist;
  400. result := n;
  401. pointFound := pts[n];
  402. end;
  403. end;
  404. end;
  405. function TToolTextureMapping.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
  406. ptF: TPointF; rightBtn: boolean): TRect;
  407. var
  408. n: Integer;
  409. selPt: TPointF;
  410. begin
  411. result := EmptyRect;
  412. if rightBtn then exit;
  413. if not quadDefined then
  414. begin
  415. if not definingQuad then
  416. begin
  417. if GetTexture = nil then
  418. Manager.ToolPopup(tpmNothingToBeDeformed)
  419. else
  420. begin
  421. definingQuad := true;
  422. setlength(quad,4);
  423. quad[0] := ptF;
  424. quad[1] := ptF;
  425. quad[2] := ptF;
  426. quad[3] := ptF;
  427. end;
  428. end;
  429. exit;
  430. end;
  431. UpdateBoundsMode(result);
  432. n := GetClosestPoint(ptF, selPt);
  433. if n <> -1 then
  434. begin
  435. quadMovingIndex := n;
  436. quadMovingDelta := selPt-PtF;
  437. quadMoving := True;
  438. quadMovingBounds := boundsMode;
  439. end else
  440. if IsPointInPolygon(quad, ptF, true) then
  441. begin
  442. quadMovingIndex := -1;
  443. quadMovingDelta := (quad[0]+quad[2])*0.5-ptF;
  444. quadMoving := true;
  445. quadMovingBounds := boundsMode;
  446. end;
  447. end;
  448. function NonZero(AValue, ADefault: single): single;
  449. begin
  450. if AValue = 0 then result := ADefault
  451. else result := AValue;
  452. end;
  453. function TToolTextureMapping.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
  454. ptF: TPointF): TRect;
  455. var n: integer;
  456. delta,prevSize,newSize,selPt: TPointF;
  457. curBounds: array of TPointF;
  458. ratioX,ratioY,ratio: single;
  459. avgSize: single;
  460. begin
  461. if definingQuad then
  462. begin
  463. if ssShift in ShiftState then
  464. begin
  465. if (GetTexture <> nil) and (GetTexture.Height <> 0)
  466. and (GetTexture.Width <> 0) then
  467. begin
  468. ratio := GetTexture.Width/GetTexture.Height;
  469. newSize := ptF - quad[0];
  470. avgSize := (abs(newSize.x)+abs(newSize.y))/2;
  471. ptF.x := quad[0].x+avgSize*NonZero(sign(newSize.x),1)*ratio/((ratio+1)/2);
  472. ptF.y := quad[0].y+avgSize*NonZero(sign(newSize.y),1)*1/((ratio+1)/2);
  473. end;
  474. end;
  475. quad[2] := ptF;
  476. quad[1].x := ptF.x;
  477. quad[3].y := ptF.y;
  478. result := OnlyRenderChange;
  479. exit;
  480. end;
  481. result := EmptyRect;
  482. if not ScaleHintShown then
  483. begin
  484. Manager.ToolPopup(tpmHoldKeysScaleMode, VK_SHIFT);
  485. ScaleHintShown:= true;
  486. end;
  487. if quadMoving then
  488. begin
  489. if quadMovingIndex = -1 then
  490. begin
  491. delta := SnapIfNecessary(quadMovingDelta + ptF) - ((quad[0]+quad[2])*0.5);
  492. for n := 0 to high(quad) do
  493. quad[n] += delta;
  494. if quadMovingBounds then boundsPts := ComputeBoundsPoints;
  495. end
  496. else
  497. if quadMovingBounds then
  498. begin
  499. boundsPts[quadMovingIndex] := SnapIfNecessary(quadMovingDelta + ptF);
  500. case quadMovingIndex of
  501. 0:begin
  502. boundsPts[1].y := boundsPts[quadMovingIndex].y;
  503. boundsPts[3].x := boundsPts[quadMovingIndex].x;
  504. end;
  505. 1:begin
  506. boundsPts[0].y := boundsPts[quadMovingIndex].y;
  507. boundsPts[2].x := boundsPts[quadMovingIndex].x;
  508. end;
  509. 2:begin
  510. boundsPts[3].y := boundsPts[quadMovingIndex].y;
  511. boundsPts[1].x := boundsPts[quadMovingIndex].x;
  512. end;
  513. 3:begin
  514. boundsPts[2].y := boundsPts[quadMovingIndex].y;
  515. boundsPts[0].x := boundsPts[quadMovingIndex].x;
  516. end;
  517. end;
  518. if ssShift in ShiftState then
  519. begin
  520. curBounds := ComputeBoundsPoints;
  521. prevSize := curBounds[2]-curBounds[0];
  522. newSize := boundsPts[2]-boundsPts[0];
  523. if (abs(prevSize.x) > 1e-6) and (abs(prevSize.y) > 1e-6) then
  524. begin
  525. ratioX := abs(newSize.X/prevSize.X);
  526. ratioY := abs(newSize.Y/prevSize.Y);
  527. ratio := (ratioX+ratioY)/2;
  528. newSize.X := abs(prevSize.X)*ratio*NonZero(Sign(newSize.X),1);
  529. newSize.Y := abs(prevSize.Y)*ratio*NonZero(Sign(newSize.Y),1);
  530. case quadMovingIndex of
  531. 0: boundsPts[0] := boundsPts[2]-newSize;
  532. 1: boundsPts[1] := boundsPts[3]+PointF(newSize.X,-newSize.Y);
  533. 2: boundsPts[2] := boundsPts[0]+newSize;
  534. 3: boundsPts[3] := boundsPts[1]+PointF(-newSize.X,newSize.Y);
  535. end;
  536. case quadMovingIndex of
  537. 0:begin
  538. boundsPts[1].y := boundsPts[quadMovingIndex].y;
  539. boundsPts[3].x := boundsPts[quadMovingIndex].x;
  540. end;
  541. 1:begin
  542. boundsPts[0].y := boundsPts[quadMovingIndex].y;
  543. boundsPts[2].x := boundsPts[quadMovingIndex].x;
  544. end;
  545. 2:begin
  546. boundsPts[3].y := boundsPts[quadMovingIndex].y;
  547. boundsPts[1].x := boundsPts[quadMovingIndex].x;
  548. end;
  549. 3:begin
  550. boundsPts[2].y := boundsPts[quadMovingIndex].y;
  551. boundsPts[0].x := boundsPts[quadMovingIndex].x;
  552. end;
  553. end;
  554. end;
  555. end;
  556. end
  557. else
  558. quad[quadMovingIndex] := SnapIfNecessary(quadMovingDelta + ptF);
  559. PrepareBackground(toolDest,False);
  560. DrawQuad;
  561. result := FCurrentBounds;
  562. end;
  563. UpdateBoundsMode(result);
  564. if not quadMoving then
  565. begin
  566. if GetClosestPoint(ptF, selPt) <> -1 then
  567. Cursor := crSizeAll
  568. else
  569. Cursor := crDefault;
  570. end;
  571. end;
  572. function TToolTextureMapping.GetIsSelectingTool: boolean;
  573. begin
  574. Result:= false;
  575. end;
  576. function TToolTextureMapping.GetTexture: TBGRABitmap;
  577. begin
  578. if (Manager.BackFill.Texture = nil) or (Manager.BackFill.Texture = FLastTexture) then
  579. begin
  580. if FTextureAfterAlpha <> nil then
  581. result := FTextureAfterAlpha
  582. else
  583. result := FLastTexture;
  584. end
  585. else
  586. begin
  587. if (Manager.BackFill.Texture <> nil) and (Manager.BackFill.TextureOpacity <> 255) then
  588. begin
  589. FTextureAfterAlpha := Manager.BackFill.Texture.Duplicate as TBGRABitmap;
  590. FTextureAfterAlpha.ApplyGlobalOpacity(Manager.BackFill.TextureOpacity);
  591. result := FTextureAfterAlpha;
  592. end else
  593. begin
  594. result := Manager.BackFill.Texture;
  595. FreeAndNil(FTextureAfterAlpha);
  596. end;
  597. FLastTexture.FreeReference;
  598. FLastTexture := Manager.BackFill.Texture.NewReference as TBGRABitmap;
  599. end;
  600. end;
  601. function TToolTextureMapping.GetTextureRepetition: TTextureRepetition;
  602. begin
  603. if Manager.BackFill.FillType = vftTexture then
  604. result := Manager.BackFill.TextureRepetition
  605. else
  606. result := trNone;
  607. end;
  608. procedure TToolTextureMapping.OnTryStop(sender: TCustomLayerAction);
  609. begin
  610. //nothing
  611. end;
  612. function TToolTextureMapping.ComputeBoundsPoints: ArrayOfTPointF;
  613. var
  614. minPt,maxPt: TPointF;
  615. i: integer;
  616. begin
  617. if quadDefined then
  618. begin
  619. minPt := quad[low(quad)];
  620. maxPt := quad[low(quad)];
  621. for i := 1 to high(quad) do
  622. begin
  623. if quad[i].x < minPt.X then minPt.x := quad[i].x;
  624. if quad[i].x > maxPt.X then maxPt.x := quad[i].x;
  625. if quad[i].y < minPt.y then minPt.y := quad[i].y;
  626. if quad[i].y > maxPt.y then maxPt.y := quad[i].y;
  627. end;
  628. result := PointsF([minPt, PointF(maxPt.X,minPt.Y), maxPt, PointF(MinPt.X,MaxPt.Y)]);
  629. end else
  630. result := nil;
  631. end;
  632. procedure TToolTextureMapping.PrepareBackground(toolDest: TBGRABitmap;
  633. AFirstTime: boolean);
  634. begin
  635. if not AFirstTime then RestoreBackupDrawingLayer;
  636. end;
  637. function TToolTextureMapping.DefaultTextureCenter: TPointF;
  638. begin
  639. result := PointF(Manager.Image.Width/2-0.5-LayerOffset.X,Manager.Image.Height/2-0.5-LayerOffset.Y);
  640. end;
  641. function TToolTextureMapping.DoToolUpdate(toolDest: TBGRABitmap): TRect;
  642. begin
  643. if quadDefined then
  644. begin
  645. PrepareBackground(GetToolDrawingLayer,False);
  646. DrawQuad;
  647. result := FCurrentBounds;
  648. end
  649. else
  650. result := EmptyRect;
  651. end;
  652. function TToolTextureMapping.GetStatusText: string;
  653. var
  654. i: Integer;
  655. begin
  656. result := '';
  657. for i := 0 to high(quad) do
  658. begin
  659. if i > 0 then result += '|';
  660. result += 'x'+inttostr(i+1)+' = '+inttostr(round(quad[i].x+0.5))+'|'+
  661. 'y'+inttostr(i+1)+' = '+inttostr(round(quad[i].y+0.5));
  662. end;
  663. end;
  664. function TToolTextureMapping.GetAllowedBackFillTypes: TVectorialFillTypes;
  665. begin
  666. Result:= [vftTexture];
  667. end;
  668. class procedure TToolTextureMapping.ForgetHintShown;
  669. begin
  670. ScaleHintShown:= false;
  671. ReturnHintShown:= false;
  672. end;
  673. constructor TToolTextureMapping.Create(AManager: TToolManager);
  674. begin
  675. inherited Create(AManager);
  676. FCurrentBounds := EmptyRect;
  677. FHighQuality:= False;
  678. FLastTexture := nil;
  679. quadDefined:= false;
  680. definingQuad:= false;
  681. end;
  682. function TToolTextureMapping.DoToolKeyDown(var key: Word): TRect;
  683. begin
  684. result := EmptyRect;
  685. if Key = VK_RETURN then
  686. begin
  687. if quadDefined then
  688. begin
  689. ValidateQuad;
  690. result := EmptyRect;
  691. key := 0;
  692. end;
  693. end else
  694. if Key = VK_ESCAPE then
  695. begin
  696. if quadDefined then
  697. begin
  698. CancelActionPartially;
  699. result := OnlyRenderChange;
  700. manager.QueryExitTool;
  701. key := 0;
  702. end;
  703. end else
  704. if (Key = VK_SHIFT) or (Key = VK_MENU) then
  705. UpdateBoundsMode(result);
  706. end;
  707. function TToolTextureMapping.DoToolKeyUp(var key: Word): TRect;
  708. begin
  709. Result:= EmptyRect;
  710. if (Key = VK_SHIFT) or (Key = VK_MENU) then
  711. UpdateBoundsMode(result);
  712. end;
  713. function TToolTextureMapping.ToolUp: TRect;
  714. var prevSize,newSize: TPointF;
  715. oldBounds: array of TPointF;
  716. i: integer;
  717. redraw: boolean;
  718. begin
  719. if definingQuad then
  720. begin
  721. definingQuad:= false;
  722. quadDefined:= true;
  723. PrepareBackground(GetToolDrawingLayer,False);
  724. FCanReadaptTexture:= true;
  725. DrawQuad;
  726. FCanReadaptTexture:= false;
  727. result := FCurrentBounds;
  728. if not ReturnHintShown then
  729. begin
  730. Manager.ToolPopup(tpmreturnValides);
  731. ReturnHintShown:= true;
  732. end;
  733. exit;
  734. end;
  735. if quadMoving then
  736. begin
  737. redraw := GetTextureRepetition = trNone;
  738. if quadMovingBounds then
  739. begin
  740. oldBounds := ComputeBoundsPoints;
  741. prevSize := oldBounds[2]-oldBounds[0];
  742. newSize := boundsPts[2]-boundsPts[0];
  743. if (abs(newSize.x) > 1e-6) and (abs(newSize.y) > 1e-6) and
  744. (abs(prevSize.x) > 1e-6) and (abs(prevSize.y) > 1e-6) then
  745. begin
  746. for i := low(quad) to high(quad) do
  747. begin
  748. quad[i] -= oldBounds[0];
  749. quad[i].x *= newSize.X/prevSize.X;
  750. quad[i].y *= newSize.Y/prevSize.Y;
  751. quad[i] += boundsPts[0];
  752. end;
  753. end;
  754. quadMovingBounds := false;
  755. boundsPts := ComputeBoundsPoints;
  756. redraw := true;
  757. end;
  758. if redraw then
  759. begin
  760. PrepareBackground(GetToolDrawingLayer,False);
  761. FCanReadaptTexture:= true;
  762. DrawQuad;
  763. FCanReadaptTexture:= false;
  764. result := FCurrentBounds;
  765. end else
  766. result := EmptyRect;
  767. quadMoving := false;
  768. end else
  769. result := EmptyRect;
  770. end;
  771. function TToolTextureMapping.GetContextualToolbars: TContextualToolbars;
  772. begin
  773. Result:= [ctBackFill,ctPerspective];
  774. end;
  775. function TToolTextureMapping.Render(VirtualScreen: TBGRABitmap;
  776. VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
  777. procedure DrawPoints(pts: array of TPointF; alpha: byte);
  778. var curPt,nextPt: TPointF;
  779. n: Integer;
  780. begin
  781. For n := 0 to high(pts) do
  782. begin
  783. curPt := BitmapToVirtualScreen(pts[n]);
  784. nextPt := BitmapToVirtualScreen(pts[(n+1)mod length(pts)]);
  785. NiceLine(VirtualScreen, curPt.X,curPt.Y,nextPt.x,nextPt.y,alpha);
  786. end;
  787. For n := 0 to high(pts) do
  788. begin
  789. curPt := BitmapToVirtualScreen(pts[n]);
  790. result := RectUnion(result,NicePoint(VirtualScreen, curPt.X,curPt.Y,alpha));
  791. end;
  792. end;
  793. begin
  794. result := EmptyRect;
  795. if not quadDefined and not definingQuad then exit;
  796. if boundsMode or quadMovingBounds then
  797. begin
  798. DrawPoints(quad,80);
  799. DrawPoints(boundsPts,192);
  800. end else
  801. DrawPoints(quad,192);
  802. end;
  803. function TToolTextureMapping.ToolProvideCommand(ACommand: TToolCommand
  804. ): boolean;
  805. begin
  806. case ACommand of
  807. tcFinish: result := quadDefined;
  808. else result := false;
  809. end;
  810. end;
  811. function TToolTextureMapping.ToolCommand(ACommand: TToolCommand): boolean;
  812. begin
  813. case ACommand of
  814. tcFinish: if quadDefined then
  815. begin
  816. ValidateQuad;
  817. result := true;
  818. end else
  819. result := false;
  820. else result := false;
  821. end;
  822. end;
  823. destructor TToolTextureMapping.Destroy;
  824. begin
  825. ValidateAction;
  826. FLastTexture.FreeReference;
  827. FreeAndNil(FTextureAfterAlpha);
  828. FreeAndNil(FAdaptedTexture);
  829. inherited Destroy;
  830. end;
  831. { TToolDeformationGrid }
  832. function TToolDeformationGrid.ToolDeformationGridNeeded: boolean;
  833. var xb,yb: integer;
  834. layer: TBGRABitmap;
  835. begin
  836. if (DeformationGrid = nil) then
  837. begin
  838. layer := GetToolDrawingLayer;
  839. if layer = nil then
  840. begin
  841. result := false;
  842. exit;
  843. end;
  844. deformationGridNbX:= Manager.DeformationGridNbX;
  845. deformationGridNbY:= Manager.DeformationGridNbY;
  846. SetLength(DeformationGrid, deformationGridNbY, deformationGridNbX);
  847. SetLength(DeformationGridTexCoord, deformationGridNbY, deformationGridNbX);
  848. for yb := 0 to deformationGridNbY-1 do
  849. for xb := 0 to deformationGridNbX-1 do
  850. begin
  851. DeformationGridTexCoord[yb,xb] := PointF(xb/(deformationGridNbX-1)*layer.Width-0.5,
  852. yb/(deformationGridNbY-1)*layer.Height-0.5);
  853. DeformationGrid[yb,xb] :=DeformationGridTexCoord[yb,xb];
  854. end;
  855. end;
  856. result := true;
  857. end;
  858. function TToolDeformationGrid.ToolCommand(ACommand: TToolCommand): boolean;
  859. begin
  860. case ACommand of
  861. tcFinish: if DoingDeformation then
  862. begin
  863. ValidateDeformationGrid;
  864. result := true;
  865. end
  866. else result := false;
  867. else result := false;
  868. end;
  869. end;
  870. function TToolDeformationGrid.ToolProvideCommand(ACommand: TToolCommand
  871. ): boolean;
  872. begin
  873. case ACommand of
  874. tcFinish: result := DoingDeformation;
  875. else result := false;
  876. end;
  877. end;
  878. destructor TToolDeformationGrid.Destroy;
  879. begin
  880. ValidateDeformationGrid;
  881. inherited Destroy;
  882. end;
  883. procedure TToolDeformationGrid.ReleaseGrid;
  884. var
  885. xb,yb: Integer;
  886. begin
  887. if DoingDeformation then
  888. begin
  889. ValidateAction;
  890. DoingDeformation := false;
  891. for yb := 0 to deformationGridNbY-2 do
  892. for xb := 0 to deformationGridNbX-2 do
  893. DeformationGridTexCoord[yb,xb] := DeformationGrid[yb,xb];
  894. end;
  895. end;
  896. procedure TToolDeformationGrid.ValidateDeformationGrid;
  897. begin
  898. if DoingDeformation then
  899. begin
  900. DeformationGrid := nil;
  901. DeformationGridTexCoord := nil;
  902. ValidateAction;
  903. DoingDeformation := false;
  904. end;
  905. end;
  906. function TToolDeformationGrid.GetPointAt(const ptF: TPointF; var x, y: integer): boolean;
  907. var
  908. yb, xb: Integer;
  909. curDist, minDist: single;
  910. begin
  911. result := false;
  912. minDist := sqr(SelectionMaxPointDistance);
  913. for yb := 1 to deformationGridNbY-2 do
  914. for xb := 1 to deformationGridNbX-2 do
  915. begin
  916. curDist := sqr(ptF.x-DeformationGrid[yb,xb].x) + sqr(ptF.y-DeformationGrid[yb,xb].y);
  917. if curDist < minDist then
  918. begin
  919. minDist := curDist;
  920. x := xb;
  921. y := yb;
  922. result := True;
  923. end;
  924. end;
  925. end;
  926. function TToolDeformationGrid.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
  927. ptF: TPointF; rightBtn: boolean): TRect;
  928. begin
  929. result := EmptyRect;
  930. deformationGridX := 1;
  931. deformationGridY := 1;
  932. if DeformationGrid <> nil then
  933. begin
  934. if GetPointAt(ptF, deformationGridX, deformationGridY) then
  935. begin
  936. deformationGridMoving := True;
  937. deformationOrigin := ptF;
  938. end;
  939. end;
  940. end;
  941. function TToolDeformationGrid.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
  942. ptF: TPointF): Trect;
  943. var xb,yb,NbX,NbY: integer;
  944. gridDone: array of array of boolean;
  945. layer,backupLayer : TBGRABitmap;
  946. PreviousClipRect: TRect;
  947. previousBounds: TRect;
  948. gridMinX,gridMinY,gridMaxX,gridMaxY, dummyX, dummyY: integer;
  949. procedure AddToDeformationArea(xi,yi: integer);
  950. var ptF: TPointF;
  951. pix: TRect;
  952. begin
  953. if (xi >= 0) and (yi >= 0) and (xi < NbX) and (yi < NbY) then
  954. begin
  955. ptF := deformationGrid[yi,xi];
  956. pix := rect(floor(ptF.X)-1,floor(ptF.Y)-1,ceil(ptF.X)+2,ceil(ptF.Y)+2);
  957. if IsRectEmpty(FCurrentBounds) then
  958. FCurrentBounds := pix
  959. else
  960. UnionRect(FCurrentBounds,FCurrentBounds,pix);
  961. end;
  962. end;
  963. begin
  964. result := EmptyRect;
  965. if not deformationGridMoving then
  966. begin
  967. dummyX := 1;
  968. dummyY := 1;
  969. if GetPointAt(ptF, dummyX, dummyY) then
  970. Cursor := crHandPoint
  971. else Cursor := crDefault;
  972. exit;
  973. end;
  974. if Manager.DeformationGridMode = gmMovePointWithoutDeformation then
  975. begin
  976. ReleaseGrid;
  977. DeformationGrid[deformationGridY,deformationGridX] := PointF(
  978. DeformationGrid[deformationGridY,deformationGridX].X + ptF.X-deformationOrigin.X,
  979. DeformationGrid[deformationGridY,deformationGridX].Y + ptF.Y-deformationOrigin.Y);
  980. DeformationGridTexCoord[deformationGridY,deformationGridX] := DeformationGrid[deformationGridY,deformationGridX];
  981. result := OnlyRenderChange;
  982. end else
  983. begin
  984. if not DoingDeformation then
  985. begin
  986. FCurrentBounds := EmptyRect;
  987. DoingDeformation := True;
  988. end;
  989. layer := GetToolDrawingLayer;
  990. backupLayer := GetBackupLayerIfExists;
  991. NbX := deformationGridNbX;
  992. NbY := deformationGridNbY;
  993. DeformationGrid[deformationGridY,deformationGridX] := PointF(
  994. DeformationGrid[deformationGridY,deformationGridX].X + ptF.X-deformationOrigin.X,
  995. DeformationGrid[deformationGridY,deformationGridX].Y + ptF.Y-deformationOrigin.Y);
  996. previousBounds := FCurrentBounds;
  997. FCurrentBounds := EmptyRect;
  998. gridMinX := deformationGridX-1;
  999. if gridMinX < 0 then gridMinX := 0;
  1000. gridMinY := deformationGridY-1;
  1001. if gridMinY < 0 then gridMinY := 0;
  1002. gridMaxX := deformationGridX+1;
  1003. if gridMaxX > NbX-1 then gridMaxX := NbX-1;
  1004. gridMaxY := deformationGridY+1;
  1005. if gridMaxY > NbY-1 then gridMaxY := NbY-1;
  1006. for yb := gridMinY to gridMaxY do
  1007. for xb := gridMinX to gridMaxX do
  1008. AddToDeformationArea(xb,yb);
  1009. FMergedBounds := RectUnion(previousBounds,FCurrentBounds);
  1010. gridMinX := 0;
  1011. gridMinY := 0;
  1012. gridMaxX := NbX-1;
  1013. gridMaxY := NbY-1;
  1014. //progressive drawing of deformation zones
  1015. gridDone := nil;
  1016. setlength(gridDone,NbY-1,NbX-1);
  1017. for yb := gridMinY to gridMaxY-1 do
  1018. for xb := gridMinX to gridMaxX-1 do
  1019. gridDone[yb,xb] := false;
  1020. if not IsRectEmpty(FMergedBounds) and (backupLayer <>nil) then
  1021. begin
  1022. PreviousClipRect := layer.ClipRect;
  1023. layer.ClipRect := FMergedBounds;
  1024. layer.FillRect(0,0,layer.Width,layer.Height,BGRAPixelTransparent,dmSet);
  1025. //drawing zones that are not deformed
  1026. for yb := gridMinY to gridMaxY-1 do
  1027. for xb := gridMinX to gridMaxX-1 do
  1028. if (DeformationGrid[yb,xb] = DeformationGridTexCoord[yb,xb]) and
  1029. (DeformationGrid[yb,xb+1] = DeformationGridTexCoord[yb,xb+1]) and
  1030. (DeformationGrid[yb+1,xb+1] = DeformationGridTexCoord[yb+1,xb+1]) and
  1031. (DeformationGrid[yb+1,xb] = DeformationGridTexCoord[yb+1,xb]) then
  1032. begin
  1033. layer.FillPoly([DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1034. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb]],backupLayer,dmDrawWithTransparency);
  1035. gridDone[yb,xb] := true;
  1036. end;
  1037. //drawing zones that are inverted
  1038. for yb := gridMinY to gridMaxY-1 do
  1039. for xb := gridMinX to gridMaxX-1 do
  1040. if not gridDone[yb,xb] and
  1041. not IsMostlyClockwise([DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1042. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb]]) then
  1043. begin
  1044. layer.FillQuadLinearMapping(DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1045. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb],backupLayer,
  1046. DeformationGridTexCoord[yb,xb],DeformationGridTexCoord[yb,xb+1],DeformationGridTexCoord[yb+1,xb+1],
  1047. DeformationGridTexCoord[yb+1,xb],true, fcKeepCW);
  1048. gridDone[yb,xb] := true;
  1049. end;
  1050. //drawing zones that are intersecting
  1051. for yb := gridMinY to gridMaxY-1 do
  1052. for xb := gridMinX to gridMaxX-1 do
  1053. if not gridDone[yb,xb] and
  1054. DoesQuadIntersect(DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1055. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb]) then
  1056. begin
  1057. layer.FillQuadLinearMapping(DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1058. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb],backupLayer,
  1059. DeformationGridTexCoord[yb,xb],DeformationGridTexCoord[yb,xb+1],DeformationGridTexCoord[yb+1,xb+1],
  1060. DeformationGridTexCoord[yb+1,xb],true, fcKeepCW);
  1061. gridDone[yb,xb] := true;
  1062. end;
  1063. //drawing zones that are concave
  1064. for yb := gridMinY to gridMaxY-1 do
  1065. for xb := gridMinX to gridMaxX-1 do
  1066. if not gridDone[yb,xb] and
  1067. not IsConvex([DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1068. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb]]) then
  1069. begin
  1070. layer.FillQuadLinearMapping(DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1071. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb],backupLayer,
  1072. DeformationGridTexCoord[yb,xb],DeformationGridTexCoord[yb,xb+1],DeformationGridTexCoord[yb+1,xb+1],
  1073. DeformationGridTexCoord[yb+1,xb],true, fcKeepCW);
  1074. gridDone[yb,xb] := true;
  1075. end;
  1076. //drawing convex zones
  1077. for yb := gridMinY to gridMaxY-1 do
  1078. for xb := gridMinX to gridMaxX-1 do
  1079. if not gridDone[yb,xb] and IsClockwise([DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1080. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb]]) then
  1081. layer.FillQuadLinearMapping(DeformationGrid[yb,xb],DeformationGrid[yb,xb+1],
  1082. DeformationGrid[yb+1,xb+1],DeformationGrid[yb+1,xb],backupLayer,
  1083. DeformationGridTexCoord[yb,xb],DeformationGridTexCoord[yb,xb+1],DeformationGridTexCoord[yb+1,xb+1],
  1084. DeformationGridTexCoord[yb+1,xb],true);
  1085. layer.ClipRect := PreviousClipRect;
  1086. end;
  1087. result := FMergedBounds;
  1088. end;
  1089. deformationOrigin := ptF;
  1090. end;
  1091. function TToolDeformationGrid.GetIsSelectingTool: boolean;
  1092. begin
  1093. Result:= false;
  1094. end;
  1095. function TToolDeformationGrid.DoToolUpdate(toolDest: TBGRABitmap): TRect;
  1096. begin
  1097. if (deformationGridNbX <> Manager.DeformationGridNbX) or
  1098. (deformationGridNbY <> Manager.DeformationGridNbY) then
  1099. begin
  1100. ReleaseGrid;
  1101. DeformationGrid := nil;
  1102. DeformationGridTexCoord := nil;
  1103. deformationGridNbX:= 0;
  1104. deformationGridNbY:= 0;
  1105. Result:= OnlyRenderChange;
  1106. end
  1107. else
  1108. result := EmptyRect;
  1109. end;
  1110. class procedure TToolDeformationGrid.ForgetHintShown;
  1111. begin
  1112. ReturnHintShown := false;
  1113. end;
  1114. constructor TToolDeformationGrid.Create(AManager: TToolManager);
  1115. begin
  1116. inherited Create(AManager);
  1117. deformationGridNbX:= 0;
  1118. deformationGridNbY:= 0;
  1119. DoingDeformation:= false;
  1120. deformationGrid := nil;
  1121. deformationGridTexCoord := nil;
  1122. end;
  1123. function TToolDeformationGrid.Render(VirtualScreen: TBGRABitmap;
  1124. VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
  1125. var curPt,rightPt,downPt: TPointF;
  1126. xb,yb: Integer;
  1127. begin
  1128. result := EmptyRect;
  1129. if (VirtualScreen = nil) and (deformationGrid = nil) then exit;
  1130. if not ToolDeformationGridNeeded then exit;
  1131. for xb := 0 to deformationGridNbX-1 do
  1132. for yb := 0 to deformationGridNbY-1 do
  1133. begin
  1134. curPt := BitmapToVirtualScreen(DeformationGrid[yb,xb]);
  1135. if not deformationGridMoving or ((xb+1 >= deformationGridX) and (xb <= deformationGridX) and
  1136. (yb >= deformationGridY-1) and (yb <= deformationGridY+1)) then
  1137. begin
  1138. if (xb < deformationGridNbX-1) and (yb > 0) and (yb < deformationGridNbY-1) then
  1139. begin
  1140. rightPt := BitmapToVirtualScreen(DeformationGrid[yb,xb+1]);
  1141. if Assigned(VirtualScreen) then NiceLine(VirtualScreen, curPt.X,curPt.Y, rightPt.X,rightPt.Y);
  1142. result := RectUnion(result,rect(floor(curPt.x)-1,floor(curPt.y)-1,
  1143. ceil(curPt.x)+2,ceil(curPt.y)+2));
  1144. result := RectUnion(result,rect(floor(rightPt.x)-1,floor(rightPt.y)-1,
  1145. ceil(rightPt.x)+2,ceil(rightPt.y)+2));
  1146. end;
  1147. end;
  1148. if not deformationGridMoving or ((xb >= deformationGridX-1) and (xb <= deformationGridX+1) and
  1149. (yb+1 >= deformationGridY) and (yb <= deformationGridY)) then
  1150. begin
  1151. if (yb < deformationGridNbY-1) and (xb > 0) and (xb < deformationGridNbX-1) then
  1152. begin
  1153. downPt := BitmapToVirtualScreen(DeformationGrid[yb+1,xb]);
  1154. if Assigned(virtualScreen) then NiceLine(VirtualScreen, curPt.X,curPt.Y, downPt.X,downPt.Y);
  1155. result := RectUnion(result,rect(floor(curPt.x)-1,floor(curPt.y)-1,
  1156. ceil(curPt.x)+2,ceil(curPt.y)+2));
  1157. result := RectUnion(result,rect(floor(downPt.x)-1,floor(downPt.y)-1,
  1158. ceil(downPt.x)+2,ceil(downPt.y)+2));
  1159. end;
  1160. end;
  1161. end;
  1162. for xb := 1 to deformationGridNbX-2 do
  1163. for yb := 1 to deformationGridNbY-2 do
  1164. begin
  1165. if not deformationGridMoving or ((xb >= deformationGridX-1) and (xb <= deformationGridX+1) and
  1166. (yb >= deformationGridY-1) and (yb <= deformationGridY+1)) then
  1167. begin
  1168. curPt := BitmapToVirtualScreen(DeformationGrid[yb,xb]);
  1169. result := RectUnion(result,NicePoint(VirtualScreen, curPt.X,curPt.Y));
  1170. end;
  1171. end;
  1172. end;
  1173. function TToolDeformationGrid.DoToolKeyDown(var key: Word): TRect;
  1174. begin
  1175. result := EmptyRect;
  1176. if Key = VK_RETURN then
  1177. begin
  1178. if DoingDeformation then
  1179. begin
  1180. ValidateDeformationGrid;
  1181. result := EmptyRect;
  1182. manager.QueryExitTool;
  1183. Key := 0;
  1184. end;
  1185. end else
  1186. if Key = VK_ESCAPE then
  1187. begin
  1188. if DoingDeformation then
  1189. CancelActionPartially;
  1190. result := OnlyRenderChange;
  1191. manager.QueryExitTool;
  1192. Key := 0;
  1193. end;
  1194. end;
  1195. function TToolDeformationGrid.ToolUp: TRect;
  1196. begin
  1197. if deformationGridMoving then
  1198. begin
  1199. result := OnlyRenderChange;
  1200. if not ReturnHintShown then
  1201. begin
  1202. Manager.ToolPopup(tpmreturnValides);
  1203. ReturnHintShown := true;
  1204. end;
  1205. end
  1206. else
  1207. Result:=EmptyRect;
  1208. deformationGridMoving := false;
  1209. end;
  1210. function TToolDeformationGrid.GetContextualToolbars: TContextualToolbars;
  1211. begin
  1212. Result:= [ctDeformation];
  1213. end;
  1214. initialization
  1215. RegisterTool(ptDeformation, TToolDeformationGrid);
  1216. RegisterTool(ptTextureMapping, TToolTextureMapping);
  1217. RegisterTool(ptLayerMapping, TToolLayerMapping);
  1218. end.