GR32_VPR2.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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. {$include GR32.inc}
  35. uses
  36. GR32, 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,
  75. Types,
  76. GR32_VectorUtils,
  77. GR32_Math,
  78. GR32_LowLevel,
  79. GR32_Blend;
  80. // FastFloor is slow on x86 due to call overhead
  81. {$if (not defined(PUREPASCAL)) and defined(CPUx86_64)}
  82. // Use of FastFloor currently corrupts the memory manager of FPC
  83. // so temporarily disabled there.
  84. {$if (not defined(FPC))}
  85. {$define USE_POLYFLOOR}
  86. {$ifend}
  87. {$ifend}
  88. function PolyFloor(Value: Single): integer; overload; inline;
  89. begin
  90. {$if defined(USE_POLYFLOOR)}
  91. Result := FastFloorSingle(Value);
  92. {$else}
  93. Result := Round(Value);
  94. {$ifend}
  95. end;
  96. function PolyFloor(Value: Double): integer; overload; inline;
  97. begin
  98. {$if defined(USE_POLYFLOOR)}
  99. Result := FastFloorDouble(Value);
  100. {$else}
  101. Result := Round(Value);
  102. {$ifend}
  103. end;
  104. { TPolygonRenderer32VPR2 }
  105. procedure UpdateSpan(var Span: TIntSpan; Value: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
  106. begin
  107. if Value < Span.Min then
  108. Span.Min := Value;
  109. if Value > Span.Max then
  110. Span.Max := Value;
  111. end;
  112. procedure TPolygonRenderer32VPR2.AddLineSegment(X1, Y1, X2, Y2: TFloat);
  113. type
  114. PFloatArray = ^TFloatArray;
  115. TFloatArray = array [0..1] of TFloat;
  116. const
  117. SGN: array [0..1] of Integer = (1, -1);
  118. EPSILON: TFloat = 0.0001;
  119. EPSILON_Dx: Double = 1 / 255;
  120. var
  121. P: PFloatArray;
  122. procedure AddSegment(X1, Y1, X2, Y2: TFloat);
  123. var
  124. dX, dY: TFloat;
  125. begin
  126. dX := (X1 + X2) * 0.5;
  127. dX := dX - PolyFloor(dX);
  128. dY := Y2 - Y1;
  129. dX := dX * dY;
  130. P[0] := P[0] + dY - dX;
  131. P[1] := P[1] + dX;
  132. end;
  133. var
  134. dX, dY, dYdX, dXdY: Double;
  135. PrevX, PrevY, NextX, NextY: Double;
  136. Delta, DeltaX, DeltaY: Double;
  137. X, Y, StepX, StepY: Integer;
  138. MaxDelta: Double;
  139. begin
  140. {$ifndef FPC}
  141. // Same as (Y2 = Y1)
  142. if (PCardinal(@Y2)^ = PCardinal(@Y1)^) then
  143. Exit;
  144. {$else} // Above optimization fails on FPC
  145. if (Y2 = Y1) then
  146. Exit;
  147. {$endif}
  148. {$ifndef FPC}
  149. dY := Double(Y2) - Double(Y1);
  150. dX := Double(X2) - Double(X1);
  151. {$else}
  152. dY := Y2 - Y1;
  153. dX := X2 - X1;
  154. {$endif}
  155. X := PolyFloor(X1);
  156. Y := PolyFloor(Y1);
  157. UpdateSpan(FYSpan, Y);
  158. StepX := Ord(dX < 0);
  159. StepY := Ord(dY < 0);
  160. X1 := X1 - StepX;
  161. Y1 := Y1 - StepY;
  162. X2 := X2 - StepX;
  163. Y2 := Y2 - StepY;
  164. StepX := SGN[StepX];
  165. StepY := SGN[StepY];
  166. if (Abs(dX) <= EPSILON_Dx) then
  167. begin
  168. MaxDelta := Abs(dY) - EPSILON;
  169. NextY := Y1;
  170. repeat
  171. UpdateSpan(FXSpan[Y], X);
  172. P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
  173. PrevY := NextY;
  174. Inc(Y, StepY);
  175. NextY := Y;
  176. AddSegment(X1, PrevY, X1, NextY);
  177. until (Abs(Y1 - NextY) >= MaxDelta);
  178. AddSegment(X1, NextY, X1, Y2);
  179. end else
  180. begin
  181. dYdX := dY/dX;
  182. dXdY := dX/dY;
  183. DeltaX := X + StepX - X1;
  184. DeltaY := (Y + StepY - Y1) * dXdY;
  185. MaxDelta := Abs(dX) - EPSILON;
  186. NextX := X1;
  187. NextY := Y1;
  188. repeat
  189. PrevX := NextX;
  190. PrevY := NextY;
  191. UpdateSpan(FXSpan[Y], X);
  192. P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
  193. if (Abs(DeltaX) <= Abs(DeltaY)) then
  194. begin
  195. Inc(X, StepX);
  196. Delta := DeltaX;
  197. DeltaX := DeltaX + StepX;
  198. end else
  199. begin
  200. Inc(Y, StepY);
  201. Delta := DeltaY;
  202. DeltaY := DeltaY + StepY * dXdY;
  203. end;
  204. NextX := X1 + Delta;
  205. NextY := Y1 + Delta * dYdX;
  206. AddSegment(PrevX, PrevY, NextX, NextY);
  207. until (Abs(Delta) >= MaxDelta);
  208. AddSegment(NextX, NextY, X2, Y2);
  209. end;
  210. end;
  211. constructor TPolygonRenderer32VPR2.Create;
  212. begin
  213. inherited Create;
  214. FOpacityMap := TFloatMap.Create;
  215. end;
  216. destructor TPolygonRenderer32VPR2.Destroy;
  217. begin
  218. FOpacityMap.Free;
  219. inherited;
  220. end;
  221. procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
  222. Count: Integer; Color: TColor32);
  223. var
  224. I: Integer;
  225. M, V: Cardinal;
  226. Last: TFloat;
  227. C: TColor32Entry absolute Color;
  228. begin
  229. M := C.A * $101;
  230. Last := Infinity;
  231. for I := 0 to Count - 1 do
  232. begin
  233. if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
  234. begin
  235. Last := Coverage[I];
  236. V := Abs(PolyFloor(Last * $10000)); // TODO : Is Floor the correct operator here?
  237. if V > $10000 then V := $10000;
  238. V := V * M shr 24;
  239. C.A := V;
  240. end;
  241. AlphaValues[I] := Color;
  242. end;
  243. end;
  244. procedure MakeAlphaEvenOddUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
  245. Count: Integer; Color: TColor32);
  246. var
  247. I: Integer;
  248. M, V: Cardinal;
  249. Last: TFloat;
  250. C: TColor32Entry absolute Color;
  251. begin
  252. M := C.A * $101;
  253. Last := Infinity;
  254. for I := 0 to Count - 1 do
  255. begin
  256. if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
  257. begin
  258. Last := Coverage[I];
  259. V := Abs(PolyFloor(Coverage[I] * $10000)); // TODO : Is Floor the correct operator here?
  260. V := V and $01ffff;
  261. if V >= $10000 then V := V xor $1ffff;
  262. V := V * M shr 24;
  263. C.A := V;
  264. end;
  265. AlphaValues[I] := Color;
  266. end;
  267. end;
  268. {$IFDEF UseStackAlloc}{$W+}{$ENDIF}
  269. procedure TPolygonRenderer32VPR2.DrawBitmap;
  270. const
  271. FillProcs: array [TPolyFillMode] of TFillProc = (MakeAlphaEvenOddUP, MakeAlphaNonZeroUP);
  272. var
  273. I, N: Integer;
  274. Dst: PColor32Array;
  275. Src: PFloatArray;
  276. P: PIntSpan;
  277. FillProc: TFillProc;
  278. FG: PColor32Array;
  279. begin
  280. {$IFDEF UseStackAlloc}
  281. FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
  282. {$ELSE}
  283. GetMem(FG, Bitmap.Width * SizeOf(TColor32));
  284. {$ENDIF}
  285. FillProc := FillProcs[FillMode];
  286. FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
  287. Assert(FYSpan.Min >= 0);
  288. Assert(FYSpan.Max < Bitmap.Height);
  289. for I := FYSpan.Min to FYSpan.Max do
  290. begin
  291. P := @FXSpan[I];
  292. P.Max := Min(P.Max + 1, Bitmap.Width - 1);
  293. if P.Max < P.Min then Continue;
  294. N := P.Max - P.Min + 1;
  295. Dst := Bitmap.Scanline[I];
  296. Src := PFloatArray(FOpacityMap.ValPtr[0, I]);
  297. // 1. Cumulative sum
  298. CumSum(@Src[P.Min], N);
  299. // 2. Convert opacity to colors
  300. FillProc(@Src[P.Min], @FG[P.Min], N, Color);
  301. // 3. Blend colors
  302. BlendLine(@FG[P.Min], @Dst[P.Min], N);
  303. // 4. Clear opacity map
  304. FillLongWord(Src[P.Min], N, 0);
  305. end;
  306. {$IFDEF UseStackAlloc}
  307. StackFree(FG);
  308. {$ELSE}
  309. FreeMem(FG);
  310. {$ENDIF}
  311. end;
  312. {$IFDEF UseStackAlloc}{$W-}{$ENDIF}
  313. {$ifdef FPC}
  314. type
  315. TRoundingMode = Math.TFPURoundingMode;
  316. {$endif}
  317. procedure TPolygonRenderer32VPR2.PolyPolygonFS(
  318. const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
  319. var
  320. APoints: TArrayOfFloatPoint;
  321. I, J, H: Integer;
  322. R: TFloatRect;
  323. {$if not defined(USE_POLYFLOOR)}
  324. SavedRoundingMode: TRoundingMode;
  325. {$ifend}
  326. begin
  327. FYSpan := STARTSPAN;
  328. {$if not defined(USE_POLYFLOOR)}
  329. SavedRoundingMode := SetRoundMode(rmDown);
  330. try
  331. {$ifend}
  332. FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
  333. // temporary fix for floating point rounding errors
  334. R := ClipRect;
  335. R.Right := R.Right - 0.0001;
  336. R.Bottom := R.Bottom - 0.0001;
  337. SetLength(FXSpan, Bitmap.Height);
  338. for I := 0 to High(FXSpan) do
  339. FXSpan[I] := STARTSPAN;
  340. for I := 0 to High(Points) do
  341. begin
  342. APoints := ClipPolygon(Points[I], R);
  343. H := High(APoints);
  344. if H <= 0 then Continue;
  345. for J := 0 to H - 1 do
  346. AddLineSegment(APoints[J].X, APoints[J].Y, APoints[J + 1].X, APoints[J + 1].Y);
  347. AddLineSegment(APoints[H].X, APoints[H].Y, APoints[0].X, APoints[0].Y);
  348. end;
  349. DrawBitmap;
  350. {$if not defined(USE_POLYFLOOR)}
  351. finally
  352. SetRoundMode(SavedRoundingMode);
  353. end
  354. {$ifend}
  355. end;
  356. //============================================================================//
  357. procedure TPolygonRenderer32VPR2X.AddLineSegment(X1, Y1, X2, Y2: TFixed);
  358. type
  359. PFixedArray = ^TFixedArray;
  360. TFixedArray = array [0..1] of TFixed;
  361. const
  362. SGN: array [0..1] of Integer = (1, -1);
  363. var
  364. Dx, Dy, DyDx, DxDy, t, tX, tY, Xm, Ym, Xn, Yn: TFixed;
  365. X, Y, StepX, StepY: Integer;
  366. P: PFixedArray;
  367. procedure AddSegment(X1, Y1, X2, Y2: TFixed);
  368. var
  369. Dx, Dy: TFixed;
  370. begin
  371. Dx := (X1 + X2) shr 1;
  372. Dx := Dx and $ffff;
  373. Dy := Y2 - Y1;
  374. Dx := FixedMul(Dx, Dy);
  375. P[0] := P[0] + Dy - Dx;
  376. P[1] := P[1] + Dx;
  377. end;
  378. begin
  379. Dx := X2 - X1;
  380. Dy := Y2 - Y1;
  381. if Dy = 0 then Exit;
  382. X := FixedFloor(X1);
  383. Y := FixedFloor(Y1);
  384. UpdateSpan(FYSpan, Y);
  385. StepX := Ord(Dx < 0);
  386. StepY := Ord(Dy < 0);
  387. X1 := X1 - StepX * FixedOne;
  388. Y1 := Y1 - StepY * FixedOne;
  389. X2 := X2 - StepX * FixedOne;
  390. Y2 := Y2 - StepY * FixedOne;
  391. StepX := SGN[StepX];
  392. StepY := SGN[StepY];
  393. if Dx = 0 then
  394. begin
  395. Yn := Y1;
  396. repeat
  397. UpdateSpan(FXSpan[Y], X);
  398. P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
  399. Ym := Yn;
  400. Inc(Y, StepY);
  401. Yn := Y * FixedOne;
  402. AddSegment(X1, Ym, X1, Yn);
  403. until Abs(Y1 - Yn) >= Abs(Dy);
  404. AddSegment(X1, Yn, X1, Y2);
  405. end
  406. else
  407. begin
  408. DyDx := FixedDiv(Dy, Dx);
  409. DxDy := FixedDiv(Dx, Dy);
  410. tX := (X + StepX) * FixedOne - X1;
  411. tY := FixedMul((Y + StepY) * FixedOne - Y1, DxDy);
  412. Xn := X1;
  413. Yn := Y1;
  414. repeat
  415. Xm := Xn;
  416. Ym := Yn;
  417. UpdateSpan(FXSpan[Y], X);
  418. P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
  419. if Abs(tX) <= Abs(tY) then
  420. begin
  421. Inc(X, StepX);
  422. t := tX;
  423. tX := tX + StepX*FixedOne;
  424. end
  425. else
  426. begin
  427. Inc(Y, StepY);
  428. t := tY;
  429. tY := tY + StepY * DxDy;
  430. end;
  431. Xn := X1 + t;
  432. Yn := Y1 + FixedMul(t, DyDx);
  433. AddSegment(Xm, Ym, Xn, Yn);
  434. until Abs(t) >= Abs(Dx);
  435. AddSegment(Xn, Yn, X2, Y2);
  436. end;
  437. end;
  438. procedure CumSumX(PSrc: PFixedArray; N: Integer);
  439. var
  440. I: Integer;
  441. begin
  442. for I := 1 to N - 1 do
  443. Inc(PSrc[I], PSrc[I - 1]);
  444. end;
  445. procedure MakeAlphaNonZeroUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
  446. Count: Integer; Color: TColor32);
  447. var
  448. I, V, M, Last: Integer;
  449. C: TColor32Entry absolute Color;
  450. begin
  451. M := C.A * $101;
  452. Last := MaxInt;
  453. for I := 0 to Count - 1 do
  454. begin
  455. if Last <> Coverage[I] then
  456. begin
  457. V := Abs(Coverage[I]);
  458. if V > $ffff then V := $ffff;
  459. V := V * M shr 24;
  460. C.A := V;
  461. end;
  462. AlphaValues[I] := Color;
  463. end;
  464. end;
  465. procedure MakeAlphaEvenOddUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
  466. Count: Integer; Color: TColor32);
  467. var
  468. I, V, M, Last: Integer;
  469. C: TColor32Entry absolute Color;
  470. begin
  471. M := C.A * $101;
  472. Last := MaxInt;
  473. for I := 0 to Count - 1 do
  474. begin
  475. if Last <> Coverage[I] then
  476. begin
  477. V := Abs(Coverage[I]);
  478. V := V and $01ffff;
  479. if V >= $10000 then V := V xor $1ffff;
  480. V := V * M shr 24;
  481. C.A := V;
  482. end;
  483. AlphaValues[I] := Color;
  484. end;
  485. end;
  486. {$IFDEF UseStackAlloc}{$W+}{$ENDIF}
  487. procedure TPolygonRenderer32VPR2X.DrawBitmap;
  488. type
  489. TFillProcX = procedure(Coverage: PFixedArray; AlphaValues: PColor32Array; Count: Integer; Color: TColor32);
  490. const
  491. FillProcs: array [TPolyFillMode] of TFillProcX = (MakeAlphaEvenOddUPX, MakeAlphaNonZeroUPX);
  492. var
  493. I, N: Integer;
  494. Dst: PColor32Array;
  495. Src: PFixedArray;
  496. P: PIntSpan;
  497. FillProc: TFillProcX;
  498. FG: PColor32Array;
  499. begin
  500. {$IFDEF UseStackAlloc}
  501. FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
  502. {$ELSE}
  503. GetMem(FG, Bitmap.Width * SizeOf(TColor32));
  504. {$ENDIF}
  505. FillProc := FillProcs[FillMode];
  506. FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
  507. Assert(FYSpan.Min >= 0);
  508. Assert(FYSpan.Max < Bitmap.Height);
  509. for I := FYSpan.Min to FYSpan.Max do
  510. begin
  511. P := @FXSpan[I];
  512. P.Max := Min(P.Max + 1, Bitmap.Width - 1);
  513. if P.Max < P.Min then Continue;
  514. N := P.Max - P.Min + 1;
  515. Dst := Bitmap.Scanline[I];
  516. Src := PFixedArray(FOpacityMap.ValPtr[0, I]);
  517. // 1. Cumulative sum
  518. CumSumX(@Src[P.Min], N);
  519. // 2. Convert opacity to colors
  520. FillProc(@Src[P.Min], @FG[P.Min], N, Color);
  521. // 3. Blend colors
  522. BlendLine(@FG[P.Min], @Dst[P.Min], N);
  523. // 4. Clear opacity map
  524. FillLongWord(Src[P.Min], N, 0);
  525. end;
  526. {$IFDEF UseStackAlloc}
  527. StackFree(FG);
  528. {$ELSE}
  529. FreeMem(FG);
  530. {$ENDIF}
  531. end;
  532. {$IFDEF UseStackAlloc}{$W-}{$ENDIF}
  533. procedure TPolygonRenderer32VPR2X.PolyPolygonFS(
  534. const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
  535. var
  536. APoints: TArrayOfFloatPoint;
  537. I, J, H: Integer;
  538. R: TFloatRect;
  539. begin
  540. FYSpan := STARTSPAN;
  541. FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
  542. // temporary fix for floating point rounding errors
  543. R := ClipRect;
  544. {$ifndef FPC}
  545. R.Inflate(-0.05, -0.05);
  546. {$else}
  547. GR32.InflateRect(R, -0.05, -0.05);
  548. {$endif}
  549. SetLength(FXSpan, Bitmap.Height);
  550. for I := 0 to High(FXSpan) do
  551. FXSpan[I] := STARTSPAN;
  552. for I := 0 to High(Points) do
  553. begin
  554. APoints := ClipPolygon(Points[I], R);
  555. H := High(APoints);
  556. if H <= 0 then Continue;
  557. for J := 0 to H - 1 do
  558. AddLineSegment(Fixed(APoints[J].X), Fixed(APoints[J].Y), Fixed(APoints[J + 1].X), Fixed(APoints[J + 1].Y));
  559. AddLineSegment(Fixed(APoints[H].X), Fixed(APoints[H].Y), Fixed(APoints[0].X), Fixed(APoints[0].Y));
  560. end;
  561. DrawBitmap;
  562. end;
  563. constructor TPolygonRenderer32VPR2X.Create;
  564. begin
  565. inherited Create;
  566. FOpacityMap := TIntegerMap.Create;
  567. end;
  568. destructor TPolygonRenderer32VPR2X.Destroy;
  569. begin
  570. FOpacityMap.Free;
  571. inherited Destroy;
  572. end;
  573. initialization
  574. RegisterPolygonRenderer(TPolygonRenderer32VPR2);
  575. // TPolygonRenderer32VPR2X has been disabled as it's incomplete.
  576. // It causes AVs - and always have.
  577. // RegisterPolygonRenderer(TPolygonRenderer32VPR2X);
  578. end.