GR32_Rasterizers.pas 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  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. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. {$if defined(DCC) and (CompilerVersion >= 28.0)} // TODO : Test for PLATFORM_VCL when it is merged
  34. {$define USE_PPL} // Use Delphi's Parallel Programming Library (introduced XE7)
  35. {$ifend}
  36. uses
  37. Classes,
  38. GR32,
  39. GR32_Blend;
  40. type
  41. TAssignColor = procedure(var Dst: TColor32; Src: TColor32) of object;
  42. PCombineInfo = ^TCombineInfo;
  43. TCombineInfo = record
  44. SrcAlpha: Integer;
  45. DrawMode: TDrawMode;
  46. CombineMode: TCombineMode;
  47. CombineCallBack: TPixelCombineEvent;
  48. TransparentColor: TColor32;
  49. end;
  50. //------------------------------------------------------------------------------
  51. //
  52. // TRasterizer
  53. //
  54. //------------------------------------------------------------------------------
  55. // A base class for TCustomBitmap32-specific rasterizers.
  56. //------------------------------------------------------------------------------
  57. type
  58. TRasterizer = class(TThreadPersistent)
  59. private
  60. FSampler: TCustomSampler;
  61. FSrcAlpha: Integer;
  62. FBlendMemEx: TBlendMemEx;
  63. FCombineCallBack: TPixelCombineEvent;
  64. FAssignColor: TAssignColor;
  65. FTransparentColor: TColor32;
  66. procedure SetSampler(const Value: TCustomSampler);
  67. procedure SetCombineInfo(const CombineInfo: TCombineInfo);
  68. procedure AssignColorOpaque(var Dst: TColor32; Src: TColor32);
  69. procedure AssignColorBlend(var Dst: TColor32; Src: TColor32);
  70. procedure AssignColorCustom(var Dst: TColor32; Src: TColor32);
  71. procedure AssignColorTransparent(var Dst: TColor32; Src: TColor32);
  72. protected
  73. procedure AssignTo(Dst: TPersistent); override;
  74. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); virtual; abstract;
  75. property AssignColor: TAssignColor read FAssignColor write FAssignColor;
  76. public
  77. constructor Create; override;
  78. procedure Assign(Source: TPersistent); override;
  79. procedure Rasterize(Dst: TCustomBitmap32); overload;
  80. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect); overload;
  81. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect; const CombineInfo: TCombineInfo); overload;
  82. procedure Rasterize(Dst: TCustomBitmap32; const DstRect: TRect; Src: TCustomBitmap32); overload;
  83. published
  84. property Sampler: TCustomSampler read FSampler write SetSampler;
  85. end;
  86. TRasterizerClass = class of TRasterizer;
  87. //------------------------------------------------------------------------------
  88. //
  89. // TRegularSamplingRasterizer
  90. //
  91. //------------------------------------------------------------------------------
  92. // This rasterizer simply picks one sample for each pixel in the output bitmap.
  93. //------------------------------------------------------------------------------
  94. type
  95. TRegularRasterizer = class(TRasterizer)
  96. private
  97. FUpdateRowCount: Integer;
  98. protected
  99. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  100. public
  101. constructor Create; override;
  102. published
  103. property UpdateRowCount: Integer read FUpdateRowCount write FUpdateRowCount;
  104. end;
  105. //------------------------------------------------------------------------------
  106. //
  107. // TSwizzlingRasterizer
  108. //
  109. //------------------------------------------------------------------------------
  110. // An interesting rasterization method where sample locations are choosen
  111. // according to a fractal pattern called 'swizzling'. With a slight
  112. // modification to the algorithm this routine will actually yield the
  113. // well-known sierpinski triangle fractal. An advantage with this pattern
  114. // is that it may benefit from local coherency in the sampling method used.
  115. //------------------------------------------------------------------------------
  116. type
  117. TSwizzlingRasterizer = class(TRasterizer)
  118. private
  119. FBlockSize: Integer;
  120. procedure SetBlockSize(const Value: Integer);
  121. protected
  122. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  123. public
  124. constructor Create; override;
  125. published
  126. property BlockSize: Integer read FBlockSize write SetBlockSize default 3;
  127. end;
  128. //------------------------------------------------------------------------------
  129. //
  130. // TProgressiveRasterizer
  131. //
  132. //------------------------------------------------------------------------------
  133. // This class will perform rasterization in a progressive manner. It performs
  134. // subsampling with a block size of 2^n and will successively decrease n in
  135. // each iteration until n equals zero.
  136. //------------------------------------------------------------------------------
  137. type
  138. TProgressiveRasterizer = class(TRasterizer)
  139. private
  140. FSteps: Integer;
  141. FUpdateRows: Boolean;
  142. procedure SetSteps(const Value: Integer);
  143. procedure SetUpdateRows(const Value: Boolean);
  144. protected
  145. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  146. public
  147. constructor Create; override;
  148. published
  149. property Steps: Integer read FSteps write SetSteps default 4;
  150. property UpdateRows: Boolean read FUpdateRows write SetUpdateRows default True;
  151. end;
  152. //------------------------------------------------------------------------------
  153. //
  154. // TTesseralRasterizer
  155. //
  156. //------------------------------------------------------------------------------
  157. // This is a recursive rasterization method. It uses a divide-and-conquer
  158. // scheme to subdivide blocks vertically and horizontally into smaller blocks.
  159. //------------------------------------------------------------------------------
  160. type
  161. TTesseralRasterizer = class(TRasterizer)
  162. protected
  163. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  164. end;
  165. //------------------------------------------------------------------------------
  166. //
  167. // TContourRasterizer
  168. //
  169. //------------------------------------------------------------------------------
  170. type
  171. TContourRasterizer = class(TRasterizer)
  172. protected
  173. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  174. end;
  175. //------------------------------------------------------------------------------
  176. //
  177. // TDraftRasterizer
  178. //
  179. //------------------------------------------------------------------------------
  180. // A rasterizer that trades quality for performance by pixelating the output.
  181. // Can be used to show live preview during long operations.
  182. // Adapted from TBoxRasterizer by Marc Lafon, 16 oct 2005
  183. //------------------------------------------------------------------------------
  184. type
  185. TDraftRasterizer = class(TRasterizer)
  186. private
  187. FPixelSize: Integer;
  188. procedure SetPixelSize(const Value: Integer);
  189. protected
  190. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  191. public
  192. constructor Create; override;
  193. published
  194. // Size of output pixels
  195. property PixelSize: Integer read FPixelSize write SetPixelSize default 4;
  196. end;
  197. //------------------------------------------------------------------------------
  198. //
  199. // TThreadRegularRasterizer
  200. //
  201. //------------------------------------------------------------------------------
  202. // Multi-threaded rasterizer using TTread
  203. //------------------------------------------------------------------------------
  204. // Warning: This rasterizer will have terrible performance unless the
  205. // rasterization process is more costly than the thread setup and destruction
  206. // (which happens once for every call to DoRasterize).
  207. // Don't assume that threads will solve your performance problems; Benchmark!
  208. // If possible, use TParallelRegularRasterizer or TTaskRegularRasterizer instead.
  209. //------------------------------------------------------------------------------
  210. type
  211. TThreadRegularRasterizer = class(TRasterizer)
  212. protected
  213. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  214. end {$if defined(USE_PPL)}deprecated 'Use TMultithreadedRegularRasterizer instead'{$ifend};
  215. //------------------------------------------------------------------------------
  216. //
  217. // TParallelRegularRasterizer
  218. //
  219. //------------------------------------------------------------------------------
  220. // Multi-threaded rasterizer using TParallel.For
  221. // Note: First invocation can incur a performance penalty as the thread pool is
  222. // initialized.
  223. //------------------------------------------------------------------------------
  224. {$if defined(USE_PPL)}
  225. type
  226. TParallelRegularRasterizer = class(TRasterizer)
  227. protected
  228. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  229. end;
  230. {$ifend}
  231. //------------------------------------------------------------------------------
  232. //
  233. // TTaskRegularRasterizer
  234. //
  235. //------------------------------------------------------------------------------
  236. // Multi-threaded rasterizer using TTask
  237. // Note: First invocation can incur a performance penalty as the thread pool is
  238. // initialized.
  239. //------------------------------------------------------------------------------
  240. {$if defined(USE_PPL)}
  241. type
  242. TTaskRegularRasterizer = class(TRasterizer)
  243. protected
  244. procedure DoRasterize(Dst: TCustomBitmap32; DstRect: TRect); override;
  245. end;
  246. {$ifend}
  247. //------------------------------------------------------------------------------
  248. //
  249. // TMultithreadedRegularRasterizer
  250. //
  251. //------------------------------------------------------------------------------
  252. // Multi-threaded rasterizer using whatever is available.
  253. //------------------------------------------------------------------------------
  254. type
  255. {$if defined(USE_PPL)}
  256. TMultithreadedRegularRasterizer = class(TParallelRegularRasterizer);
  257. {$else}
  258. TMultithreadedRegularRasterizer = class(TThreadRegularRasterizer);
  259. {$ifend}
  260. //------------------------------------------------------------------------------
  261. //
  262. // Auxiliary routines
  263. //
  264. //------------------------------------------------------------------------------
  265. function CombineInfo(Bitmap: TCustomBitmap32): TCombineInfo;
  266. const
  267. DEFAULT_COMBINE_INFO: TCombineInfo = (
  268. SrcAlpha: $FF;
  269. DrawMode: dmOpaque;
  270. CombineMode: cmBlend;
  271. CombineCallBack: nil;
  272. TransparentColor: clBlack32;
  273. );
  274. //------------------------------------------------------------------------------
  275. var
  276. DefaultRasterizerClass: TRasterizerClass = TRegularRasterizer;
  277. NumberOfProcessors: Integer = 1;
  278. //------------------------------------------------------------------------------
  279. //------------------------------------------------------------------------------
  280. //------------------------------------------------------------------------------
  281. implementation
  282. uses
  283. {$ifndef FPC}
  284. System.SyncObjs,
  285. {$endif}
  286. {$if defined(USE_PPL)}
  287. System.Types,
  288. System.SysUtils,
  289. System.Threading,
  290. {$ifend}
  291. Math,
  292. GR32_Math,
  293. GR32_System,
  294. GR32_LowLevel,
  295. GR32_Resamplers,
  296. GR32_Containers,
  297. GR32_OrdinalMaps;
  298. type
  299. TCustomBitmap32Access = class(TCustomBitmap32);
  300. //------------------------------------------------------------------------------
  301. //
  302. // Auxiliary routines
  303. //
  304. //------------------------------------------------------------------------------
  305. function CombineInfo(Bitmap: TCustomBitmap32): TCombineInfo;
  306. begin
  307. with Result do
  308. begin
  309. SrcAlpha := Bitmap.MasterAlpha;
  310. DrawMode := Bitmap.DrawMode;
  311. CombineMode := Bitmap.CombineMode;
  312. CombineCallBack := Bitmap.OnPixelCombine;
  313. if (DrawMode = dmCustom) and not Assigned(CombineCallBack) then
  314. DrawMode := dmOpaque;
  315. TransparentColor := Bitmap.OuterColor;
  316. end;
  317. end;
  318. //------------------------------------------------------------------------------
  319. //
  320. // TRasterizer
  321. //
  322. //------------------------------------------------------------------------------
  323. procedure TRasterizer.AssignColorBlend(var Dst: TColor32; Src: TColor32);
  324. begin
  325. FBlendMemEx(Src, Dst, FSrcAlpha);
  326. end;
  327. procedure TRasterizer.AssignColorOpaque(var Dst: TColor32; Src: TColor32);
  328. begin
  329. Dst := Src;
  330. end;
  331. procedure TRasterizer.AssignColorCustom(var Dst: TColor32; Src: TColor32);
  332. begin
  333. FCombineCallBack(Src, Dst, FSrcAlpha);
  334. end;
  335. procedure TRasterizer.AssignColorTransparent(var Dst: TColor32;
  336. Src: TColor32);
  337. begin
  338. if Src <> FTransparentColor then Dst := Src;
  339. end;
  340. procedure TRasterizer.AssignTo(Dst: TPersistent);
  341. begin
  342. if Dst is TRasterizer then
  343. SmartAssign(Self, Dst)
  344. else
  345. inherited;
  346. end;
  347. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect;
  348. Src: TCustomBitmap32);
  349. begin
  350. Rasterize(Dst, DstRect, CombineInfo(Src));
  351. end;
  352. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect;
  353. const CombineInfo: TCombineInfo);
  354. begin
  355. SetCombineInfo(CombineInfo);
  356. Rasterize(Dst, DstRect);
  357. end;
  358. procedure TRasterizer.SetCombineInfo(const CombineInfo: TCombineInfo);
  359. begin
  360. with CombineInfo do
  361. begin
  362. FTransparentColor := TransparentColor;
  363. FSrcAlpha := SrcAlpha;
  364. FBlendMemEx := BLEND_MEM_EX[CombineMode]^;
  365. FCombineCallBack := CombineCallBack;
  366. case DrawMode of
  367. dmOpaque: FAssignColor := AssignColorOpaque;
  368. dmBlend: FAssignColor := AssignColorBlend;
  369. dmTransparent: FAssignColor := AssignColorTransparent;
  370. else
  371. if Assigned(FCombineCallback) then
  372. FAssignColor := AssignColorCustom
  373. else
  374. FAssignColor := AssignColorBlend;
  375. end;
  376. end;
  377. end;
  378. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32; const DstRect: TRect);
  379. var
  380. UpdateCount: Integer;
  381. R: TRect;
  382. begin
  383. UpdateCount := TCustomBitmap32Access(Dst).UpdateCount;
  384. if Assigned(FSampler) then
  385. begin
  386. FSampler.PrepareSampling;
  387. GR32.IntersectRect(R, DstRect, Dst.BoundsRect);
  388. if FSampler.HasBounds then
  389. GR32.IntersectRect(R, DstRect, MakeRect(FSampler.GetSampleBounds, rrOutside));
  390. try
  391. DoRasterize(Dst, R);
  392. finally
  393. while TCustomBitmap32Access(Dst).UpdateCount > UpdateCount do
  394. TCustomBitmap32Access(Dst).EndUpdate;
  395. FSampler.FinalizeSampling;
  396. end;
  397. end;
  398. end;
  399. procedure TRasterizer.SetSampler(const Value: TCustomSampler);
  400. begin
  401. if FSampler <> Value then
  402. begin
  403. FSampler := Value;
  404. Changed;
  405. end;
  406. end;
  407. procedure TRasterizer.Rasterize(Dst: TCustomBitmap32);
  408. begin
  409. Rasterize(Dst, Dst.BoundsRect);
  410. end;
  411. constructor TRasterizer.Create;
  412. begin
  413. inherited;
  414. SetCombineInfo(DEFAULT_COMBINE_INFO);
  415. end;
  416. procedure TRasterizer.Assign(Source: TPersistent);
  417. begin
  418. BeginUpdate;
  419. try
  420. if Source is TCustomBitmap32 then
  421. SetCombineInfo(CombineInfo(TCustomBitmap32(Source)))
  422. else
  423. inherited;
  424. Changed;
  425. finally
  426. EndUpdate;
  427. end;
  428. end;
  429. //------------------------------------------------------------------------------
  430. //
  431. // TRegularRasterizer
  432. //
  433. //------------------------------------------------------------------------------
  434. constructor TRegularRasterizer.Create;
  435. begin
  436. inherited;
  437. FUpdateRowCount := 0;
  438. end;
  439. procedure TRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  440. var
  441. I, J, UpdateCount: Integer;
  442. P: PColor32;
  443. GetSample: TGetSampleInt;
  444. begin
  445. GetSample := FSampler.GetSampleInt;
  446. UpdateCount := 0;
  447. for J := DstRect.Top to DstRect.Bottom - 1 do
  448. begin
  449. P := @Dst.Bits[DstRect.Left + J * Dst.Width];
  450. for I := DstRect.Left to DstRect.Right - 1 do
  451. begin
  452. AssignColor(P^, GetSample(I, J));
  453. Inc(P);
  454. end;
  455. Inc(UpdateCount);
  456. if UpdateCount = FUpdateRowCount then
  457. begin
  458. Dst.Changed(Rect(DstRect.Left, J - UpdateCount, DstRect.Right, J));
  459. UpdateCount := 0;
  460. end;
  461. end;
  462. with DstRect do
  463. Dst.Changed(Rect(Left, Bottom - UpdateCount - 1, Right, Bottom));
  464. end;
  465. //------------------------------------------------------------------------------
  466. //
  467. // TSwizzlingRasterizer
  468. //
  469. //------------------------------------------------------------------------------
  470. constructor TSwizzlingRasterizer.Create;
  471. begin
  472. inherited;
  473. FBlockSize := 3;
  474. end;
  475. procedure TSwizzlingRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  476. var
  477. I, L, T, W, H, Size, RowSize, D: Integer;
  478. P1, P2, PBlock: TPoint;
  479. GetSample: TGetSampleInt;
  480. ForwardBuffer: array of Integer;
  481. function GetDstCoord(P: TPoint): TPoint;
  482. var
  483. XI, YI: Integer;
  484. begin
  485. Result := P;
  486. Inc(Result.X);
  487. Inc(Result.Y);
  488. XI := ForwardBuffer[Result.X];
  489. YI := ForwardBuffer[Result.Y];
  490. if XI <= YI then
  491. Dec(Result.Y, 1 shl XI)
  492. else
  493. Dec(Result.X, 1 shl (YI + 1));
  494. if Result.Y >= H then
  495. begin
  496. Result.Y := P.Y + 1 shl YI;
  497. Result.X := P.X;
  498. Result := GetDstCoord(Result);
  499. end;
  500. if Result.X >= W then
  501. begin
  502. Result.X := P.X + 1 shl XI;
  503. Result.Y := P.Y;
  504. Result := GetDstCoord(Result);
  505. end;
  506. end;
  507. begin
  508. W := DstRect.Right - DstRect.Left;
  509. H := DstRect.Bottom - DstRect.Top;
  510. L := DstRect.Left; T := DstRect.Top;
  511. Size := NextPowerOf2(Max(W, H));
  512. SetLength(ForwardBuffer, Size + 1);
  513. I := 2;
  514. while I <= Size do
  515. begin
  516. ForwardBuffer[I] := ForwardBuffer[I shr 1] + 1;
  517. Inc(I, 2);
  518. end;
  519. Size := W * H - 1;
  520. GetSample := FSampler.GetSampleInt;
  521. D := 1 shl FBlockSize;
  522. PBlock := GR32.Point(L + D, T + D);
  523. P1 := GR32.Point(-1, 0);
  524. RowSize := Dst.Width;
  525. for I := 0 to Size do
  526. begin
  527. P1 := GetDstCoord(P1);
  528. P2.X := L + P1.X;
  529. P2.Y := T + P1.Y;
  530. AssignColor(Dst.Bits[P2.X + P2.Y * RowSize], GetSample(P2.X, P2.Y));
  531. // Invalidate the current block
  532. if (P2.X >= PBlock.X) or (P2.Y >= PBlock.Y) then
  533. begin
  534. Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
  535. PBlock.X := P2.X + D;
  536. PBlock.Y := P2.Y + D;
  537. end;
  538. end;
  539. Dst.Changed(Rect(PBlock.X - D, PBlock.Y - D, PBlock.X, PBlock.Y));
  540. end;
  541. procedure TSwizzlingRasterizer.SetBlockSize(const Value: Integer);
  542. begin
  543. if FBlockSize <> Value then
  544. begin
  545. FBlockSize := Value;
  546. Changed;
  547. end;
  548. end;
  549. //------------------------------------------------------------------------------
  550. //
  551. // TProgressiveRasterizer
  552. //
  553. //------------------------------------------------------------------------------
  554. constructor TProgressiveRasterizer.Create;
  555. begin
  556. inherited;
  557. FSteps := 4;
  558. FUpdateRows := True;
  559. end;
  560. {$DEFINE UseInternalFill}
  561. procedure TProgressiveRasterizer.DoRasterize(Dst: TCustomBitmap32;
  562. DstRect: TRect);
  563. var
  564. I, J, Shift, W, H, B, Wk, Hk, X, Y: Integer;
  565. DoUpdate: Boolean;
  566. OnChanged: TAreaChangedEvent;
  567. Step: Integer;
  568. GetSample: TGetSampleInt;
  569. {$IFDEF UseInternalFill}
  570. Bits: PColor32Array;
  571. procedure IntFillRect(X1, Y1, X2, Y2: Integer; C: TColor32);
  572. var
  573. Y: Integer;
  574. P: PColor32Array;
  575. begin
  576. for Y := Y1 to Y2 - 1 do
  577. begin
  578. P := Pointer(@Bits[Y * W]);
  579. FillLongword(P[X1], X2 - X1, C);
  580. end;
  581. end;
  582. {$ENDIF}
  583. begin
  584. GetSample := FSampler.GetSampleInt;
  585. OnChanged := Dst.OnAreaChanged;
  586. {$IFDEF UseInternalFill}
  587. Bits := Dst.Bits;
  588. {$ENDIF}
  589. DoUpdate := (TCustomBitmap32Access(Dst).UpdateCount = 0) and Assigned(OnChanged);
  590. W := DstRect.Right - DstRect.Left;
  591. H := DstRect.Bottom - DstRect.Top;
  592. J := DstRect.Top;
  593. Step := 1 shl FSteps;
  594. while J < DstRect.Bottom do
  595. begin
  596. I := DstRect.Left;
  597. B := Min(J + Step, DstRect.Bottom);
  598. while I < DstRect.Right - Step do
  599. begin
  600. {$IFDEF UseInternalFill}
  601. IntFillRect(I, J, I + Step, B, GetSample(I, J));
  602. {$ELSE}
  603. Dst.FillRect(I, J, I + Step, B, GetSample(I, J));
  604. {$ENDIF}
  605. Inc(I, Step);
  606. end;
  607. {$IFDEF UseInternalFill}
  608. IntFillRect(I, J, DstRect.Right, B, GetSample(I, J));
  609. if DoUpdate and FUpdateRows then
  610. OnChanged(Dst, Rect(DstRect.Left, J, DstRect.Right, B), AREAINFO_RECT);
  611. {$ELSE}
  612. Dst.FillRect(I, J, DstRect.Right, B, GetSample(I, J));
  613. {$ENDIF}
  614. Inc(J, Step);
  615. end;
  616. if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
  617. Shift := FSteps;
  618. while Step > 1 do
  619. begin
  620. Dec(Shift);
  621. Step := Step div 2;
  622. Wk := W div Step - 1;
  623. Hk := H div Step;
  624. for J := 0 to Hk do
  625. begin
  626. Y := DstRect.Top + J shl Shift;
  627. B := Min(Y + Step, DstRect.Bottom);
  628. if Odd(J) then
  629. for I := 0 to Wk do
  630. begin
  631. X := DstRect.Left + I shl Shift;
  632. {$IFDEF UseInternalFill}
  633. IntFillRect(X, Y, X + Step, B, GetSample(X, Y));
  634. {$ELSE}
  635. Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
  636. {$ENDIF}
  637. end
  638. else
  639. for I := 0 to Wk do
  640. if Odd(I) then
  641. begin
  642. X := DstRect.Left + I shl Shift;
  643. {$IFDEF UseInternalFill}
  644. IntFillRect(X, Y, X + Step, B, GetSample(X, Y));
  645. {$ELSE}
  646. Dst.FillRect(X, Y, X + Step, B, GetSample(X, Y));
  647. {$ENDIF}
  648. end;
  649. X := DstRect.Left + Wk shl Shift;
  650. {$IFDEF UseInternalFill}
  651. IntFillRect(X, Y, DstRect.Right, B, GetSample(X, Y));
  652. if FUpdateRows and DoUpdate then
  653. OnChanged(Dst, Rect(DstRect.Left, Y, DstRect.Right, B), AREAINFO_RECT);
  654. {$ELSE}
  655. Dst.FillRect(X, Y, DstRect.Right, B, GetSample(X, Y));
  656. {$ENDIF}
  657. end;
  658. if DoUpdate and (not FUpdateRows) then OnChanged(Dst, DstRect, AREAINFO_RECT);
  659. end;
  660. end;
  661. procedure TProgressiveRasterizer.SetSteps(const Value: Integer);
  662. begin
  663. if FSteps <> Value then
  664. begin
  665. FSteps := Value;
  666. Changed;
  667. end;
  668. end;
  669. procedure TProgressiveRasterizer.SetUpdateRows(const Value: Boolean);
  670. begin
  671. if FUpdateRows <> Value then
  672. begin
  673. FUpdateRows := Value;
  674. Changed;
  675. end;
  676. end;
  677. //------------------------------------------------------------------------------
  678. //
  679. // TTesseralRasterizer
  680. //
  681. //------------------------------------------------------------------------------
  682. procedure TTesseralRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  683. var
  684. W, H, I: Integer;
  685. GetSample: TGetSampleInt;
  686. procedure SplitHorizontal(X, Y, Width, Height: Integer); forward;
  687. procedure SplitVertical(X, Y, Width, Height: Integer);
  688. var
  689. HalfWidth, X2, I: Integer;
  690. begin
  691. HalfWidth := Width div 2;
  692. if HalfWidth > 0 then
  693. begin
  694. X2 := X + HalfWidth;
  695. for I := Y + 1 to Y + Height - 1 do
  696. AssignColor(Dst.PixelPtr[X2, I]^, GetSample(X2, I));
  697. Dst.Changed(Rect(X2, Y, X2 + 1, Y + Height));
  698. SplitHorizontal(X, Y, HalfWidth, Height);
  699. SplitHorizontal(X2, Y, Width - HalfWidth, Height);
  700. end;
  701. end;
  702. procedure SplitHorizontal(X, Y, Width, Height: Integer);
  703. var
  704. HalfHeight, Y2, I: Integer;
  705. begin
  706. HalfHeight := Height div 2;
  707. if HalfHeight > 0 then
  708. begin
  709. Y2 := Y + HalfHeight;
  710. for I := X + 1 to X + Width - 1 do
  711. AssignColor(Dst.PixelPtr[I, Y2]^, GetSample(I, Y2));
  712. Dst.Changed(Rect(X, Y2, X + Width, Y2 + 1));
  713. SplitVertical(X, Y, Width, HalfHeight);
  714. SplitVertical(X, Y2, Width, Height - HalfHeight);
  715. end;
  716. end;
  717. begin
  718. GetSample := FSampler.GetSampleInt;
  719. with DstRect do
  720. begin
  721. W := Right - Left;
  722. H := Bottom - Top;
  723. for I := Left to Right - 1 do
  724. AssignColor(Dst.PixelPtr[I, Top]^, GetSample(I, Top));
  725. Dst.Changed(Rect(Left, Top, Right, Top + 1));
  726. for I := Top to Bottom - 1 do
  727. AssignColor(Dst.PixelPtr[Left, I]^, GetSample(Left, I));
  728. Dst.Changed(Rect(Left, Top, Left + 1, Bottom));
  729. if W > H then
  730. SplitVertical(Left, Top, W, H)
  731. else
  732. SplitHorizontal(Left, Top, W, H);
  733. end;
  734. end;
  735. //------------------------------------------------------------------------------
  736. //
  737. // TContourRasterizer
  738. //
  739. //------------------------------------------------------------------------------
  740. procedure InflateRect(const P: TPoint; var R: TRect);
  741. begin
  742. if P.X < R.Left then R.Left := P.X;
  743. if P.Y < R.Top then R.Top := P.Y;
  744. if P.X >= R.Right then R.Right := P.X + 1;
  745. if P.Y >= R.Bottom then R.Bottom := P.Y + 1;
  746. end;
  747. procedure TContourRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  748. type
  749. TDirection = (North, East, South, West);
  750. var
  751. I, J, D, Diff: Integer;
  752. C, CLast: TColor32;
  753. P, PLast: TPoint;
  754. GetSample: TGetSampleInt;
  755. NewDir, Dir: TDirection;
  756. Visited: TBooleanMap;
  757. UpdateRect: TRect;
  758. const
  759. LEFT: array[TDirection] of TDirection = (West, North, East, South);
  760. RIGHT: array[TDirection] of TDirection = (East, South, West, North);
  761. COORDS: array[TDirection] of TPoint = ((X: 0; Y: -1), (X: 1; Y: 0), (X: 0; Y: 1), (X: -1; Y: 0));
  762. label
  763. MainLoop;
  764. begin
  765. GetSample := FSampler.GetSampleInt;
  766. Visited := TBooleanMap.Create;
  767. try
  768. with DstRect do
  769. Visited.SetSize(Right - Left, Bottom - Top);
  770. I := 0; J := 0;
  771. Dir := East;
  772. NewDir := East;
  773. PLast := GR32.Point(DstRect.Left, DstRect.Top);
  774. CLast := GetSample(PLast.X, PLast.Y);
  775. AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
  776. UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
  777. while True do
  778. begin
  779. MainLoop:
  780. Diff := MaxInt;
  781. // forward
  782. with COORDS[Dir] do P := GR32.Point(PLast.X + X, PLast.Y + Y);
  783. if GR32.PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  784. begin
  785. C := GetSample(P.X, P.Y);
  786. Diff := Intensity(ColorSub(C, CLast));
  787. NewDir := Dir;
  788. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  789. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  790. InflateRect(P, UpdateRect);
  791. end;
  792. // left
  793. with COORDS[LEFT[Dir]] do P := GR32.Point(PLast.X + X, PLast.Y + Y);
  794. if GR32.PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  795. begin
  796. C := GetSample(P.X, P.Y);
  797. D := Intensity(ColorSub(C, CLast));
  798. if D < Diff then
  799. begin
  800. NewDir := LEFT[Dir];
  801. Diff := D;
  802. end;
  803. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  804. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  805. InflateRect(P, UpdateRect);
  806. end;
  807. // right
  808. with COORDS[RIGHT[Dir]] do P := GR32.Point(PLast.X + X, PLast.Y + Y);
  809. if GR32.PtInRect(DstRect, P) and (not Visited[P.X, P.Y]) then
  810. begin
  811. C := GetSample(P.X, P.Y);
  812. D := Intensity(ColorSub(C, CLast));
  813. if D < Diff then
  814. begin
  815. NewDir := RIGHT[Dir];
  816. Diff := D;
  817. end;
  818. AssignColor(Dst.PixelPtr[P.X, P.Y]^, C);
  819. Visited[P.X - DstRect.Left, P.Y - DstRect.Top] := True;
  820. InflateRect(P, UpdateRect);
  821. end;
  822. if Diff = MaxInt then
  823. begin
  824. Dst.Changed(UpdateRect);
  825. while J < Visited.Height do
  826. begin
  827. while I < Visited.Width do
  828. begin
  829. if not Visited[I, J] then
  830. begin
  831. Visited[I, J] := True;
  832. PLast := GR32.Point(DstRect.Left + I, DstRect.Top + J);
  833. CLast := GetSample(PLast.X, PLast.Y);
  834. AssignColor(Dst.PixelPtr[PLast.X, PLast.Y]^, CLast);
  835. UpdateRect := Rect(PLast.X, PLast.Y, PLast.X + 1, PLast.Y + 1);
  836. goto MainLoop;
  837. end;
  838. Inc(I);
  839. end;
  840. I := 0;
  841. Inc(J);
  842. end;
  843. Break;
  844. end;
  845. Dir := NewDir;
  846. with COORDS[Dir] do PLast := GR32.Point(PLast.X + X, PLast.Y + Y);
  847. CLast := Dst[PLast.X, PLast.Y];
  848. end;
  849. finally
  850. Visited.Free;
  851. end;
  852. end;
  853. //------------------------------------------------------------------------------
  854. //
  855. // TDraftRasterizer
  856. //
  857. //------------------------------------------------------------------------------
  858. constructor TDraftRasterizer.Create;
  859. begin
  860. inherited;
  861. FPixelSize := 4;
  862. end;
  863. procedure TDraftRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  864. var
  865. r: TRect;
  866. GetSample: TGetSampleInt;
  867. begin
  868. GetSample := Sampler.GetSampleInt;
  869. Dst.BeginLockUpdate;
  870. try
  871. r.Top := DstRect.Top;
  872. r.Bottom := r.Top;
  873. while r.Top < DstRect.Bottom do
  874. begin
  875. Inc(r.Bottom, FPixelSize);
  876. if (r.Bottom > DstRect.Bottom) then
  877. r.Bottom := DstRect.Bottom;
  878. r.Left := DstRect.Left;
  879. r.Right := r.Left + FPixelSize;
  880. while r.Right < DstRect.Right do
  881. begin
  882. Dst.FillRect(r.Left, r.Top, r.Right, r.Bottom, GetSample(r.Left, r.Top));
  883. r.Left := r.Right;
  884. Inc(r.Right, FPixelSize);
  885. end;
  886. Dst.FillRect(r.Left, r.Top, DstRect.Right, r.Bottom, GetSample(r.Left, r.Top));
  887. r.Top := r.Bottom;
  888. end;
  889. finally
  890. Dst.EndLockUpdate;
  891. end;
  892. if (TCustomBitmap32Access(Dst).UpdateCount = 0) and Assigned(Dst.OnAreaChanged) then
  893. Dst.OnAreaChanged(Dst, DstRect, AREAINFO_RECT);
  894. end;
  895. procedure TDraftRasterizer.SetPixelSize(const Value: Integer);
  896. begin
  897. if (FPixelSize <> Value) and (Value > 1) then
  898. begin
  899. FPixelSize := Value;
  900. Changed;
  901. end;
  902. end;
  903. //------------------------------------------------------------------------------
  904. //
  905. // TParallelRegularRasterizer
  906. //
  907. //------------------------------------------------------------------------------
  908. {$if defined(USE_PPL)}
  909. procedure TParallelRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  910. begin
  911. TParallel.For(DstRect.Top, DstRect.Bottom-1,
  912. procedure(ScanLine: integer)
  913. var
  914. i: Integer;
  915. p: PColor32;
  916. begin
  917. p := @Dst.Bits[DstRect.Left + ScanLine * Dst.Width];
  918. for i := DstRect.Left to DstRect.Right - 1 do
  919. begin
  920. AssignColor(p^, Sampler.GetSampleInt(i, ScanLine));
  921. Inc(p);
  922. end;
  923. end);
  924. Dst.Changed(DstRect);
  925. end;
  926. {$ifend}
  927. //------------------------------------------------------------------------------
  928. //
  929. // TTaskRegularRasterizer
  930. //
  931. //------------------------------------------------------------------------------
  932. {$if defined(USE_PPL)}
  933. type
  934. TScanlineProc = reference to procedure(AFromIndex, AToIndex: integer);
  935. procedure TTaskRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  936. // Partitioning and task setup based on idea by Stefan Glienke
  937. // https://stackoverflow.com/a/27542557
  938. procedure CalcPartBounds(Low, High, Count, Index: Integer; out Min, Max: Integer);
  939. var
  940. Len: Integer;
  941. begin
  942. Len := High - Low + 1;
  943. Min := (Len div Count) * Index;
  944. if Index + 1 < Count then
  945. Max := Len div Count * (Index + 1) - 1
  946. else
  947. Max := Len - 1;
  948. end;
  949. function GetWorker(const ScanlineProc: TScanlineProc; Min, Max: Integer): ITask;
  950. begin
  951. Result := TTask.Run(
  952. procedure
  953. begin
  954. ScanlineProc(Min, Max);
  955. end);
  956. end;
  957. var
  958. Workers: TArray<ITask>;
  959. i: integer;
  960. Min, Max: integer;
  961. begin
  962. SetLength(Workers, NumberOfProcessors);
  963. for i := 0 to High(Workers) do
  964. begin
  965. CalcPartBounds(DstRect.Top, DstRect.Bottom-1, NumberOfProcessors, i, Min, Max);
  966. Workers[i] := GetWorker(
  967. procedure (AFromScanLine, AToScanLine: integer)
  968. var
  969. i: Integer;
  970. p: PColor32;
  971. begin
  972. while (AFromScanLine <= AToScanLine) do
  973. begin
  974. p := @Dst.Bits[DstRect.Left + AFromScanLine * Dst.Width];
  975. for i := DstRect.Left to DstRect.Right - 1 do
  976. begin
  977. AssignColor(p^, Sampler.GetSampleInt(i, AFromScanLine));
  978. Inc(p);
  979. end;
  980. Inc(AFromScanLine);
  981. end;
  982. end, Min, Max);
  983. end;
  984. TTask.WaitForAll(Workers);
  985. Dst.Changed(DstRect);
  986. end;
  987. {$ifend}
  988. //------------------------------------------------------------------------------
  989. //
  990. // TThreadRegularRasterizer
  991. //
  992. //------------------------------------------------------------------------------
  993. type
  994. TLineRasterizerData = record
  995. ScanLine: Integer;
  996. end;
  997. PLineRasterizerData = ^TLineRasterizerData;
  998. TScanLineRasterizerThread = class(TThread)
  999. protected
  1000. Data: PLineRasterizerData;
  1001. DstRect: TRect;
  1002. Dst: TCustomBitmap32;
  1003. GetSample: TGetSampleInt;
  1004. AssignColor: TAssignColor;
  1005. procedure Execute; override;
  1006. end;
  1007. procedure TScanLineRasterizerThread.Execute;
  1008. var
  1009. ScanLine: Integer;
  1010. I: Integer;
  1011. P: PColor32;
  1012. begin
  1013. {$ifndef FPC}
  1014. ScanLine := TInterlocked.Increment(Data^.ScanLine);
  1015. {$else}
  1016. ScanLine := InterlockedIncrement(Data^.ScanLine);
  1017. {$endif}
  1018. while ScanLine < DstRect.Bottom do
  1019. begin
  1020. P := @Dst.Bits[DstRect.Left + ScanLine * Dst.Width];
  1021. for I := DstRect.Left to DstRect.Right - 1 do
  1022. begin
  1023. AssignColor(P^, GetSample(I, ScanLine));
  1024. Inc(P);
  1025. end;
  1026. {$ifndef FPC}
  1027. ScanLine := TInterlocked.Increment(Data^.ScanLine);
  1028. {$else}
  1029. ScanLine := InterlockedIncrement(Data^.ScanLine);
  1030. {$endif}
  1031. end;
  1032. end;
  1033. procedure TThreadRegularRasterizer.DoRasterize(Dst: TCustomBitmap32; DstRect: TRect);
  1034. var
  1035. I: Integer;
  1036. Threads: array of TScanLineRasterizerThread;
  1037. Data: TLineRasterizerData;
  1038. function CreateThread: TScanLineRasterizerThread;
  1039. begin
  1040. Result := TScanLineRasterizerThread.Create(True);
  1041. Result.Data := @Data;
  1042. Result.DstRect := DstRect;
  1043. Result.GetSample := Sampler.GetSampleInt;
  1044. Result.AssignColor := AssignColor;
  1045. Result.Dst := Dst;
  1046. {$IFDEF USETHREADRESUME}
  1047. Result.Resume;
  1048. {$ELSE}
  1049. Result.Start;
  1050. {$ENDIF}
  1051. end;
  1052. begin
  1053. Data.ScanLine := DstRect.Top - 1;
  1054. { Start Threads }
  1055. SetLength(Threads, NumberOfProcessors);
  1056. try
  1057. for I := 0 to NumberOfProcessors - 1 do
  1058. Threads[I] := CreateThread;
  1059. { Wait for Threads to be ready }
  1060. for I := 0 to High(Threads) do
  1061. begin
  1062. Threads[I].WaitFor;
  1063. Threads[I].Free;
  1064. end;
  1065. finally
  1066. Dst.Changed(DstRect);
  1067. end;
  1068. end;
  1069. //------------------------------------------------------------------------------
  1070. //------------------------------------------------------------------------------
  1071. //------------------------------------------------------------------------------
  1072. initialization
  1073. NumberOfProcessors := GetProcessorCount;
  1074. {$IFDEF USEMULTITHREADING}
  1075. if NumberOfProcessors > 1 then
  1076. DefaultRasterizerClass := TMultithreadedRegularRasterizer;
  1077. {$ENDIF}
  1078. end.