GR32_Rasterizers.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. unit GR32_Rasterizers;
  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 Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2004-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. * Steffen Binas <[email protected]>
  32. *
  33. * ***** END LICENSE BLOCK ***** *)
  34. interface
  35. {$I GR32.inc}
  36. uses
  37. {$IFDEF FPC}
  38. LCLIntf,
  39. {$IFDEF Windows}
  40. Windows,
  41. {$ENDIF}
  42. {$ELSE}
  43. Windows,
  44. {$ENDIF}
  45. Classes, GR32, GR32_Blend;
  46. type
  47. TAssignColor = procedure(var Dst: TColor32; Src: TColor32) of object;
  48. PCombineInfo = ^TCombineInfo;
  49. TCombineInfo = record
  50. SrcAlpha: Integer;
  51. DrawMode: TDrawMode;
  52. CombineMode: TCombineMode;
  53. CombineCallBack: TPixelCombineEvent;
  54. TransparentColor: TColor32;
  55. end;
  56. type
  57. { TRasterizer }
  58. { A base class for TCustomBitmap32-specific rasterizers. }
  59. TRasterizer = class(TThreadPersistent)
  60. private
  61. FSampler: TCustomSampler;
  62. FSrcAlpha: Integer;
  63. FBlendMemEx: TBlendMemEx;
  64. FCombineCallBack: TPixelCombineEvent;
  65. FAssignColor: TAssignColor;
  66. FTransparentColor: TColor32;
  67. procedure SetSampler(const Value: TCustomSampler);
  68. procedure SetCombineInfo(const CombineInfo: TCombineInfo);
  69. procedure AssignColorOpaque(var Dst: TColor32; Src: TColor32);
  70. procedure AssignColorBlend(var Dst: TColor32; Src: TColor32);
  71. procedure AssignColorCustom(var Dst: TColor32; Src: TColor32);
  72. procedure AssignColorTransparent(var Dst: TColor32; Src: TColor32);
  73. protected
  74. procedure AssignTo(Dst: TPersistent); override;
  75. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); virtual; abstract;
  76. property AssignColor: TAssignColor read FAssignColor write FAssignColor;
  77. public
  78. constructor Create; override;
  79. procedure Assign(Source: TPersistent); override;
  80. procedure Rasterize(Dst: TCustomBitmap32); overload;
  81. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect); overload;
  82. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect; const CombineInfo: TCombineInfo); overload;
  83. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect; Src: TCustomBitmap32); overload;
  84. published
  85. property Sampler: TCustomSampler read FSampler write SetSampler;
  86. end;
  87. TRasterizerClass = class of TRasterizer;
  88. { TRegularSamplingRasterizer }
  89. { This rasterizer simply picks one sample for each pixel in the output bitmap. }
  90. TRegularRasterizer = class(TRasterizer)
  91. private
  92. FUpdateRowCount: Integer;
  93. protected
  94. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  95. public
  96. constructor Create; override;
  97. published
  98. property UpdateRowCount: Integer read FUpdateRowCount write FUpdateRowCount;
  99. end;
  100. { TSwizzlingRasterizer }
  101. { An interesting rasterization method where sample locations are choosen
  102. according to a fractal pattern called 'swizzling'. With a slight
  103. modification to the algorithm this routine will actually yield the
  104. well-known sierpinski triangle fractal. An advantage with this pattern
  105. is that it may benefit from local coherency in the sampling method used. }
  106. TSwizzlingRasterizer = class(TRasterizer)
  107. private
  108. FBlockSize: Integer;
  109. procedure SetBlockSize(const Value: Integer);
  110. protected
  111. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  112. public
  113. constructor Create; override;
  114. published
  115. property BlockSize: Integer read FBlockSize write SetBlockSize default 3;
  116. end;
  117. { TProgressiveRasterizer }
  118. { This class will perform rasterization in a progressive manner. It performs
  119. subsampling with a block size of 2^n and will successively decrease n in
  120. each iteration until n equals zero. }
  121. TProgressiveRasterizer = class(TRasterizer)
  122. private
  123. FSteps: Integer;
  124. FUpdateRows: Boolean;
  125. procedure SetSteps(const Value: Integer);
  126. procedure SetUpdateRows(const Value: Boolean);
  127. protected
  128. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  129. public
  130. constructor Create; override;
  131. published
  132. property Steps: Integer read FSteps write SetSteps default 4;
  133. property UpdateRows: Boolean read FUpdateRows write SetUpdateRows default True;
  134. end;
  135. { TTesseralRasterizer }
  136. { This is a recursive rasterization method. It uses a divide-and-conquer
  137. scheme to subdivide blocks vertically and horizontally into smaller blocks. }
  138. TTesseralRasterizer = class(TRasterizer)
  139. protected
  140. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  141. end;
  142. { TContourRasterizer }
  143. TContourRasterizer = class(TRasterizer)
  144. protected
  145. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  146. end;
  147. { TMultithreadedRegularRasterizer }
  148. TMultithreadedRegularRasterizer = class(TRasterizer)
  149. protected
  150. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  151. end;
  152. { Auxiliary routines }
  153. function CombineInfo(Bitmap: TCustomBitmap32): TCombineInfo;
  154. const
  155. DEFAULT_COMBINE_INFO: TCombineInfo = (
  156. SrcAlpha: $FF;
  157. DrawMode: dmOpaque;
  158. CombineMode: cmBlend;
  159. CombineCallBack: nil;
  160. TransparentColor: clBlack32;
  161. );
  162. var
  163. DefaultRasterizerClass: TRasterizerClass = TRegularRasterizer;
  164. NumberOfProcessors: Integer = 1;
  165. implementation
  166. uses
  167. Math, SysUtils, GR32_Math, GR32_System, GR32_LowLevel, GR32_Resamplers,
  168. GR32_Containers, GR32_OrdinalMaps;
  169. type
  170. TCustomBitmap32Access = class(TCustomBitmap32);
  171. TLineRasterizerData = record
  172. ScanLine: Integer;
  173. end;
  174. PLineRasterizerData = ^TLineRasterizerData;
  175. TScanLineRasterizerThread = class(TThread)
  176. protected
  177. Data: PLineRasterizerData;
  178. DstRect: TRect;
  179. Dst: TCustomBitmap32;
  180. GetSample: TGetSampleInt;
  181. AssignColor: TAssignColor;
  182. procedure Execute; override;
  183. end;
  184. function CombineInfo(Bitmap: TCustomBitmap32): TCombineInfo;
  185. begin
  186. with Result do
  187. begin
  188. SrcAlpha := Bitmap.MasterAlpha;
  189. DrawMode := Bitmap.DrawMode;
  190. CombineMode := Bitmap.CombineMode;
  191. CombineCallBack := Bitmap.OnPixelCombine;
  192. if (DrawMode = dmCustom) and not Assigned(CombineCallBack) then
  193. DrawMode := dmOpaque;
  194. TransparentColor := Bitmap.OuterColor;
  195. end;
  196. end;
  197. { TRasterizer }
  198. procedure TRasterizer.AssignColorBlend(var Dst: TColor32; Src: TColor32);
  199. begin
  200. FBlendMemEx(Src, Dst, FSrcAlpha);
  201. EMMS;
  202. end;
  203. procedure TRasterizer.AssignColorOpaque(var Dst: TColor32; Src: TColor32);
  204. begin
  205. Dst := Src;
  206. end;
  207. procedure TRasterizer.AssignColorCustom(var Dst: TColor32; Src: TColor32);
  208. begin
  209. FCombineCallBack(Src, Dst, FSrcAlpha);
  210. end;
  211. procedure TRasterizer.AssignColorTransparent(var Dst: TColor32;
  212. Src: TColor32);
  213. begin
  214. if Src <> FTransparentColor then Dst := Src;
  215. end;
  216. procedure TRasterizer.AssignTo(Dst: TPersistent);
  217. begin
  218. if Dst is TRasterizer then
  219. SmartAssign(Self, Dst)
  220. else
  221. inherited;
  222. end;
  223. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect;
  224. Src: TCustomBitmap32);
  225. begin
  226. Rasterize(Dst, DstRect, CombineInfo(Src));
  227. end;
  228. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect;
  229. const CombineInfo: TCombineInfo);
  230. begin
  231. SetCombineInfo(CombineInfo);
  232. Rasterize(Dst, DstRect);
  233. end;
  234. procedure TRasterizer.SetCombineInfo(const CombineInfo: TCombineInfo);
  235. begin
  236. with CombineInfo do
  237. begin
  238. FTransparentColor := TransparentColor;
  239. FSrcAlpha := SrcAlpha;
  240. FBlendMemEx := BLEND_MEM_EX[CombineMode]^;
  241. FCombineCallBack := CombineCallBack;
  242. case DrawMode of
  243. dmOpaque: FAssignColor := AssignColorOpaque;
  244. dmBlend: FAssignColor := AssignColorBlend;
  245. dmTransparent: FAssignColor := AssignColorTransparent;
  246. else
  247. if Assigned(FCombineCallback) then
  248. FAssignColor := AssignColorCustom
  249. else
  250. FAssignColor := AssignColorBlend;
  251. end;
  252. end;
  253. end;
  254. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect);
  255. var
  256. UpdateCount: Integer;
  257. R: TRect;
  258. begin
  259. UpdateCount := TCustomBitmap32Access(Dst).UpdateCount;
  260. if Assigned(FSampler) then
  261. begin
  262. FSampler.PrepareSampling;
  263. IntersectRect(R, DstRect, Dst.BoundsRect);
  264. if FSampler.HasBounds then
  265. IntersectRect(R, DstRect, MakeRect(FSampler.GetSampleBounds, rrOutside));
  266. try
  267. DoRasterize(Dst, R);
  268. finally
  269. while TCustomBitmap32Access(Dst).UpdateCount > UpdateCount do
  270. TCustomBitmap32Access(Dst).EndUpdate;
  271. FSampler.FinalizeSampling;
  272. end;
  273. end;
  274. end;
  275. procedure TRasterizer.SetSampler(const Value: TCustomSampler);
  276. begin
  277. if FSampler <> Value then
  278. begin
  279. FSampler := Value;
  280. Changed;
  281. end;
  282. end;
  283. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32);
  284. begin
  285. Rasterize(Dst, Dst.BoundsRect);
  286. end;
  287. constructor TRasterizer.Create;
  288. begin
  289. inherited;
  290. SetCombineInfo(DEFAULT_COMBINE_INFO);
  291. end;
  292. procedure TRasterizer.Assign(Source: TPersistent);
  293. begin
  294. BeginUpdate;
  295. try
  296. if Source is TCustomBitmap32 then
  297. SetCombineInfo(CombineInfo(TCustomBitmap32(Source)))
  298. else
  299. inherited;
  300. finally
  301. EndUpdate;
  302. Changed;
  303. end;
  304. end;
  305. { TRegularRasterizer }
  306. constructor TRegularRasterizer.Create;
  307. begin
  308. inherited;
  309. FUpdateRowCount := 0;
  310. end;
  311. procedure TRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  312. var
  313. I, J, UpdateCount: Integer;
  314. P: PColor32;
  315. GetSample: TGetSampleInt;
  316. begin
  317. GetSample := FSampler.GetSampleInt;
  318. UpdateCount := 0;
  319. for J := DstRect.Top to DstRect.Bottom - 1 do
  320. begin
  321. P := @Dst.Bits[DstRect.Left + J * Dst.Width];
  322. for I := DstRect.Left to DstRect.Right - 1 do
  323. begin
  324. AssignColor(P^, GetSample(I, J));
  325. Inc(P);
  326. end;
  327. Inc(UpdateCount);
  328. if UpdateCount = FUpdateRowCount then
  329. begin
  330. Dst.Changed(Rect(DstRect.Left, J - UpdateCount, DstRect.Right, J));
  331. UpdateCount := 0;
  332. end;
  333. end;
  334. with DstRect do
  335. Dst.Changed(Rect(Left, Bottom - UpdateCount - 1, Right, Bottom));
  336. end;
  337. { TSwizzlingRasterizer }
  338. constructor TSwizzlingRasterizer.Create;
  339. begin
  340. inherited;
  341. FBlockSize := 3;
  342. end;
  343. procedure TSwizzlingRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  344. var
  345. I, L, T, W, H, Size, RowSize, D: Integer;
  346. P1, P2, PBlock: TPoint;
  347. GetSample: TGetSampleInt;
  348. ForwardBuffer: array of Integer;
  349. function GetDstCoord(P: TPoint): TPoint;
  350. var
  351. XI, YI: Integer;
  352. begin
  353. Result := P;
  354. Inc(Result.X);
  355. Inc(Result.Y);
  356. XI := ForwardBuffer[Result.X];
  357. YI := ForwardBuffer[Result.Y];
  358. if XI <= YI then
  359. Dec(Result.Y, 1 shl XI)
  360. else
  361. Dec(Result.X, 1 shl (YI + 1));
  362. if Result.Y >= H then
  363. begin
  364. Result.Y := P.Y + 1 shl YI;
  365. Result.X := P.X;
  366. Result := GetDstCoord(Result);
  367. end;
  368. if Result.X >= W then
  369. begin
  370. Result.X := P.X + 1 shl XI;
  371. Result.Y := P.Y;
  372. Result := GetDstCoord(Result);
  373. end;
  374. end;
  375. begin
  376. W := DstRect.Right - DstRect.Left;
  377. H := DstRect.Bottom - DstRect.Top;
  378. L := DstRect.Left; T := DstRect.Top;
  379. Size := NextPowerOf2(Max(W, H));
  380. SetLength(ForwardBuffer, Size + 1);
  381. I := 2;
  382. while I <= Size do
  383. begin
  384. ForwardBuffer[I] := ForwardBuffer[I shr 1] + 1;
  385. Inc(I, 2);
  386. end;
  387. Size := W * H - 1;
  388. GetSample := FSampler.GetSampleInt;
  389. D := 1 shl FBlockSize;
  390. PBlock := Point(L + D, T + D);
  391. P1 := Point(-1, 0);
  392. RowSize := Dst.Width;
  393. for I := 0 to Size do
  394. begin
  395. P1 := GetDstCoord(P1);
  396. P2.X := L + P1.X;
  397. P2.Y := T + P1.Y;
  398. AssignColor(Dst.Bits[P2.X + P2.Y * RowSize], GetSample(P2.X, P2.Y));
  399. // Invalidate the current block
  400. if (P2.X >= PBlock.X) or (P2.Y >= PBlock.Y) then
  401. begin
  402. Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
  403. PBlock.X := P2.X + D;
  404. PBlock.Y := P2.Y + D;
  405. end;
  406. end;
  407. Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
  408. end;
  409. procedure TSwizzlingRasterizer.SetBlockSize(const Value: Integer);
  410. begin
  411. if FBlockSize <> Value then
  412. begin
  413. FBlockSize := Value;
  414. Changed;
  415. end;
  416. end;
  417. { TProgressiveRasterizer }
  418. constructor TProgressiveRasterizer.Create;
  419. begin
  420. inherited;
  421. FSteps := 4;
  422. FUpdateRows := True;
  423. end;
  424. {$DEFINE UseInternalFill}
  425. procedure TProgressiveRasterizer.DoRasterize(Dst: TCustomBitmap32;
  426. DstRect: TRect);
  427. var
  428. I, J, Shift, W, H, B, Wk, Hk, X, Y: Integer;
  429. DoUpdate: Boolean;
  430. OnChanged: TAreaChangedEvent;
  431. Step: Integer;
  432. GetSample: TGetSampleInt;
  433. {$IFDEF UseInternalFill}
  434. Bits: PColor32Array;
  435. procedure IntFillRect(X1, Y1, X2, Y2: Integer; C: TColor32);
  436. var
  437. Y: Integer;
  438. P: PColor32Array;
  439. begin
  440. for Y := Y1 to Y2 - 1 do
  441. begin
  442. P := Pointer(@Bits[Y * W]);
  443. FillLongword(P[X1], X2 - X1, C);
  444. end;
  445. end;
  446. {$ENDIF}
  447. begin
  448. GetSample := FSampler.GetSampleInt;
  449. OnChanged := Dst.OnAreaChanged;
  450. {$IFDEF UseInternalFill}
  451. Bits := Dst.Bits;
  452. {$ENDIF}
  453. DoUpdate := (TCustomBitmap32Access(Dst).UpdateCount = 0) and Assigned(OnChanged);
  454. W := DstRect.Right - DstRect.Left;
  455. H := DstRect.Bottom - DstRect.Top;
  456. J := DstRect.Top;
  457. Step := 1 shl FSteps;
  458. while J < DstRect.Bottom do
  459. begin
  460. I := DstRect.Left;
  461. B := Min(J + Step, DstRect.Bottom);
  462. while I < DstRect.Right - Step do
  463. begin
  464. {$IFDEF UseInternalFill}
  465. IntFillRect(I, J, I + Step, B, GetSample(I, J));
  466. {$ELSE}
  467. Dst.FillRect(I, J, I + Step, B, GetSample(I, J));
  468. {$ENDIF}
  469. Inc(I, Step);
  470. end;
  471. {$IFDEF UseInternalFill}
  472. IntFillRect(I, J, DstRect.Right, B, GetSample(I, J));
  473. if DoUpdate and FUpdateRows then
  474. OnChanged(Dst, Rect(DstRect.Left, J, DstRect.Right, B), AREAINFO_RECT);
  475. {$ELSE}
  476. Dst.FillRect(I, J, DstRect.Right, B, GetSample(I, J));
  477. {$ENDIF}
  478. Inc(J, Step);
  479. end;
  480. if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
  481. Shift := FSteps;
  482. while Step > 1 do
  483. begin
  484. Dec(Shift);
  485. Step := Step div 2;
  486. Wk := W div Step - 1;
  487. Hk := H div Step;
  488. for J := 0 to Hk do
  489. begin
  490. Y := DstRect.Top + J shl Shift;
  491. B := Min(Y + Step, DstRect.Bottom);
  492. if Odd(J) then
  493. for I := 0 to Wk do
  494. begin
  495. X := DstRect.Left + I shl Shift;
  496. {$IFDEF UseInternalFill}
  497. IntFillRect(X, Y, X + Step, B, GetSample(X, Y));
  498. {$ELSE}
  499. Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
  500. {$ENDIF}
  501. end
  502. else
  503. for I := 0 to Wk do
  504. if Odd(I) then
  505. begin
  506. X := DstRect.Left + I shl Shift;
  507. {$IFDEF UseInternalFill}
  508. IntFillRect(X, Y, X + Step, B, GetSample(X, Y));
  509. {$ELSE}
  510. Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
  511. {$ENDIF}
  512. end;
  513. X := DstRect.Left + Wk shl Shift;
  514. {$IFDEF UseInternalFill}
  515. IntFillRect(X, Y, DstRect.Right, B, GetSample(X, Y));
  516. if FUpdateRows and DoUpdate then
  517. OnChanged(Dst, Rect(DstRect.Left, Y, DstRect.Right, B), AREAINFO_RECT);
  518. {$ELSE}
  519. Dst.FillRect(X, Y, DstRect.Right, B, GetSample(X, Y));
  520. {$ENDIF}
  521. end;
  522. if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
  523. end;
  524. end;
  525. procedure TProgressiveRasterizer.SetSteps(const Value: Integer);
  526. begin
  527. if FSteps <> Value then
  528. begin
  529. FSteps := Value;
  530. Changed;
  531. end;
  532. end;
  533. procedure TProgressiveRasterizer.SetUpdateRows(const Value: Boolean);
  534. begin
  535. if FUpdateRows <> Value then
  536. begin
  537. FUpdateRows := Value;
  538. Changed;
  539. end;
  540. end;
  541. { TTesseralRasterizer }
  542. procedure TTesseralRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  543. var
  544. W, H, I: Integer;
  545. GetSample: TGetSampleInt;
  546. procedure SplitHorizontal(X, Y, Width, Height: Integer); forward;
  547. procedure SplitVertical(X, Y, Width, Height: Integer);
  548. var
  549. HalfWidth, X2, I: Integer;
  550. begin
  551. HalfWidth := Width div 2;
  552. if HalfWidth > 0 then
  553. begin
  554. X2 := X + HalfWidth;
  555. for I := Y + 1 to Y + Height - 1 do
  556. AssignColor(Dst.PixelPtr[X2, I]^, GetSample(X2, I));
  557. Dst.Changed(Rect(X2, Y, X2 + 1, Y + Height));
  558. SplitHorizontal(X, Y, HalfWidth, Height);
  559. SplitHorizontal(X2, Y, Width - HalfWidth, Height);
  560. end;
  561. end;
  562. procedure SplitHorizontal(X, Y, Width, Height: Integer);
  563. var
  564. HalfHeight, Y2, I: Integer;
  565. begin
  566. HalfHeight := Height div 2;
  567. if HalfHeight > 0 then
  568. begin
  569. Y2 := Y + HalfHeight;
  570. for I := X + 1 to X + Width - 1 do
  571. AssignColor(Dst.PixelPtr[I, Y2]^, GetSample(I, Y2));
  572. Dst.Changed(Rect(X, Y2, X + Width, Y2 + 1));
  573. SplitVertical(X, Y, Width, HalfHeight);
  574. SplitVertical(X, Y2, Width, Height - HalfHeight);
  575. end;
  576. end;
  577. begin
  578. GetSample := FSampler.GetSampleInt;
  579. with DstRect do
  580. begin
  581. W := Right - Left;
  582. H := Bottom - Top;
  583. for I := Left to Right - 1 do
  584. AssignColor(Dst.PixelPtr[I, Top]^, GetSample(I, Top));
  585. Dst.Changed(Rect(Left, Top, Right, Top + 1));
  586. for I := Top to Bottom - 1 do
  587. AssignColor(Dst.PixelPtr[Left, I]^, GetSample(Left, I));
  588. Dst.Changed(Rect(Left, Top, Left + 1, Bottom));
  589. if W > H then
  590. SplitVertical(Left, Top, W, H)
  591. else
  592. SplitHorizontal(Left, Top, W, H);
  593. end;
  594. end;
  595. { TContourRasterizer }
  596. procedure InflateRect(const P: TPoint; var R: TRect);
  597. begin
  598. if P.X < R.Left then R.Left := P.X;
  599. if P.Y < R.Top then R.Top := P.Y;
  600. if P.X >= R.Right then R.Right := P.X + 1;
  601. if P.Y >= R.Bottom then R.Bottom := P.Y + 1;
  602. end;
  603. procedure TContourRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  604. type
  605. TDirection = (North, East, South, West);
  606. var
  607. I, J, D, Diff: Integer;
  608. C, CLast: TColor32;
  609. P, PLast: TPoint;
  610. GetSample: TGetSampleInt;
  611. NewDir, Dir: TDirection;
  612. Visited: TBooleanMap;
  613. UpdateRect: TRect;
  614. const
  615. LEFT: array[TDirection] of TDirection = (West, North, East, South);
  616. RIGHT: array[TDirection] of TDirection = (East, South, West, North);
  617. COORDS: array[TDirection] of TPoint = ((X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1), (X: -1; Y: 0));
  618. label
  619. MainLoop;
  620. begin
  621. GetSample := FSampler.GetSampleInt;
  622. Visited := TBooleanMap.Create;
  623. try
  624. with DstRect do
  625. Visited.SetSize(Right - Left, Bottom - Top);
  626. I := 0; J := 0;
  627. Dir := East;
  628. NewDir := East;
  629. PLast := Point(DstRect.Left, DstRect.Top);
  630. CLast := GetSample(PLast.X, PLast.Y);
  631. AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
  632. UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
  633. while True do
  634. begin
  635. MainLoop:
  636. Diff := MaxInt;
  637. // forward
  638. with COORDS[Dir] do P := Point(PLast.X + X, PLast.Y + Y);
  639. if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  640. begin
  641. C := GetSample(P.X, P.Y);
  642. Diff := Intensity(ColorSub(C, CLast));
  643. EMMS;
  644. NewDir := Dir;
  645. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  646. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  647. InflateRect(P, UpdateRect);
  648. end;
  649. // left
  650. with COORDS[LEFT[Dir]] do P := Point(PLast.X + X, PLast.Y + Y);
  651. if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  652. begin
  653. C := GetSample(P.X, P.Y);
  654. D := Intensity(ColorSub(C, CLast));
  655. EMMS;
  656. if D < Diff then
  657. begin
  658. NewDir := LEFT[Dir];
  659. Diff := D;
  660. end;
  661. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  662. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  663. InflateRect(P, UpdateRect);
  664. end;
  665. // right
  666. with COORDS[RIGHT[Dir]] do P := Point(PLast.X + X, PLast.Y + Y);
  667. if PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  668. begin
  669. C := GetSample(P.X, P.Y);
  670. D := Intensity(ColorSub(C, CLast));
  671. EMMS;
  672. if D < Diff then
  673. begin
  674. NewDir := RIGHT[Dir];
  675. Diff := D;
  676. end;
  677. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  678. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  679. InflateRect(P, UpdateRect);
  680. end;
  681. if Diff = MaxInt then
  682. begin
  683. Dst.Changed(UpdateRect);
  684. while J < Visited.Height do
  685. begin
  686. while I < Visited.Width do
  687. begin
  688. if not Visited[I, J] then
  689. begin
  690. Visited[I, J] := True;
  691. PLast := Point(DstRect.Left + I, DstRect.Top + J);
  692. CLast := GetSample(PLast.X, PLast.Y);
  693. AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
  694. UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
  695. goto MainLoop;
  696. end;
  697. Inc(I);
  698. end;
  699. I := 0;
  700. Inc(J);
  701. end;
  702. Break;
  703. end;
  704. Dir := NewDir;
  705. with COORDS[Dir] do PLast := Point(PLast.X + X, PLast.Y + Y);
  706. CLast := Dst[PLast.X, PLast.Y];
  707. end;
  708. finally
  709. Visited.Free;
  710. end;
  711. end;
  712. { TMultithreadedRegularRasterizer }
  713. procedure TMultithreadedRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  714. var
  715. I: Integer;
  716. Threads: array of TScanLineRasterizerThread;
  717. Data: TLineRasterizerData;
  718. function CreateThread: TScanLineRasterizerThread;
  719. begin
  720. Result := TScanLineRasterizerThread.Create(True);
  721. Result.Data := @Data;
  722. Result.DstRect := DstRect;
  723. Result.GetSample := Sampler.GetSampleInt;
  724. Result.AssignColor := AssignColor;
  725. Result.Dst := Dst;
  726. {$IFDEF USETHREADRESUME}
  727. Result.Resume;
  728. {$ELSE}
  729. Result.Start;
  730. {$ENDIF}
  731. end;
  732. begin
  733. Data.ScanLine := DstRect.Top - 1;
  734. { Start Threads }
  735. SetLength(Threads, NumberOfProcessors);
  736. try
  737. for I := 0 to NumberOfProcessors - 1 do
  738. Threads[I] := CreateThread;
  739. { Wait for Threads to be ready }
  740. for I := 0 to High(Threads) do
  741. begin
  742. Threads[I].WaitFor;
  743. Threads[I].Free;
  744. end;
  745. finally
  746. Dst.Changed(DstRect);
  747. end;
  748. end;
  749. { TLineRasterizerThread }
  750. procedure TScanLineRasterizerThread.Execute;
  751. var
  752. ScanLine: Integer;
  753. I: Integer;
  754. P: PColor32;
  755. begin
  756. ScanLine := InterlockedIncrement(Data^.ScanLine);
  757. while ScanLine < DstRect.Bottom do
  758. begin
  759. P := @Dst.Bits[DstRect.Left + ScanLine * Dst.Width];
  760. for I := DstRect.Left to DstRect.Right - 1 do
  761. begin
  762. AssignColor(P^, GetSample(I, ScanLine));
  763. Inc(P);
  764. end;
  765. ScanLine := InterlockedIncrement(Data^.ScanLine);
  766. end;
  767. end;
  768. initialization
  769. NumberOfProcessors := GetProcessorCount;
  770. {$IFDEF USEMULTITHREADING}
  771. if NumberOfProcessors > 1 then
  772. DefaultRasterizerClass := TMultithreadedRegularRasterizer;
  773. {$ENDIF}
  774. end.