| 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.
|
|---|