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