📄 gr32_rasterizers.pas
字号:
unit GR32_Rasterizers;
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Graphics32
*
* The Initial Developer of the Original Code is
* Mattias Andersson
*
* Portions created by the Initial Developer are Copyright (C) 2000-2006
* the Initial Developer. All Rights Reserved.
*
* ***** END LICENSE BLOCK ***** *)
interface
{$I GR32.inc}
uses
{$IFDEF CLX}
Qt, Types, {$IFDEF LINUX}Libc, {$ELSE}Windows, {$ENDIF}
{$ELSE}
Windows,
{$ENDIF}
Classes, GR32, GR32_Blend, GR32_OrdinalMaps;
type
TAssignColor = procedure(var Dst: TColor32; Src: TColor32) of object;
PCombineInfo = ^TCombineInfo;
TCombineInfo = record
SrcAlpha: Integer;
DrawMode: TDrawMode;
CombineMode: TCombineMode;
CombineCallBack: TPixelCombineEvent;
TransparentColor: TColor32;
end;
type
{ TRasterizer }
{ A base class for TBitmap32-specific rasterizers. }
TRasterizer = class(TThreadPersistent)
private
FSampler: TCustomSampler;
FSrcAlpha: Integer;
FBlendMemEx: TBlendMemEx;
FCombineCallBack: TPixelCombineEvent;
FAssignColor: TAssignColor;
FTransparentColor: TColor32;
procedure SetSampler(const Value: TCustomSampler);
procedure AssignColorOpaque(var Dst: TColor32; Src: TColor32);
procedure AssignColorBlend(var Dst: TColor32; Src: TColor32);
procedure AssignColorCustom(var Dst: TColor32; Src: TColor32);
procedure AssignColorTransparent(var Dst: TColor32; Src: TColor32);
protected
procedure AssignTo(Dst: TPersistent); override;
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); virtual; abstract;
procedure Rasterize(Dst: TBitmap32; const DstRect: TRect; SrcAlpha: TColor32;
DrawMode: TDrawMode; CombineMode: TCombineMode;
CombineCallBack: TPixelCombineEvent); overload;
property AssignColor: TAssignColor read FAssignColor write FAssignColor;
public
procedure Rasterize(Dst: TBitmap32); overload;
procedure Rasterize(Dst: TBitmap32; const DstRect: TRect); overload;
procedure Rasterize(Dst: TBitmap32; const DstRect: TRect; const CombineInfo: TCombineInfo); overload;
procedure Rasterize(Dst: TBitmap32; const DstRect: TRect; Src: TBitmap32); overload;
published
property Sampler: TCustomSampler read FSampler write SetSampler;
end;
TRasterizerClass = class of TRasterizer;
{ TRegularSamplingRasterizer }
{ This rasterizer simply picks one sample for each pixel in the output bitmap. }
TRegularRasterizer = class(TRasterizer)
private
FUpdateRowCount: Integer;
protected
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); override;
public
constructor Create; override;
published
property UpdateRowCount: Integer read FUpdateRowCount write FUpdateRowCount;
end;
{ TSwizzlingRasterizer }
{ An interesting rasterization method where sample locations are choosen
according to a fractal pattern called 'swizzling'. With a slight
modification to the algorithm this routine will actually yield the
well-known sierpinski triangle fractal. An advantage with this pattern
is that it may benefit from local coherency in the sampling method used. }
TSwizzlingRasterizer = class(TRasterizer)
private
FBlockSize: Integer;
procedure SetBlockSize(const Value: Integer);
protected
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); override;
public
constructor Create; override;
published
property BlockSize: Integer read FBlockSize write SetBlockSize default 3;
end;
{ TProgressiveRasterizer }
{ This class will perform rasterization in a progressive manner. It performs
subsampling with a block size of 2^n and will successively decrease n in
each iteration until n equals zero. }
TProgressiveRasterizer = class(TRasterizer)
private
FSteps: Integer;
FUpdateRows: Boolean;
procedure SetSteps(const Value: Integer);
procedure SetUpdateRows(const Value: Boolean);
protected
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); override;
public
constructor Create; override;
published
property Steps: Integer read FSteps write SetSteps default 4;
property UpdateRows: Boolean read FUpdateRows write SetUpdateRows default True;
end;
{ TTesseralRasterizer }
{ This is a recursive rasterization method. It uses a divide-and-conquer
scheme to subdivide blocks vertically and horizontally into smaller blocks. }
TTesseralRasterizer = class(TRasterizer)
protected
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); override;
end;
{ TContourRasterizer }
TContourRasterizer = class(TRasterizer)
protected
procedure DoRasterize(Dst: TBitmap32; DstRect: TRect); override;
end;
{ Auxiliary routines }
function CombineInfo(Bitmap: TBitmap32): TCombineInfo;
var
DefaultRasterizerClass: TRasterizerClass = TRegularRasterizer;
implementation
uses
GR32_Resamplers, GR32_Math, GR32_Containers, Math, SysUtils;
type
TThreadPersistentAccess = class(TThreadPersistent);
function CombineInfo(Bitmap: TBitmap32): TCombineInfo;
begin
with Result do
begin
SrcAlpha := Bitmap.MasterAlpha;
DrawMode := Bitmap.DrawMode;
CombineMode := Bitmap.CombineMode;
CombineCallBack := Bitmap.OnPixelCombine;
if (DrawMode = dmCustom) and not Assigned(CombineCallBack) then
DrawMode := dmOpaque;
TransparentColor := Bitmap.OuterColor;
end;
end;
{ TRasterizer }
procedure TRasterizer.AssignColorBlend(var Dst: TColor32; Src: TColor32);
begin
FBlendMemEx(Src, Dst, FSrcAlpha);
EMMS;
end;
procedure TRasterizer.AssignColorOpaque(var Dst: TColor32; Src: TColor32);
begin
Dst := Src;
end;
procedure TRasterizer.AssignColorCustom(var Dst: TColor32; Src: TColor32);
begin
FCombineCallBack(Src, Dst, FSrcAlpha);
end;
procedure TRasterizer.AssignColorTransparent(var Dst: TColor32;
Src: TColor32);
begin
if Src <> FTransparentColor then Dst := Src;
end;
procedure TRasterizer.AssignTo(Dst: TPersistent);
begin
if Dst is TRasterizer then
SmartAssign(Self, Dst)
else
inherited;
end;
procedure TRasterizer.Rasterize(Dst: TBitmap32; const DstRect: TRect;
Src: TBitmap32);
begin
Rasterize(Dst, DstRect, CombineInfo(Src));
end;
procedure TRasterizer.Rasterize(Dst: TBitmap32; const DstRect: TRect);
const
DEFAULT_COMBINE_INFO: TCombineInfo = (
SrcAlpha: $FF;
DrawMode: dmOpaque;
CombineMode: cmBlend;
CombineCallBack: nil;
TransparentColor: clBlack32;
);
begin
Rasterize(Dst, DstRect, DEFAULT_COMBINE_INFO);
end;
procedure TRasterizer.Rasterize(Dst: TBitmap32; const DstRect: TRect;
const CombineInfo: TCombineInfo);
begin
FTransparentColor := CombineInfo.TransparentColor;
with CombineInfo do
Rasterize(Dst, DstRect, SrcAlpha, DrawMode, CombineMode, CombineCallBack);
end;
procedure TRasterizer.Rasterize(Dst: TBitmap32; const DstRect: TRect;
SrcAlpha: TColor32; DrawMode: TDrawMode; CombineMode: TCombineMode;
CombineCallBack: TPixelCombineEvent);
var
UpdateCount: Integer;
R: TRect;
begin
FSrcAlpha := SrcAlpha;
FBlendMemEx := BLEND_MEM_EX[CombineMode];
FCombineCallBack := CombineCallBack;
case DrawMode of
dmOpaque: FAssignColor := AssignColorOpaque;
dmBlend: FAssignColor := AssignColorBlend;
dmTransparent: FAssignColor := AssignColorTransparent;
else
if Assigned(FCombineCallback) then
FAssignColor := AssignColorCustom
else
FAssignColor := AssignColorBlend;
end;
UpdateCount := TThreadPersistentAccess(Dst).UpdateCount;
if Assigned(FSampler) then
begin
FSampler.PrepareSampling;
IntersectRect(R, DstRect, Dst.BoundsRect);
if FSampler.HasBounds then
IntersectRect(R, DstRect, FSampler.GetSampleBounds);
try
DoRasterize(Dst, R);
finally
while TThreadPersistentAccess(Dst).UpdateCount > UpdateCount do
TThreadPersistentAccess(Dst).EndUpdate;
FSampler.FinalizeSampling;
end;
end;
end;
procedure TRasterizer.SetSampler(const Value: TCustomSampler);
begin
if FSampler <> Value then
begin
FSampler := Value;
Changed;
end;
end;
procedure TRasterizer.Rasterize(Dst: TBitmap32);
begin
Rasterize(Dst, Dst.BoundsRect);
end;
{ TRegularRasterizer }
constructor TRegularRasterizer.Create;
begin
inherited;
FUpdateRowCount := 0;
end;
procedure TRegularRasterizer.DoRasterize(Dst: TBitmap32; DstRect: TRect);
var
I, J, UpdateCount: Integer;
P: PColor32;
GetSample: TGetSampleInt;
begin
GetSample := FSampler.GetSampleInt;
UpdateCount := 0;
for J := DstRect.Top to DstRect.Bottom - 1 do
begin
P := @Dst.Bits[DstRect.Left + J * Dst.Width];
for I := DstRect.Left to DstRect.Right - 1 do
begin
AssignColor(P^, GetSample(I, J));
Inc(P);
end;
Inc(UpdateCount);
if UpdateCount = FUpdateRowCount then
begin
Dst.Changed(Rect(DstRect.Left, J - UpdateCount, DstRect.Right, J));
UpdateCount := 0;
end;
end;
with DstRect do
Dst.Changed(Rect(Left, Bottom - UpdateCount - 1, Right, Bottom));
end;
{ TSwizzlingRasterizer }
constructor TSwizzlingRasterizer.Create;
begin
inherited;
FBlockSize := 3;
end;
procedure TSwizzlingRasterizer.DoRasterize(Dst: TBitmap32; DstRect: TRect);
var
I, L, T, W, H, Size, RowSize, D: Integer;
P1, P2, PBlock: TPoint;
GetSample: TGetSampleInt;
ForwardBuffer: array of Integer;
function ScanReverse(Value: Integer): Integer;
asm
BSR EAX,EAX
end;
function GetDstCoord(P: TPoint): TPoint;
var
XI, YI: Integer;
begin
Result := P;
Inc(Result.X);
Inc(Result.Y);
XI := ForwardBuffer[Result.X];
YI := ForwardBuffer[Result.Y];
if XI <= YI then
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -