GR32_VectorMaps.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. unit GR32_VectorMaps;
  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 GR32_VectorMaps
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Michael Hansen <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. uses
  34. {$if defined(UseInlining)}
  35. Types,
  36. {$ifend}
  37. GR32;
  38. type
  39. TFixedVector = TFixedPoint;
  40. PFixedVector = ^TFixedVector;
  41. TFloatVector = TFloatPoint;
  42. PFloatVector = ^TFloatVector;
  43. TArrayOfFixedVector = array of TFixedVector;
  44. PArrayOfFixedVector = ^TArrayOfFixedVector;
  45. TArrayOfFloatVector = array of TFloatVector;
  46. PArrayOfFloatVector = ^TArrayOfFixedVector;
  47. type
  48. TVectorCombineMode = (vcmAdd, vcmReplace, vcmCustom);
  49. TVectorCombineEvent= procedure(F, P: TFixedVector; var B: TFixedVector) of object;
  50. TVectorMap = class(TCustomMap)
  51. private
  52. FVectors: TArrayOfFixedVector;
  53. FOnVectorCombine: TVectorCombineEvent;
  54. FVectorCombineMode: TVectorCombineMode;
  55. function GetVectors: PFixedPointArray;
  56. function GetFixedVector(X,Y: Integer): TFixedVector;
  57. function GetFixedVectorS(X,Y: Integer): TFixedVector;
  58. function GetFixedVectorX(X,Y: TFixed): TFixedVector;
  59. function GetFixedVectorXS(X,Y: TFixed): TFixedVector;
  60. function GetFloatVector(X,Y: Integer): TFloatVector;
  61. function GetFloatVectorS(X,Y: Integer): TFloatVector;
  62. function GetFloatVectorF(X,Y: Single): TFloatVector;
  63. function GetFloatVectorFS(X,Y: Single): TFloatVector;
  64. procedure SetFixedVector(X,Y: Integer; const Point: TFixedVector);
  65. procedure SetFixedVectorS(X,Y: Integer; const Point: TFixedVector);
  66. procedure SetFixedVectorX(X,Y: TFixed; const Point: TFixedVector);
  67. procedure SetFixedVectorXS(X,Y: TFixed; const Point: TFixedVector);
  68. procedure SetFloatVector(X,Y: Integer; const Point: TFloatVector);
  69. procedure SetFloatVectorS(X,Y: Integer; const Point: TFloatVector);
  70. procedure SetFloatVectorF(X,Y: Single; const Point: TFloatVector);
  71. procedure SetFloatVectorFS(X,Y: Single; const Point: TFloatVector);
  72. procedure SetVectorCombineMode(const Value: TVectorCombineMode);
  73. protected
  74. procedure ChangeSize(var Width, Height: Integer; NewWidth,
  75. NewHeight: Integer); override;
  76. public
  77. destructor Destroy; override;
  78. procedure Clear;
  79. procedure Merge(DstLeft, DstTop: Integer; Src: TVectorMap; SrcRect: TRect);
  80. property Vectors: PFixedPointArray read GetVectors;
  81. function BoundsRect: TRect;
  82. function GetTrimmedBounds: TRect;
  83. function Empty: Boolean; override;
  84. procedure LoadFromFile(const FileName: string);
  85. procedure SaveToFile(const FileName: string);
  86. property FixedVector[X, Y: Integer]: TFixedVector read GetFixedVector write SetFixedVector; default;
  87. property FixedVectorS[X, Y: Integer]: TFixedVector read GetFixedVectorS write SetFixedVectorS;
  88. property FixedVectorX[X, Y: TFixed]: TFixedVector read GetFixedVectorX write SetFixedVectorX;
  89. property FixedVectorXS[X, Y: TFixed]: TFixedVector read GetFixedVectorXS write SetFixedVectorXS;
  90. property FloatVector[X, Y: Integer]: TFloatVector read GetFloatVector write SetFloatVector;
  91. property FloatVectorS[X, Y: Integer]: TFloatVector read GetFloatVectorS write SetFloatVectorS;
  92. property FloatVectorF[X, Y: Single]: TFloatVector read GetFloatVectorF write SetFloatVectorF;
  93. property FloatVectorFS[X, Y: Single]: TFloatVector read GetFloatVectorFS write SetFloatVectorFS;
  94. published
  95. property VectorCombineMode: TVectorCombineMode read FVectorCombineMode write SetVectorCombineMode;
  96. property OnVectorCombine: TVectorCombineEvent read FOnVectorCombine write FOnVectorCombine;
  97. end;
  98. implementation
  99. uses
  100. SysUtils,
  101. GR32_Lowlevel,
  102. GR32_Math;
  103. resourcestring
  104. RCStrCantAllocateVectorMap = 'Can''t allocate VectorMap!';
  105. RCStrBadFormat = 'Bad format - Photoshop .msh expected!';
  106. RCStrFileNotFound = 'File not found!';
  107. RCStrSrcIsEmpty = 'Src is empty!';
  108. RCStrBaseIsEmpty = 'Base is empty!';
  109. { TVectorMap }
  110. function CombineVectorsReg(const A, B: TFixedVector; Weight: TFixed): TFixedVector;
  111. begin
  112. Result.X := FixedCombine(Weight, B.X, A.X);
  113. Result.Y := FixedCombine(Weight, B.Y, A.Y);
  114. end;
  115. procedure CombineVectorsMem(const A: TFixedVector;var B: TFixedVector; Weight: TFixed);
  116. begin
  117. B.X := FixedCombine(Weight, B.X, A.X);
  118. B.Y := FixedCombine(Weight, B.Y, A.Y);
  119. end;
  120. function TVectorMap.BoundsRect: TRect;
  121. begin
  122. Result := MakeRect(0, 0, Width, Height);
  123. end;
  124. procedure TVectorMap.ChangeSize(var Width, Height: Integer;
  125. NewWidth, NewHeight: Integer);
  126. begin
  127. inherited;
  128. FVectors := nil;
  129. Width := 0;
  130. Height := 0;
  131. SetLength(FVectors, NewWidth * NewHeight);
  132. if (NewWidth > 0) and (NewHeight > 0) then
  133. begin
  134. if FVectors = nil then
  135. raise Exception.Create(RCStrCantAllocateVectorMap);
  136. FillLongword(FVectors[0], NewWidth * NewHeight * 2, 0);
  137. end;
  138. Width := NewWidth;
  139. Height := NewHeight;
  140. end;
  141. procedure TVectorMap.Clear;
  142. begin
  143. FillLongword(FVectors[0], Width * Height * 2, 0);
  144. end;
  145. destructor TVectorMap.Destroy;
  146. begin
  147. Lock;
  148. try
  149. SetSize(0, 0);
  150. finally
  151. Unlock;
  152. end;
  153. inherited;
  154. end;
  155. function TVectorMap.GetVectors: PFixedPointArray;
  156. begin
  157. Result := @FVectors[0];
  158. end;
  159. function TVectorMap.GetFloatVector(X, Y: Integer): TFloatVector;
  160. begin
  161. Result := FloatPoint(FVectors[X + Y * Width]);
  162. end;
  163. function TVectorMap.GetFloatVectorF(X, Y: Single): TFloatVector;
  164. begin
  165. Result := FloatPoint(GetFixedVectorX(Fixed(X), Fixed(Y)));
  166. end;
  167. function TVectorMap.GetFloatVectorFS(X, Y: Single): TFloatVector;
  168. begin
  169. Result := FloatPoint(GetFixedVectorXS(Fixed(X), Fixed(Y)));
  170. end;
  171. function TVectorMap.GetFloatVectorS(X, Y: Integer): TFloatVector;
  172. begin
  173. if (X >= 0) and (Y >= 0) and
  174. (X < Width) and (Y < Height) then
  175. Result := GetFloatVector(X,Y)
  176. else
  177. begin
  178. Result.X := 0;
  179. Result.Y := 0;
  180. end;
  181. end;
  182. function TVectorMap.GetFixedVector(X, Y: Integer): TFixedVector;
  183. begin
  184. Result := FVectors[X + Y * Width];
  185. end;
  186. function TVectorMap.GetFixedVectorS(X, Y: Integer): TFixedVector;
  187. begin
  188. if (X >= 0) and (Y >= 0) and
  189. (X < Width) and (Y < Height) then
  190. Result := GetFixedVector(X,Y)
  191. else
  192. begin
  193. Result.X := 0;
  194. Result.Y := 0;
  195. end;
  196. end;
  197. function TVectorMap.GetFixedVectorX(X, Y: TFixed): TFixedVector;
  198. const
  199. Next = SizeOf(TFixedVector);
  200. var
  201. WX,WY: TFixed;
  202. W, H: Integer;
  203. P: Pointer;
  204. begin
  205. WX := TFixedRec(X).Int;
  206. WY := TFixedRec(Y).Int;
  207. W := Width;
  208. H := Height;
  209. if (WX >= 0) and (WX <= W - 1) and (WY >= 0) and (WY <= H - 1) then
  210. begin
  211. P := @FVectors[WX + WY * W];
  212. if (WY = H - 1) then
  213. W := 0
  214. else
  215. W := W * Next;
  216. if (WX = W - 1) then
  217. H := 0
  218. else
  219. H := Next;
  220. WX := TFixedRec(X).Frac;
  221. WY := TFixedRec(Y).Frac;
  222. Result := CombineVectorsReg(CombineVectorsReg(PFixedPoint(P)^,
  223. PFixedPoint(NativeUInt(P) + NativeUInt(H))^, WX), CombineVectorsReg(
  224. PFixedPoint(NativeUInt(P) + NativeUInt(W))^,
  225. PFixedPoint(NativeUInt(P) + NativeUInt(W + H))^, WX), WY);
  226. end else
  227. begin
  228. Result.X := 0;
  229. Result.Y := 0;
  230. end;
  231. end;
  232. function TVectorMap.GetFixedVectorXS(X, Y: TFixed): TFixedVector;
  233. var
  234. WX,WY: TFixed;
  235. begin
  236. WX := TFixedRec(X).Frac;
  237. X := TFixedRec(X).Int;
  238. WY := TFixedRec(Y).Frac;
  239. Y := TFixedRec(Y).Int;
  240. Result := CombineVectorsReg(CombineVectorsReg(FixedVectorS[X,Y], FixedVectorS[X + 1,Y], WX),
  241. CombineVectorsReg(FixedVectorS[X,Y + 1], FixedVectorS[X + 1,Y + 1], WX), WY);
  242. end;
  243. function TVectorMap.Empty: Boolean;
  244. begin
  245. Result := false;
  246. if (Width = 0) or (Height = 0) or (FVectors = nil) then Result := True;
  247. end;
  248. const
  249. MeshIdent = 'yfqLhseM';
  250. type
  251. {TVectorMap supports the photoshop liquify mesh fileformat .msh}
  252. TPSLiquifyMeshHeader = record
  253. Pad0 : cardinal;
  254. Ident : array [0..7] of Char;
  255. Pad1 : cardinal;
  256. Width : cardinal;
  257. Height: cardinal;
  258. end;
  259. procedure TVectorMap.LoadFromFile(const FileName: string);
  260. procedure ConvertVertices;
  261. var
  262. I: Integer;
  263. begin
  264. for I := 0 to Length(FVectors) - 1 do
  265. begin
  266. //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
  267. //Do no change to PFloat.. the type is relative to the msh format.
  268. FVectors[I].X := Fixed(PSingle(@FVectors[I].X)^);
  269. FVectors[I].Y := Fixed(PSingle(@FVectors[I].Y)^);
  270. end;
  271. end;
  272. var
  273. Header: TPSLiquifyMeshHeader;
  274. MeshFile: File;
  275. begin
  276. If FileExists(Filename) then
  277. try
  278. AssignFile(MeshFile, FileName);
  279. Reset(MeshFile, 1);
  280. BlockRead(MeshFile, Header, SizeOf(TPSLiquifyMeshHeader));
  281. if LowerCase(string(Header.Ident)) <> LowerCase(MeshIdent) then
  282. Exception.Create(RCStrBadFormat);
  283. with Header do
  284. begin
  285. SetSize(Width, Height);
  286. BlockRead(MeshFile, FVectors[0], Width * Height * SizeOf(TFixedVector));
  287. ConvertVertices;
  288. end;
  289. finally
  290. CloseFile(MeshFile);
  291. end
  292. else Exception.Create(RCStrFileNotFound);
  293. end;
  294. procedure TVectorMap.Merge(DstLeft, DstTop: Integer; Src: TVectorMap; SrcRect: TRect);
  295. var
  296. I,J,P: Integer;
  297. DstRect: TRect;
  298. Progression: TFixedVector;
  299. ProgressionX, ProgressionY: TFixed;
  300. CombineCallback: TVectorCombineEvent;
  301. DstPtr : PFixedPointArray;
  302. SrcPtr : PFixedPoint;
  303. begin
  304. if Src.Empty then Exception.Create(RCStrSrcIsEmpty);
  305. if Empty then Exception.Create(RCStrBaseIsEmpty);
  306. GR32.IntersectRect(SrcRect, Src.BoundsRect, SrcRect);
  307. DstRect.Left := DstLeft;
  308. DstRect.Top := DstTop;
  309. DstRect.Right := DstLeft + (SrcRect.Right - SrcRect.Left);
  310. DstRect.Bottom := DstTop + (SrcRect.Bottom - SrcRect.Top);
  311. GR32.IntersectRect(DstRect, BoundsRect, DstRect);
  312. if GR32.IsRectEmpty(DstRect) then Exit;
  313. P := SrcRect.Top * Src.Width;
  314. Progression.Y := - FixedOne;
  315. case Src.FVectorCombineMode of
  316. vcmAdd:
  317. begin
  318. for I := DstRect.Top to DstRect.Bottom do
  319. begin
  320. // Added ^ for FPC
  321. DstPtr := @GetVectors^[I * Width];
  322. SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
  323. for J := DstRect.Left to DstRect.Right do
  324. begin
  325. Inc(SrcPtr^.X, DstPtr[J].X);
  326. Inc(SrcPtr^.Y, DstPtr[J].Y);
  327. Inc(SrcPtr);
  328. end;
  329. Inc(P, Src.Width);
  330. end;
  331. end;
  332. vcmReplace:
  333. begin
  334. for I := DstRect.Top to DstRect.Bottom do
  335. begin
  336. // Added ^ for FPC
  337. DstPtr := @GetVectors^[I * Width];
  338. SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
  339. for J := DstRect.Left to DstRect.Right do
  340. begin
  341. SrcPtr^.X := DstPtr[J].X;
  342. SrcPtr^.Y := DstPtr[J].Y;
  343. Inc(SrcPtr);
  344. end;
  345. Inc(P, Src.Width);
  346. end;
  347. end;
  348. else
  349. CombineCallback := Src.FOnVectorCombine;
  350. ProgressionX := Fixed(2 / (DstRect.Right - DstRect.Left - 1));
  351. ProgressionY := Fixed(2 / (DstRect.Bottom - DstRect.Top - 1));
  352. for I := DstRect.Top to DstRect.Bottom do
  353. begin
  354. Progression.X := - FixedOne;
  355. // Added ^ for FPC
  356. DstPtr := @GetVectors^[I * Width];
  357. SrcPtr := @Src.GetVectors^[SrcRect.Left + P];
  358. for J := DstRect.Left to DstRect.Right do
  359. begin
  360. CombineCallback(SrcPtr^, Progression, DstPtr[J]);
  361. Inc(SrcPtr);
  362. Inc(Progression.X, ProgressionX);
  363. end;
  364. Inc(P, Src.Width);
  365. Inc(Progression.Y, ProgressionY);
  366. end;
  367. end;
  368. end;
  369. procedure TVectorMap.SaveToFile(const FileName: string);
  370. procedure ConvertVerticesX;
  371. var
  372. I: Integer;
  373. begin
  374. for I := 0 to Length(FVectors) - 1 do
  375. begin
  376. //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
  377. //Do no change to PFloat.. the type is relative to the msh format.
  378. FVectors[I].X := Fixed(PSingle(@FVectors[I].X)^);
  379. FVectors[I].Y := Fixed(PSingle(@FVectors[I].Y)^);
  380. end;
  381. end;
  382. procedure ConvertVerticesF;
  383. var
  384. I: Integer;
  385. {$if (defined(CompilerVersion)) and (CompilerVersion = 31)}
  386. f: single;
  387. {$ifend}
  388. begin
  389. for I := 0 to Length(FVectors) - 1 do
  390. begin
  391. //Not a mistake! Converting physical mem. directly to avoid temporary floating point buffer
  392. //Do no change to PFloat.. the type is relative to the msh format.
  393. // Workaround for Delphi 10.1 Internal Error C6949 ...
  394. {$if (defined(CompilerVersion)) and (CompilerVersion = 31)}
  395. f := FVectors[I].X * FixedToFloat;
  396. FVectors[I].X := PInteger(@f)^;
  397. f := FVectors[I].Y * FixedToFloat;
  398. FVectors[I].Y := PInteger(@f)^;
  399. {$else}
  400. PSingle(@FVectors[I].X)^ := FVectors[I].X * FixedToFloat;
  401. PSingle(@FVectors[I].Y)^ := FVectors[I].Y * FixedToFloat;
  402. {$ifend}
  403. end;
  404. end;
  405. var
  406. Header: TPSLiquifyMeshHeader;
  407. MeshFile: File;
  408. Pad: Cardinal;
  409. begin
  410. try
  411. AssignFile(MeshFile, FileName);
  412. Rewrite(MeshFile, 1);
  413. with Header do
  414. begin
  415. Pad0 := $02000000;
  416. Ident := MeshIdent;
  417. Pad1 := $00000002;
  418. Width := Self.Width;
  419. Height := Self.Height;
  420. end;
  421. BlockWrite(MeshFile, Header, SizeOf(TPSLiquifyMeshHeader));
  422. with Header do
  423. begin
  424. ConvertVerticesF;
  425. BlockWrite(MeshFile, FVectors[0], Length(FVectors) * SizeOf(TFixedVector));
  426. ConvertVerticesX;
  427. end;
  428. if Odd(Length(FVectors) * SizeOf(TFixedVector) - 1) then
  429. begin
  430. Pad := $00000000;
  431. BlockWrite(MeshFile, Pad, 4);
  432. BlockWrite(MeshFile, Pad, 4);
  433. end;
  434. finally
  435. CloseFile(MeshFile);
  436. end;
  437. end;
  438. procedure TVectorMap.SetFloatVector(X, Y: Integer; const Point: TFloatVector);
  439. begin
  440. FVectors[X + Y * Width] := FixedPoint(Point);
  441. end;
  442. procedure TVectorMap.SetFloatVectorF(X, Y: Single; const Point: TFloatVector);
  443. begin
  444. SetFixedVectorX(Fixed(X), Fixed(Y), FixedPoint(Point));
  445. end;
  446. procedure TVectorMap.SetFloatVectorFS(X, Y: Single; const Point: TFloatVector);
  447. begin
  448. SetFixedVectorXS(Fixed(X), Fixed(Y), FixedPoint(Point));
  449. end;
  450. procedure TVectorMap.SetFloatVectorS(X, Y: Integer; const Point: TFloatVector);
  451. begin
  452. if (X >= 0) and (X < Width) and
  453. (Y >= 0) and (Y < Height) then
  454. FVectors[X + Y * Width] := FixedPoint(Point);
  455. end;
  456. procedure TVectorMap.SetFixedVector(X, Y: Integer; const Point: TFixedVector);
  457. begin
  458. FVectors[X + Y * Width] := Point;
  459. end;
  460. procedure TVectorMap.SetFixedVectorS(X, Y: Integer; const Point: TFixedVector);
  461. begin
  462. if (X >= 0) and (X < Width) and
  463. (Y >= 0) and (Y < Height) then
  464. FVectors[X + Y * Width] := Point;
  465. end;
  466. procedure TVectorMap.SetFixedVectorX(X, Y: TFixed; const Point: TFixedVector);
  467. var
  468. flrx, flry, celx, cely: Integer;
  469. P: PFixedPoint;
  470. begin
  471. flrx := TFixedRec(X).Frac;
  472. celx := flrx xor $FFFF;
  473. flry := TFixedRec(Y).Frac;
  474. cely := flry xor $FFFF;
  475. P := @FVectors[TFixedRec(X).Int + TFixedRec(Y).Int * Width];
  476. CombineVectorsMem(Point, P^, FixedMul(celx, cely)); Inc(P);
  477. CombineVectorsMem(Point, P^, FixedMul(flrx, cely)); Inc(P, Width);
  478. CombineVectorsMem(Point, P^, FixedMul(flrx, flry)); Dec(P);
  479. CombineVectorsMem(Point, P^, FixedMul(celx, flry));
  480. end;
  481. procedure TVectorMap.SetFixedVectorXS(X, Y: TFixed; const Point: TFixedVector);
  482. var
  483. flrx, flry, celx, cely: Integer;
  484. P: PFixedPoint;
  485. begin
  486. if (X < -$10000) or (Y < -$10000) then Exit;
  487. flrx := TFixedRec(X).Frac;
  488. X := TFixedRec(X).Int;
  489. flry := TFixedRec(Y).Frac;
  490. Y := TFixedRec(Y).Int;
  491. if (X >= Width) or (Y >= Height) then Exit;
  492. celx := flrx xor $FFFF;
  493. cely := flry xor $FFFF;
  494. P := @FVectors[X + Y * Width];
  495. if (X >= 0) and (Y >= 0)then
  496. begin
  497. CombineVectorsMem(Point, P^, FixedMul(celx, cely) ); Inc(P);
  498. CombineVectorsMem(Point, P^, FixedMul(flrx, cely) ); Inc(P, Width);
  499. CombineVectorsMem(Point, P^, FixedMul(flrx, flry) ); Dec(P);
  500. CombineVectorsMem(Point, P^, FixedMul(celx, flry) );
  501. end
  502. else
  503. begin
  504. if (X >= 0) and (Y >= 0) then CombineVectorsMem(Point, P^, FixedMul(celx, cely)); Inc(P);
  505. if (X < Width - 1) and (Y >= 0) then CombineVectorsMem(Point, P^, FixedMul(flrx, cely)); Inc(P, Width);
  506. if (X < Width - 1) and (Y < Height - 1) then CombineVectorsMem(Point, P^, FixedMul(flrx, flry)); Dec(P);
  507. if (X >= 0) and (Y < Height - 1) then CombineVectorsMem(Point, P^, FixedMul(celx, flry));
  508. end;
  509. end;
  510. procedure TVectorMap.SetVectorCombineMode(const Value: TVectorCombineMode);
  511. begin
  512. if FVectorCombineMode <> Value then
  513. begin
  514. FVectorCombineMode := Value;
  515. Changed;
  516. end;
  517. end;
  518. function TVectorMap.GetTrimmedBounds: TRect;
  519. var
  520. J: Integer;
  521. VectorPtr : PFixedVector;
  522. label
  523. TopDone, BottomDone, LeftDone, RightDone;
  524. begin
  525. with Result do
  526. begin
  527. //Find Top
  528. Top := 0;
  529. VectorPtr := @Vectors[Top];
  530. repeat
  531. if Int64(VectorPtr^) <> 0 then goto TopDone;
  532. Inc(VectorPtr);
  533. Inc(Top);
  534. until Top = Self.Width * Self.Height;
  535. TopDone: Top := Top div Self.Width;
  536. //Find Bottom
  537. Bottom := Self.Width * Self.Height - 1;
  538. VectorPtr := @Vectors[Bottom];
  539. repeat
  540. if Int64(VectorPtr^) <> 0 then goto BottomDone;
  541. Dec(VectorPtr);
  542. Dec(Bottom);
  543. until Bottom < 0;
  544. BottomDone: Bottom := Bottom div Self.Width - 1;
  545. //Find Left
  546. Left := 0;
  547. repeat
  548. J := Top;
  549. repeat
  550. if Int64(FixedVector[Left, J]) <> 0 then goto LeftDone;
  551. Inc(J);
  552. until J >= Bottom;
  553. Inc(Left)
  554. until Left >= Self.Width;
  555. LeftDone:
  556. //Find Right
  557. Right := Self.Width - 1;
  558. repeat
  559. J := Bottom;
  560. repeat
  561. if Int64(FixedVector[Right, J]) <> 0 then goto RightDone;
  562. Dec(J);
  563. until J <= Top;
  564. Dec(Right)
  565. until Right <= Left;
  566. end;
  567. RightDone:
  568. if GR32.IsRectEmpty(Result) then
  569. Result := MakeRect(0, 0, 0, 0);
  570. end;
  571. end.