GR32_VPR2.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. unit GR32_VPR2;
  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 Vectorial Polygon Rasterizer for Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Mattias Andersson <[email protected]>
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2012
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * Contributor(s):
  31. *
  32. * ***** END LICENSE BLOCK ***** *)
  33. interface
  34. {$I GR32.inc}
  35. uses
  36. GR32, GR32_Gamma, GR32_Polygons, GR32_OrdinalMaps;
  37. type
  38. PIntSpan = ^TIntSpan;
  39. TIntSpan = record
  40. Min, Max: Integer;
  41. end;
  42. const
  43. STARTSPAN: TIntSpan = (Min: MAXINT; Max: 0);
  44. type
  45. TPolygonRenderer32VPR2 = class(TPolygonRenderer32)
  46. private
  47. FOpacityMap: TFloatMap;
  48. FXSpan: array of TIntSpan;
  49. FYSpan: TIntSpan;
  50. procedure AddLineSegment(X1, Y1, X2, Y2: TFloat); overload;
  51. procedure DrawBitmap;
  52. public
  53. constructor Create; override;
  54. destructor Destroy; override;
  55. procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
  56. const ClipRect: TFloatRect); override;
  57. end;
  58. { TPolygonRenderer32VPR2X }
  59. TPolygonRenderer32VPR2X = class(TPolygonRenderer32)
  60. private
  61. FOpacityMap: TIntegerMap;
  62. FXSpan: array of TIntSpan;
  63. FYSpan: TIntSpan;
  64. procedure AddLineSegment(X1, Y1, X2, Y2: TFixed); overload;
  65. procedure DrawBitmap;
  66. public
  67. constructor Create; override;
  68. destructor Destroy; override;
  69. procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
  70. const ClipRect: TFloatRect); override;
  71. end;
  72. implementation
  73. uses
  74. Math, GR32_VectorUtils, GR32_Math, GR32_LowLevel, GR32_Blend;
  75. { TPolygonRenderer32VPR2 }
  76. procedure UpdateSpan(var Span: TIntSpan; Value: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  77. begin
  78. if Value < Span.Min then Span.Min := Value;
  79. if Value > Span.Max then Span.Max := Value;
  80. end;
  81. procedure TPolygonRenderer32VPR2.AddLineSegment(X1, Y1, X2, Y2: TFloat);
  82. type
  83. PFloatArray = ^TFloatArray;
  84. TFloatArray = array [0..1] of TFloat;
  85. const
  86. SGN: array [0..1] of Integer = (1, -1);
  87. EPSILON: TFloat = 0.0001;
  88. var
  89. Dx, Dy, DyDx, DxDy, Xm, Ym, Xn, Yn, t, tX, tY: Double;
  90. X, Y, StepX, StepY: Integer;
  91. P: PFloatArray;
  92. procedure AddSegment(X1, Y1, X2, Y2: TFloat);
  93. var
  94. Dx, Dy: TFloat;
  95. begin
  96. Dx := (X1 + X2) * 0.5;
  97. Dx := Dx - Round(Dx);
  98. Dy := Y2 - Y1;
  99. Dx := Dx * Dy;
  100. P[0] := P[0] + Dy - Dx;
  101. P[1] := P[1] + Dx;
  102. end;
  103. begin
  104. Dx := X2 - X1;
  105. Dy := Y2 - Y1;
  106. if Dy = 0 then Exit;
  107. X := Round(X1);
  108. Y := Round(Y1);
  109. UpdateSpan(FYSpan, Y);
  110. StepX := Ord(Dx < 0);
  111. StepY := Ord(Dy < 0);
  112. X1 := X1 - StepX;
  113. Y1 := Y1 - StepY;
  114. X2 := X2 - StepX;
  115. Y2 := Y2 - StepY;
  116. StepX := SGN[StepX];
  117. StepY := SGN[StepY];
  118. if Dx = 0 then
  119. begin
  120. Yn := Y1;
  121. repeat
  122. UpdateSpan(FXSpan[Y], X);
  123. P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
  124. Ym := Yn;
  125. Inc(Y, StepY);
  126. Yn := Y;
  127. AddSegment(X1, Ym, X1, Yn);
  128. until Abs(Y1 - Yn) + EPSILON >= Abs(Dy);
  129. AddSegment(X1, Yn, X1, Y2);
  130. end
  131. else
  132. begin
  133. DyDx := Dy/Dx;
  134. DxDy := Dx/Dy;
  135. tX := X + StepX - X1;
  136. tY := (Y + StepY - Y1) * DxDy;
  137. Xn := X1;
  138. Yn := Y1;
  139. repeat
  140. Xm := Xn;
  141. Ym := Yn;
  142. UpdateSpan(FXSpan[Y], X);
  143. P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
  144. if Abs(tX) <= Abs(tY) then
  145. begin
  146. Inc(X, StepX);
  147. t := tX;
  148. tX := tX + StepX;
  149. end
  150. else
  151. begin
  152. Inc(Y, StepY);
  153. t := tY;
  154. tY := tY + StepY * DxDy;
  155. end;
  156. Xn := X1 + t;
  157. Yn := Y1 + t * DyDx;
  158. AddSegment(Xm, Ym, Xn, Yn);
  159. until Abs(t) + EPSILON >= Abs(Dx);
  160. AddSegment(Xn, Yn, X2, Y2);
  161. end;
  162. end;
  163. constructor TPolygonRenderer32VPR2.Create;
  164. begin
  165. inherited Create;
  166. FOpacityMap := TFloatMap.Create;
  167. end;
  168. destructor TPolygonRenderer32VPR2.Destroy;
  169. begin
  170. FOpacityMap.Free;
  171. inherited;
  172. end;
  173. procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
  174. Count: Integer; Color: TColor32);
  175. var
  176. I: Integer;
  177. M, V: Cardinal;
  178. Last: TFloat;
  179. C: TColor32Entry absolute Color;
  180. begin
  181. M := C.A * $101;
  182. Last := Infinity;
  183. for I := 0 to Count - 1 do
  184. begin
  185. if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
  186. begin
  187. Last := Coverage[I];
  188. V := Abs(Round(Last * $10000));
  189. if V > $10000 then V := $10000;
  190. V := V * M shr 24;
  191. {$IFDEF USEGR32GAMMA}
  192. V := GAMMA_ENCODING_TABLE[V];
  193. {$ENDIF}
  194. C.A := V;
  195. end;
  196. AlphaValues[I] := Color;
  197. end;
  198. end;
  199. procedure MakeAlphaEvenOddUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
  200. Count: Integer; Color: TColor32);
  201. var
  202. I: Integer;
  203. M, V: Cardinal;
  204. Last: TFloat;
  205. C: TColor32Entry absolute Color;
  206. begin
  207. M := C.A * $101;
  208. Last := Infinity;
  209. for I := 0 to Count - 1 do
  210. begin
  211. if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
  212. begin
  213. Last := Coverage[I];
  214. V := Abs(Round(Coverage[I] * $10000));
  215. V := V and $01ffff;
  216. if V >= $10000 then V := V xor $1ffff;
  217. V := V * M shr 24;
  218. {$IFDEF USEGR32GAMMA}
  219. V := GAMMA_ENCODING_TABLE[V];
  220. {$ENDIF}
  221. C.A := V;
  222. end;
  223. AlphaValues[I] := Color;
  224. end;
  225. end;
  226. {$IFDEF UseStackAlloc}{$W+}{$ENDIF}
  227. procedure TPolygonRenderer32VPR2.DrawBitmap;
  228. const
  229. FillProcs: array [TPolyFillMode] of TFillProc = (MakeAlphaEvenOddUP, MakeAlphaNonZeroUP);
  230. var
  231. I, N: Integer;
  232. Dst: PColor32Array;
  233. Src: PFloatArray;
  234. P: PIntSpan;
  235. FillProc: TFillProc;
  236. FG: PColor32Array;
  237. begin
  238. {$IFDEF UseStackAlloc}
  239. FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
  240. {$ELSE}
  241. GetMem(FG, Bitmap.Width * SizeOf(TColor32));
  242. {$ENDIF}
  243. FillProc := FillProcs[FillMode];
  244. FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
  245. Assert(FYSpan.Min >= 0);
  246. Assert(FYSpan.Max < Bitmap.Height);
  247. for I := FYSpan.Min to FYSpan.Max do
  248. begin
  249. P := @FXSpan[I];
  250. P.Max := Min(P.Max + 1, Bitmap.Width - 1);
  251. if P.Max < P.Min then Continue;
  252. N := P.Max - P.Min + 1;
  253. Dst := Bitmap.Scanline[I];
  254. Src := PFloatArray(FOpacityMap.ValPtr[0, I]);
  255. // 1. Cumulative sum
  256. CumSum(@Src[P.Min], N);
  257. // 2. Convert opacity to colors
  258. FillProc(@Src[P.Min], @FG[P.Min], N, Color);
  259. // 3. Blend colors
  260. BlendLine(@FG[P.Min], @Dst[P.Min], N);
  261. EMMS;
  262. // 4. Clear opacity map
  263. FillLongWord(Src[P.Min], N, 0);
  264. end;
  265. {$IFDEF UseStackAlloc}
  266. StackFree(FG);
  267. {$ELSE}
  268. FreeMem(FG);
  269. {$ENDIF}
  270. end;
  271. {$IFDEF UseStackAlloc}{$W-}{$ENDIF}
  272. {$ifndef COMPILERXE2_UP}
  273. type
  274. TRoundingMode = Math.TFPURoundingMode;
  275. {$endif COMPILERXE2_UP}
  276. procedure TPolygonRenderer32VPR2.PolyPolygonFS(
  277. const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
  278. var
  279. APoints: TArrayOfFloatPoint;
  280. I, J, H: Integer;
  281. SavedRoundMode: TRoundingMode;
  282. R: TFloatRect;
  283. begin
  284. FYSpan := STARTSPAN;
  285. SavedRoundMode := SetRoundMode(rmDown);
  286. try
  287. FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
  288. // temporary fix for floating point rounding errors
  289. R := ClipRect;
  290. R.Right := R.Right - 0.0001;
  291. R.Bottom := R.Bottom - 0.0001;
  292. SetLength(FXSpan, Bitmap.Height);
  293. for I := 0 to High(FXSpan) do
  294. FXSpan[I] := STARTSPAN;
  295. for I := 0 to High(Points) do
  296. begin
  297. APoints := ClipPolygon(Points[I], R);
  298. H := High(APoints);
  299. if H <= 0 then Continue;
  300. for J := 0 to H - 1 do
  301. AddLineSegment(APoints[J].X, APoints[J].Y, APoints[J + 1].X, APoints[J + 1].Y);
  302. AddLineSegment(APoints[H].X, APoints[H].Y, APoints[0].X, APoints[0].Y);
  303. end;
  304. DrawBitmap;
  305. finally
  306. SetRoundMode(SavedRoundMode);
  307. end;
  308. end;
  309. //============================================================================//
  310. procedure TPolygonRenderer32VPR2X.AddLineSegment(X1, Y1, X2, Y2: TFixed);
  311. type
  312. PFixedArray = ^TFixedArray;
  313. TFixedArray = array [0..1] of TFixed;
  314. const
  315. SGN: array [0..1] of Integer = (1, -1);
  316. var
  317. Dx, Dy, DyDx, DxDy, t, tX, tY, Xm, Ym, Xn, Yn: TFixed;
  318. X, Y, StepX, StepY: Integer;
  319. P: PFixedArray;
  320. procedure AddSegment(X1, Y1, X2, Y2: TFixed);
  321. var
  322. Dx, Dy: TFixed;
  323. begin
  324. Dx := (X1 + X2) shr 1;
  325. Dx := Dx and $ffff;
  326. Dy := Y2 - Y1;
  327. Dx := FixedMul(Dx, Dy);
  328. P[0] := P[0] + Dy - Dx;
  329. P[1] := P[1] + Dx;
  330. end;
  331. begin
  332. Dx := X2 - X1;
  333. Dy := Y2 - Y1;
  334. if Dy = 0 then Exit;
  335. X := FixedFloor(X1);
  336. Y := FixedFloor(Y1);
  337. UpdateSpan(FYSpan, Y);
  338. StepX := Ord(Dx < 0);
  339. StepY := Ord(Dy < 0);
  340. X1 := X1 - StepX * FixedOne;
  341. Y1 := Y1 - StepY * FixedOne;
  342. X2 := X2 - StepX * FixedOne;
  343. Y2 := Y2 - StepY * FixedOne;
  344. StepX := SGN[StepX];
  345. StepY := SGN[StepY];
  346. if Dx = 0 then
  347. begin
  348. Yn := Y1;
  349. repeat
  350. UpdateSpan(FXSpan[Y], X);
  351. P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
  352. Ym := Yn;
  353. Inc(Y, StepY);
  354. Yn := Y * FixedOne;
  355. AddSegment(X1, Ym, X1, Yn);
  356. until Abs(Y1 - Yn) >= Abs(Dy);
  357. AddSegment(X1, Yn, X1, Y2);
  358. end
  359. else
  360. begin
  361. DyDx := FixedDiv(Dy, Dx);
  362. DxDy := FixedDiv(Dx, Dy);
  363. tX := (X + StepX) * FixedOne - X1;
  364. tY := FixedMul((Y + StepY) * FixedOne - Y1, DxDy);
  365. Xn := X1;
  366. Yn := Y1;
  367. repeat
  368. Xm := Xn;
  369. Ym := Yn;
  370. UpdateSpan(FXSpan[Y], X);
  371. P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
  372. if Abs(tX) <= Abs(tY) then
  373. begin
  374. Inc(X, StepX);
  375. t := tX;
  376. tX := tX + StepX*FixedOne;
  377. end
  378. else
  379. begin
  380. Inc(Y, StepY);
  381. t := tY;
  382. tY := tY + StepY * DxDy;
  383. end;
  384. Xn := X1 + t;
  385. Yn := Y1 + FixedMul(t, DyDx);
  386. AddSegment(Xm, Ym, Xn, Yn);
  387. until Abs(t) >= Abs(Dx);
  388. AddSegment(Xn, Yn, X2, Y2);
  389. end;
  390. end;
  391. procedure CumSumX(PSrc: PFixedArray; N: Integer);
  392. var
  393. I: Integer;
  394. begin
  395. for I := 1 to N - 1 do
  396. Inc(PSrc[I], PSrc[I - 1]);
  397. end;
  398. procedure MakeAlphaNonZeroUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
  399. Count: Integer; Color: TColor32);
  400. var
  401. I, V, M, Last: Integer;
  402. C: TColor32Entry absolute Color;
  403. begin
  404. M := C.A * $101;
  405. Last := MaxInt;
  406. for I := 0 to Count - 1 do
  407. begin
  408. if Last <> Coverage[I] then
  409. begin
  410. V := Abs(Coverage[I]);
  411. if V > $ffff then V := $ffff;
  412. V := V * M shr 24;
  413. {$IFDEF USEGR32GAMMA}
  414. V := GAMMA_ENCODING_TABLE[V];
  415. {$ENDIF}
  416. C.A := V;
  417. end;
  418. AlphaValues[I] := Color;
  419. end;
  420. end;
  421. procedure MakeAlphaEvenOddUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
  422. Count: Integer; Color: TColor32);
  423. var
  424. I, V, M, Last: Integer;
  425. C: TColor32Entry absolute Color;
  426. begin
  427. M := C.A * $101;
  428. Last := MaxInt;
  429. for I := 0 to Count - 1 do
  430. begin
  431. if Last <> Coverage[I] then
  432. begin
  433. V := Abs(Coverage[I]);
  434. V := V and $01ffff;
  435. if V >= $10000 then V := V xor $1ffff;
  436. V := V * M shr 24;
  437. {$IFDEF USEGR32GAMMA}
  438. V := GAMMA_ENCODING_TABLE[V];
  439. {$ENDIF}
  440. C.A := V;
  441. end;
  442. AlphaValues[I] := Color;
  443. end;
  444. end;
  445. {$IFDEF UseStackAlloc}{$W+}{$ENDIF}
  446. procedure TPolygonRenderer32VPR2X.DrawBitmap;
  447. type
  448. TFillProcX = procedure(Coverage: PFixedArray; AlphaValues: PColor32Array; Count: Integer; Color: TColor32);
  449. const
  450. FillProcs: array [TPolyFillMode] of TFillProcX = (MakeAlphaEvenOddUPX, MakeAlphaNonZeroUPX);
  451. var
  452. I, N: Integer;
  453. Dst: PColor32Array;
  454. Src: PFixedArray;
  455. P: PIntSpan;
  456. FillProc: TFillProcX;
  457. FG: PColor32Array;
  458. begin
  459. {$IFDEF UseStackAlloc}
  460. FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
  461. {$ELSE}
  462. GetMem(FG, Bitmap.Width * SizeOf(TColor32));
  463. {$ENDIF}
  464. FillProc := FillProcs[FillMode];
  465. FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
  466. Assert(FYSpan.Min >= 0);
  467. Assert(FYSpan.Max < Bitmap.Height);
  468. for I := FYSpan.Min to FYSpan.Max do
  469. begin
  470. P := @FXSpan[I];
  471. P.Max := Min(P.Max + 1, Bitmap.Width - 1);
  472. if P.Max < P.Min then Continue;
  473. N := P.Max - P.Min + 1;
  474. Dst := Bitmap.Scanline[I];
  475. Src := PFixedArray(FOpacityMap.ValPtr[0, I]);
  476. // 1. Cumulative sum
  477. CumSumX(@Src[P.Min], N);
  478. // 2. Convert opacity to colors
  479. FillProc(@Src[P.Min], @FG[P.Min], N, Color);
  480. // 3. Blend colors
  481. BlendLine(@FG[P.Min], @Dst[P.Min], N);
  482. EMMS;
  483. // 4. Clear opacity map
  484. FillLongWord(Src[P.Min], N, 0);
  485. end;
  486. {$IFDEF UseStackAlloc}
  487. StackFree(FG);
  488. {$ELSE}
  489. FreeMem(FG);
  490. {$ENDIF}
  491. end;
  492. {$IFDEF UseStackAlloc}{$W-}{$ENDIF}
  493. procedure TPolygonRenderer32VPR2X.PolyPolygonFS(
  494. const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
  495. var
  496. APoints: TArrayOfFloatPoint;
  497. I, J, H: Integer;
  498. R: TFloatRect;
  499. begin
  500. FYSpan := STARTSPAN;
  501. FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
  502. // temporary fix for floating point rounding errors
  503. R := ClipRect;
  504. InflateRect(R, -0.05, -0.05);
  505. SetLength(FXSpan, Bitmap.Height);
  506. for I := 0 to High(FXSpan) do
  507. FXSpan[I] := STARTSPAN;
  508. for I := 0 to High(Points) do
  509. begin
  510. APoints := ClipPolygon(Points[I], R);
  511. H := High(APoints);
  512. if H <= 0 then Continue;
  513. for J := 0 to H - 1 do
  514. AddLineSegment(Fixed(APoints[J].X), Fixed(APoints[J].Y), Fixed(APoints[J + 1].X), Fixed(APoints[J + 1].Y));
  515. AddLineSegment(Fixed(APoints[H].X), Fixed(APoints[H].Y), Fixed(APoints[0].X), Fixed(APoints[0].Y));
  516. end;
  517. DrawBitmap;
  518. end;
  519. constructor TPolygonRenderer32VPR2X.Create;
  520. begin
  521. inherited Create;
  522. FOpacityMap := TIntegerMap.Create;
  523. end;
  524. destructor TPolygonRenderer32VPR2X.Destroy;
  525. begin
  526. FOpacityMap.Free;
  527. inherited Destroy;
  528. end;
  529. initialization
  530. RegisterPolygonRenderer(TPolygonRenderer32VPR2);
  531. RegisterPolygonRenderer(TPolygonRenderer32VPR2X);
  532. end.