source: trunk/Packages/Graphics32/GR32_VPR2.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 14.6 KB
Line 
1unit GR32_VPR2;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Vectorial Polygon Rasterizer for Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Mattias Andersson <mattias@centaurix.com>
27 *
28 * Portions created by the Initial Developer are Copyright (C) 2012
29 * the Initial Developer. All Rights Reserved.
30 *
31 * Contributor(s):
32 *
33 * ***** END LICENSE BLOCK ***** *)
34
35interface
36
37{$I GR32.inc}
38
39uses
40 GR32, GR32_Gamma, GR32_Polygons, GR32_OrdinalMaps;
41
42type
43 PIntSpan = ^TIntSpan;
44 TIntSpan = record
45 Min, Max: Integer;
46 end;
47
48const
49 STARTSPAN: TIntSpan = (Min: MAXINT; Max: 0);
50
51type
52 TPolygonRenderer32VPR2 = class(TPolygonRenderer32)
53 private
54 FOpacityMap: TFloatMap;
55 FXSpan: array of TIntSpan;
56 FYSpan: TIntSpan;
57 procedure AddLineSegment(X1, Y1, X2, Y2: TFloat); overload;
58 procedure DrawBitmap;
59 public
60 constructor Create; override;
61 destructor Destroy; override;
62 procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
63 const ClipRect: TFloatRect); override;
64 end;
65
66 { TPolygonRenderer32VPR2X }
67
68 TPolygonRenderer32VPR2X = class(TPolygonRenderer32)
69 private
70 FOpacityMap: TIntegerMap;
71 FXSpan: array of TIntSpan;
72 FYSpan: TIntSpan;
73 procedure AddLineSegment(X1, Y1, X2, Y2: TFixed); overload;
74 procedure DrawBitmap;
75 public
76 constructor Create; override;
77 destructor Destroy; override;
78 procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
79 const ClipRect: TFloatRect); override;
80 end;
81
82implementation
83
84uses
85 Math, GR32_VectorUtils, GR32_Math, GR32_LowLevel, GR32_Blend;
86
87{ TPolygonRenderer32VPR2 }
88
89procedure UpdateSpan(var Span: TIntSpan; Value: Integer); {$IFDEF USEINLINING} inline; {$ENDIF}
90begin
91 if Value < Span.Min then Span.Min := Value;
92 if Value > Span.Max then Span.Max := Value;
93end;
94
95procedure TPolygonRenderer32VPR2.AddLineSegment(X1, Y1, X2, Y2: TFloat);
96type
97 PFloatArray = ^TFloatArray;
98 TFloatArray = array [0..1] of TFloat;
99const
100 SGN: array [0..1] of Integer = (1, -1);
101 EPSILON: TFloat = 0.0001;
102var
103 Dx, Dy, DyDx, DxDy, Xm, Ym, Xn, Yn, t, tX, tY: Double;
104 X, Y, StepX, StepY: Integer;
105 P: PFloatArray;
106
107 procedure AddSegment(X1, Y1, X2, Y2: TFloat);
108 var
109 Dx, Dy: TFloat;
110 begin
111 Dx := (X1 + X2) * 0.5;
112 Dx := Dx - Round(Dx);
113 Dy := Y2 - Y1;
114 Dx := Dx * Dy;
115 P[0] := P[0] + Dy - Dx;
116 P[1] := P[1] + Dx;
117 end;
118
119begin
120 Dx := X2 - X1;
121 Dy := Y2 - Y1;
122
123 if Dy = 0 then Exit;
124
125 X := Round(X1);
126 Y := Round(Y1);
127
128 UpdateSpan(FYSpan, Y);
129
130 StepX := Ord(Dx < 0);
131 StepY := Ord(Dy < 0);
132
133 X1 := X1 - StepX;
134 Y1 := Y1 - StepY;
135 X2 := X2 - StepX;
136 Y2 := Y2 - StepY;
137
138 StepX := SGN[StepX];
139 StepY := SGN[StepY];
140
141 if Dx = 0 then
142 begin
143 Yn := Y1;
144 repeat
145 UpdateSpan(FXSpan[Y], X);
146 P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
147 Ym := Yn;
148 Inc(Y, StepY);
149 Yn := Y;
150 AddSegment(X1, Ym, X1, Yn);
151 until Abs(Y1 - Yn) + EPSILON >= Abs(Dy);
152 AddSegment(X1, Yn, X1, Y2);
153 end
154 else
155 begin
156 DyDx := Dy/Dx;
157 DxDy := Dx/Dy;
158
159 tX := X + StepX - X1;
160 tY := (Y + StepY - Y1) * DxDy;
161
162 Xn := X1;
163 Yn := Y1;
164
165 repeat
166 Xm := Xn;
167 Ym := Yn;
168
169 UpdateSpan(FXSpan[Y], X);
170 P := PFloatArray(FOpacityMap.ValPtr[X, Y]);
171 if Abs(tX) <= Abs(tY) then
172 begin
173 Inc(X, StepX);
174 t := tX;
175 tX := tX + StepX;
176 end
177 else
178 begin
179 Inc(Y, StepY);
180 t := tY;
181 tY := tY + StepY * DxDy;
182 end;
183 Xn := X1 + t;
184 Yn := Y1 + t * DyDx;
185 AddSegment(Xm, Ym, Xn, Yn);
186 until Abs(t) + EPSILON >= Abs(Dx);
187 AddSegment(Xn, Yn, X2, Y2);
188 end;
189end;
190
191
192constructor TPolygonRenderer32VPR2.Create;
193begin
194 inherited Create;
195 FOpacityMap := TFloatMap.Create;
196end;
197
198destructor TPolygonRenderer32VPR2.Destroy;
199begin
200 FOpacityMap.Free;
201 inherited;
202end;
203
204
205procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
206 Count: Integer; Color: TColor32);
207var
208 I: Integer;
209 M, V: Cardinal;
210 Last: TFloat;
211 C: TColor32Entry absolute Color;
212begin
213 M := C.A * $101;
214 Last := Infinity;
215 for I := 0 to Count - 1 do
216 begin
217 if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
218 begin
219 Last := Coverage[I];
220 V := Abs(Round(Last * $10000));
221 if V > $10000 then V := $10000;
222 V := V * M shr 24;
223{$IFDEF USEGR32GAMMA}
224 V := GAMMA_ENCODING_TABLE[V];
225{$ENDIF}
226 C.A := V;
227 end;
228 AlphaValues[I] := Color;
229 end;
230end;
231
232procedure MakeAlphaEvenOddUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
233 Count: Integer; Color: TColor32);
234var
235 I: Integer;
236 M, V: Cardinal;
237 Last: TFloat;
238 C: TColor32Entry absolute Color;
239begin
240 M := C.A * $101;
241 Last := Infinity;
242 for I := 0 to Count - 1 do
243 begin
244 if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
245 begin
246 Last := Coverage[I];
247 V := Abs(Round(Coverage[I] * $10000));
248 V := V and $01ffff;
249 if V >= $10000 then V := V xor $1ffff;
250 V := V * M shr 24;
251{$IFDEF USEGR32GAMMA}
252 V := GAMMA_ENCODING_TABLE[V];
253{$ENDIF}
254 C.A := V;
255 end;
256 AlphaValues[I] := Color;
257 end;
258end;
259
260{$IFDEF UseStackAlloc}{$W+}{$ENDIF}
261procedure TPolygonRenderer32VPR2.DrawBitmap;
262const
263 FillProcs: array [TPolyFillMode] of TFillProc = (MakeAlphaEvenOddUP, MakeAlphaNonZeroUP);
264var
265 I, N: Integer;
266 Dst: PColor32Array;
267 Src: PFloatArray;
268 P: PIntSpan;
269 FillProc: TFillProc;
270 FG: PColor32Array;
271begin
272 {$IFDEF UseStackAlloc}
273 FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
274 {$ELSE}
275 GetMem(FG, Bitmap.Width * SizeOf(TColor32));
276 {$ENDIF}
277
278 FillProc := FillProcs[FillMode];
279 FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
280 Assert(FYSpan.Min >= 0);
281 Assert(FYSpan.Max < Bitmap.Height);
282 for I := FYSpan.Min to FYSpan.Max do
283 begin
284 P := @FXSpan[I];
285 P.Max := Min(P.Max + 1, Bitmap.Width - 1);
286 if P.Max < P.Min then Continue;
287
288 N := P.Max - P.Min + 1;
289 Dst := Bitmap.Scanline[I];
290 Src := PFloatArray(FOpacityMap.ValPtr[0, I]);
291
292 // 1. Cumulative sum
293 CumSum(@Src[P.Min], N);
294
295 // 2. Convert opacity to colors
296 FillProc(@Src[P.Min], @FG[P.Min], N, Color);
297
298 // 3. Blend colors
299 BlendLine(@FG[P.Min], @Dst[P.Min], N);
300
301 // 4. Clear opacity map
302 FillLongWord(Src[P.Min], N, 0);
303 end;
304
305 {$IFDEF UseStackAlloc}
306 StackFree(FG);
307 {$ELSE}
308 FreeMem(FG);
309 {$ENDIF}
310end;
311{$IFDEF UseStackAlloc}{$W-}{$ENDIF}
312
313{$ifndef COMPILERXE2_UP}
314type
315 TRoundingMode = Math.TFPURoundingMode;
316{$endif COMPILERXE2_UP}
317
318procedure TPolygonRenderer32VPR2.PolyPolygonFS(
319 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
320var
321 APoints: TArrayOfFloatPoint;
322 I, J, H: Integer;
323 SavedRoundMode: TRoundingMode;
324 R: TFloatRect;
325begin
326 FYSpan := STARTSPAN;
327 SavedRoundMode := SetRoundMode(rmDown);
328 try
329 FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
330
331 // temporary fix for floating point rounding errors
332 R := ClipRect;
333 R.Right := R.Right - 0.0001;
334 R.Bottom := R.Bottom - 0.0001;
335
336 SetLength(FXSpan, Bitmap.Height);
337 for I := 0 to High(FXSpan) do
338 FXSpan[I] := STARTSPAN;
339
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
346 for J := 0 to H - 1 do
347 AddLineSegment(APoints[J].X, APoints[J].Y, APoints[J + 1].X, APoints[J + 1].Y);
348 AddLineSegment(APoints[H].X, APoints[H].Y, APoints[0].X, APoints[0].Y);
349 end;
350
351 DrawBitmap;
352 finally
353 SetRoundMode(SavedRoundMode);
354 end;
355end;
356
357//============================================================================//
358procedure TPolygonRenderer32VPR2X.AddLineSegment(X1, Y1, X2, Y2: TFixed);
359type
360 PFixedArray = ^TFixedArray;
361 TFixedArray = array [0..1] of TFixed;
362const
363 SGN: array [0..1] of Integer = (1, -1);
364var
365 Dx, Dy, DyDx, DxDy, t, tX, tY, Xm, Ym, Xn, Yn: TFixed;
366 X, Y, StepX, StepY: Integer;
367 P: PFixedArray;
368
369 procedure AddSegment(X1, Y1, X2, Y2: TFixed);
370 var
371 Dx, Dy: TFixed;
372 begin
373 Dx := (X1 + X2) shr 1;
374 Dx := Dx and $ffff;
375 Dy := Y2 - Y1;
376 Dx := FixedMul(Dx, Dy);
377 P[0] := P[0] + Dy - Dx;
378 P[1] := P[1] + Dx;
379 end;
380
381begin
382 Dx := X2 - X1;
383 Dy := Y2 - Y1;
384
385 if Dy = 0 then Exit;
386
387 X := FixedFloor(X1);
388 Y := FixedFloor(Y1);
389
390 UpdateSpan(FYSpan, Y);
391
392 StepX := Ord(Dx < 0);
393 StepY := Ord(Dy < 0);
394
395 X1 := X1 - StepX * FixedOne;
396 Y1 := Y1 - StepY * FixedOne;
397 X2 := X2 - StepX * FixedOne;
398 Y2 := Y2 - StepY * FixedOne;
399
400 StepX := SGN[StepX];
401 StepY := SGN[StepY];
402
403 if Dx = 0 then
404 begin
405 Yn := Y1;
406 repeat
407 UpdateSpan(FXSpan[Y], X);
408 P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
409 Ym := Yn;
410 Inc(Y, StepY);
411 Yn := Y * FixedOne;
412 AddSegment(X1, Ym, X1, Yn);
413 until Abs(Y1 - Yn) >= Abs(Dy);
414 AddSegment(X1, Yn, X1, Y2);
415 end
416 else
417 begin
418 DyDx := FixedDiv(Dy, Dx);
419 DxDy := FixedDiv(Dx, Dy);
420
421 tX := (X + StepX) * FixedOne - X1;
422 tY := FixedMul((Y + StepY) * FixedOne - Y1, DxDy);
423
424 Xn := X1;
425 Yn := Y1;
426
427 repeat
428 Xm := Xn;
429 Ym := Yn;
430
431 UpdateSpan(FXSpan[Y], X);
432 P := PFixedArray(FOpacityMap.ValPtr[X, Y]);
433 if Abs(tX) <= Abs(tY) then
434 begin
435 Inc(X, StepX);
436 t := tX;
437 tX := tX + StepX*FixedOne;
438 end
439 else
440 begin
441 Inc(Y, StepY);
442 t := tY;
443 tY := tY + StepY * DxDy;
444 end;
445 Xn := X1 + t;
446 Yn := Y1 + FixedMul(t, DyDx);
447 AddSegment(Xm, Ym, Xn, Yn);
448 until Abs(t) >= Abs(Dx);
449 AddSegment(Xn, Yn, X2, Y2);
450 end;
451end;
452
453procedure CumSumX(PSrc: PFixedArray; N: Integer);
454var
455 I: Integer;
456begin
457 for I := 1 to N - 1 do
458 Inc(PSrc[I], PSrc[I - 1]);
459end;
460
461procedure MakeAlphaNonZeroUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
462 Count: Integer; Color: TColor32);
463var
464 I, V, M, Last: Integer;
465 C: TColor32Entry absolute Color;
466begin
467 M := C.A * $101;
468 Last := MaxInt;
469 for I := 0 to Count - 1 do
470 begin
471 if Last <> Coverage[I] then
472 begin
473 V := Abs(Coverage[I]);
474 if V > $ffff then V := $ffff;
475 V := V * M shr 24;
476{$IFDEF USEGR32GAMMA}
477 V := GAMMA_ENCODING_TABLE[V];
478{$ENDIF}
479 C.A := V;
480 end;
481 AlphaValues[I] := Color;
482 end;
483end;
484
485procedure MakeAlphaEvenOddUPX(Coverage: PFixedArray; AlphaValues: PColor32Array;
486 Count: Integer; Color: TColor32);
487var
488 I, V, M, Last: Integer;
489 C: TColor32Entry absolute Color;
490begin
491 M := C.A * $101;
492 Last := MaxInt;
493 for I := 0 to Count - 1 do
494 begin
495 if Last <> Coverage[I] then
496 begin
497 V := Abs(Coverage[I]);
498 V := V and $01ffff;
499 if V >= $10000 then V := V xor $1ffff;
500 V := V * M shr 24;
501{$IFDEF USEGR32GAMMA}
502 V := GAMMA_ENCODING_TABLE[V];
503{$ENDIF}
504 C.A := V;
505 end;
506 AlphaValues[I] := Color;
507 end;
508end;
509
510{$IFDEF UseStackAlloc}{$W+}{$ENDIF}
511procedure TPolygonRenderer32VPR2X.DrawBitmap;
512type
513 TFillProcX = procedure(Coverage: PFixedArray; AlphaValues: PColor32Array; Count: Integer; Color: TColor32);
514const
515 FillProcs: array [TPolyFillMode] of TFillProcX = (MakeAlphaEvenOddUPX, MakeAlphaNonZeroUPX);
516var
517 I, N: Integer;
518 Dst: PColor32Array;
519 Src: PFixedArray;
520 P: PIntSpan;
521 FillProc: TFillProcX;
522 FG: PColor32Array;
523begin
524 {$IFDEF UseStackAlloc}
525 FG := StackAlloc(Bitmap.Width * SizeOf(TColor32));
526 {$ELSE}
527 GetMem(FG, Bitmap.Width * SizeOf(TColor32));
528 {$ENDIF}
529
530 FillProc := FillProcs[FillMode];
531 FYSpan.Max := Min(FYSpan.Max, Bitmap.Height - 1);
532 Assert(FYSpan.Min >= 0);
533 Assert(FYSpan.Max < Bitmap.Height);
534 for I := FYSpan.Min to FYSpan.Max do
535 begin
536 P := @FXSpan[I];
537 P.Max := Min(P.Max + 1, Bitmap.Width - 1);
538 if P.Max < P.Min then Continue;
539
540 N := P.Max - P.Min + 1;
541 Dst := Bitmap.Scanline[I];
542 Src := PFixedArray(FOpacityMap.ValPtr[0, I]);
543
544 // 1. Cumulative sum
545 CumSumX(@Src[P.Min], N);
546
547 // 2. Convert opacity to colors
548 FillProc(@Src[P.Min], @FG[P.Min], N, Color);
549
550 // 3. Blend colors
551 BlendLine(@FG[P.Min], @Dst[P.Min], N);
552
553 // 4. Clear opacity map
554 FillLongWord(Src[P.Min], N, 0);
555 end;
556
557 {$IFDEF UseStackAlloc}
558 StackFree(FG);
559 {$ELSE}
560 FreeMem(FG);
561 {$ENDIF}
562end;
563{$IFDEF UseStackAlloc}{$W-}{$ENDIF}
564
565procedure TPolygonRenderer32VPR2X.PolyPolygonFS(
566 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
567var
568 APoints: TArrayOfFloatPoint;
569 I, J, H: Integer;
570 SavedRoundMode: TRoundingMode;
571 R: TFloatRect;
572begin
573 FYSpan := STARTSPAN;
574
575 FOpacityMap.SetSize(Bitmap.Width + 1, Bitmap.Height);
576
577 // temporary fix for floating point rounding errors
578 R := ClipRect;
579 InflateRect(R, -0.05, -0.05);
580
581 SetLength(FXSpan, Bitmap.Height);
582 for I := 0 to High(FXSpan) do
583 FXSpan[I] := STARTSPAN;
584
585 for I := 0 to High(Points) do
586 begin
587 APoints := ClipPolygon(Points[I], R);
588 H := High(APoints);
589 if H <= 0 then Continue;
590
591 for J := 0 to H - 1 do
592 AddLineSegment(Fixed(APoints[J].X), Fixed(APoints[J].Y), Fixed(APoints[J + 1].X), Fixed(APoints[J + 1].Y));
593 AddLineSegment(Fixed(APoints[H].X), Fixed(APoints[H].Y), Fixed(APoints[0].X), Fixed(APoints[0].Y));
594 end;
595
596 DrawBitmap;
597end;
598
599constructor TPolygonRenderer32VPR2X.Create;
600begin
601 inherited Create;
602 FOpacityMap := TIntegerMap.Create;
603end;
604
605destructor TPolygonRenderer32VPR2X.Destroy;
606begin
607 FOpacityMap.Free;
608 inherited Destroy;
609end;
610
611initialization
612 RegisterPolygonRenderer(TPolygonRenderer32VPR2);
613 RegisterPolygonRenderer(TPolygonRenderer32VPR2X);
614
615end.
Note: See TracBrowser for help on using the repository browser.