GR32_Rasterizers.pas 23 KB

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