123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- unit GR32_Blend;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * 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.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Graphics32
- *
- * The Initial Developer of the Original Code is
- * Alex A. Denisov
- *
- * Portions created by the Initial Developer are Copyright (C) 2000-2009
- * the Initial Developer. All Rights Reserved.
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$include GR32.inc}
- uses
- GR32,
- GR32_Bindings;
- //------------------------------------------------------------------------------
- //
- // Alpha Composition
- //
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- // Blend
- //------------------------------------------------------------------------------
- //
- // The Blend operation mixes a foreground color (F) onto a background color (B),
- // using the alpha channel value of F:
- //
- // Result Z = Fa * (Fargb - Bargb) + Bargb
- // = Fa * Fargb + (1 - Fa) * Bargb
- //
- // The background color is assumed to be fully opaque (i.e. Ba=255).
- // If the alpha of the background is to be taken into account, the Merge
- // operation should be used instead.
- //
- // The blend operation is commonly just referred to as "alpha blending".
- //
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- // Merge
- //------------------------------------------------------------------------------
- //
- // The Merge operation is based on a formula described in a paper by Bruce
- // Wallace in 1981.
- //
- // Merging is associative, that is, A over (B over C) = (A over B) over C.
- //
- // The formula is,
- //
- // Ra = Fa + Ba * (1 - Fa)
- // Rc = (Fa * (Fc - Bc * Ba) + Bc * Ba) / Ra
- //
- // where
- //
- // Rc is the resultant color,
- // Ra is the resultant alpha,
- // Fc is the foreground color,
- // Fa is the foreground alpha,
- // Bc is the background color,
- // Ba is the background alpha.
- //
- // Implementation:
- //
- // Ra := 1 - (1 - Fa) * (1 - Ba);
- // Wa := Fa / Ra;
- // Rc := Bc + Wa * (Fc - Bc);
- //
- // (1 - Fa) * (1 - Ba) = 1 - Fa - Ba + Fa * Ba = (1 - Ra)
- //
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- // Combine
- //------------------------------------------------------------------------------
- //
- // The Combine operation performs linear interpolation, commonly refered to as
- // "Lerp", between two colors (X and Y), given a weight (W):
- //
- // Result Z = W * X + (1 - W) * Y
- // = W * (X - Y) + Y
- //
- // All channels are combined, including the alpha channel.
- //
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- //
- // Function Prototypes
- //
- //------------------------------------------------------------------------------
- type
- //------------------------------------------------------------------------------
- // Blend & Merge
- //------------------------------------------------------------------------------
- TBlendReg = function(F, B: TColor32): TColor32;
- TBlendMem = procedure(F: TColor32; var B: TColor32);
- TBlendMems = procedure(F: TColor32; B: PColor32; Count: Integer);
- TBlendRegEx = function(F, B: TColor32; M: Cardinal): TColor32;
- TBlendMemEx = procedure(F: TColor32; var B: TColor32; M: Cardinal);
- TBlendRegRGB = function(F, B: TColor32; W: Cardinal): TColor32;
- TBlendMemRGB = procedure(F: TColor32; var B: TColor32; W: Cardinal);
- {$IFDEF TEST_BLENDMEMRGB128SSE4}
- TBlendMemRGB128 = procedure(F: TColor32; var B: TColor32; W: UInt64);
- {$ENDIF}
- TBlendLine = procedure(Src, Dst: PColor32; Count: Integer);
- TBlendLineEx = procedure(Src, Dst: PColor32; Count: Integer; M: Cardinal);
- TBlendLine1 = TBlendMems deprecated 'Use TBlendMems';
- //------------------------------------------------------------------------------
- // Combine
- //------------------------------------------------------------------------------
- TCombineReg = function(X, Y: TColor32; W: Cardinal): TColor32;
- TCombineMem = procedure(X: TColor32; var Y: TColor32; W: Cardinal);
- TCombineLine = procedure(Src, Dst: PColor32; Count: Integer; W: Cardinal);
- //------------------------------------------------------------------------------
- // Misc
- //------------------------------------------------------------------------------
- TLightenReg = function(C: TColor32; Amount: Integer): TColor32;
- TScaleMems = procedure(Dst: PColor32; Count: Integer; Weight: Cardinal);
- //------------------------------------------------------------------------------
- //
- // Function variables (i.e. delegates)
- //
- //------------------------------------------------------------------------------
- var
- //------------------------------------------------------------------------------
- // Blend
- //------------------------------------------------------------------------------
- BlendReg: TBlendReg;
- BlendMem: TBlendMem;
- BlendMems: TBlendMems;
- BlendRegEx: TBlendRegEx;
- BlendMemEx: TBlendMemEx;
- BlendRegRGB: TBlendRegRGB;
- BlendMemRGB: TBlendMemRGB;
- {$IFDEF TEST_BLENDMEMRGB128SSE4}
- BlendMemRGB128: TBlendMemRGB128;
- {$ENDIF}
- BlendLine: TBlendLine;
- BlendLineEx: TBlendLineEx;
- //------------------------------------------------------------------------------
- // Merge
- //------------------------------------------------------------------------------
- MergeReg: TBlendReg;
- MergeMem: TBlendMem;
- MergeMems: TBlendMems;
- MergeRegEx: TBlendRegEx;
- MergeMemEx: TBlendMemEx;
- MergeLine: TBlendLine;
- MergeLineEx: TBlendLineEx;
- //------------------------------------------------------------------------------
- // Combine
- //------------------------------------------------------------------------------
- CombineReg: TCombineReg;
- CombineMem: TCombineMem;
- CombineLine: TCombineLine;
- //------------------------------------------------------------------------------
- // Color algebra
- //------------------------------------------------------------------------------
- ColorAdd: TBlendReg;
- ColorSub: TBlendReg;
- ColorDiv: TBlendReg;
- ColorModulate: TBlendReg;
- ColorMax: TBlendReg;
- ColorMin: TBlendReg;
- ColorDifference: TBlendReg;
- ColorAverage: TBlendReg;
- ColorExclusion: TBlendReg;
- ColorScale: TBlendReg;
- ColorScreen: TBlendReg;
- ColorDodge: TBlendReg;
- ColorBurn: TBlendReg;
- //------------------------------------------------------------------------------
- // Blended color algebra
- //------------------------------------------------------------------------------
- BlendColorAdd: TBlendReg;
- BlendColorModulate: TBlendReg;
- //------------------------------------------------------------------------------
- // Misc
- //------------------------------------------------------------------------------
- LightenReg: TLightenReg;
- Lighten: TLightenReg absolute LightenReg; // Lighten is an alias for LigthenReg
- ScaleMems: TScaleMems;
- //------------------------------------------------------------------------------
- //
- // Access to alpha composite functions corresponding to a combine mode
- //
- //------------------------------------------------------------------------------
- type
- PBlendReg = ^TBlendReg;
- PBlendMem = ^TBlendMem;
- PBlendRegEx = ^TBlendRegEx;
- PBlendMemEx = ^TBlendMemEx;
- PBlendLine = ^TBlendLine;
- PBlendLineEx = ^TBlendLineEx;
- TBlendRegCombineModeArray = array[TCombineMode] of PBlendReg;
- TBlendMemCombineModeArray = array[TCombineMode] of PBlendMem;
- TBlendRegExCombineModeArray = array[TCombineMode] of PBlendRegEx;
- TBlendMemExCombineModeArray = array[TCombineMode] of PBlendMemEx;
- TBlendLineCombineModeArray = array[TCombineMode] of PBlendLine;
- TBlendLineExCombineModeArray = array[TCombineMode] of PBlendLineEx;
- const
- BLEND_REG: TBlendRegCombineModeArray = ((@@BlendReg),(@@MergeReg));
- BLEND_MEM: TBlendMemCombineModeArray = ((@@BlendMem),(@@MergeMem));
- BLEND_REG_EX: TBlendRegExCombineModeArray = ((@@BlendRegEx),(@@MergeRegEx));
- BLEND_MEM_EX: TBlendMemExCombineModeArray = ((@@BlendMemEx),(@@MergeMemEx));
- BLEND_LINE: TBlendLineCombineModeArray = ((@@BlendLine),(@@MergeLine));
- BLEND_LINE_EX: TBlendLineExCombineModeArray = ((@@BlendLineEx),(@@MergeLineEx));
- //------------------------------------------------------------------------------
- //
- // Function bindings
- //
- //------------------------------------------------------------------------------
- function BlendRegistry: TFunctionRegistry;
- const
- FID_EMMS = 0 deprecated;
- FID_MERGEREG = 1;
- FID_MERGEMEM = 2;
- FID_MERGELINE = 3;
- FID_MERGEMEMS = 4;
- FID_MERGELINE1 = FID_MERGEMEMS deprecated;
- FID_MERGEREGEX = 5;
- FID_MERGEMEMEX = 6;
- FID_MERGELINEEX = 7;
- FID_COMBINEREG = 8;
- FID_COMBINEMEM = 9;
- FID_COMBINELINE = 10;
- FID_BLENDREG = 11;
- FID_BLENDMEM = 12;
- FID_BLENDMEMS = 13;
- FID_BLENDLINE = 14;
- FID_BLENDREGEX = 15;
- FID_BLENDMEMEX = 16;
- FID_BLENDLINEEX = 17;
- FID_BLENDLINE1 = 18 deprecated;
- FID_COLORMAX = 19;
- FID_COLORMIN = 20;
- FID_COLORAVERAGE = 21;
- FID_COLORADD = 22;
- FID_COLORSUB = 23;
- FID_COLORDIV = 24;
- FID_COLORMODULATE = 25;
- FID_COLORDIFFERENCE = 26;
- FID_COLOREXCLUSION = 27;
- FID_COLORSCALE = 28;
- FID_COLORSCREEN = 29;
- FID_COLORDODGE = 30;
- FID_COLORBURN = 31;
- FID_BLENDCOLORADD = 32;
- FID_BLENDCOLORMODULATE= 33;
- FID_LIGHTEN = 34;
- FID_BLENDREGRGB = 35;
- FID_BLENDMEMRGB = 36;
- {$IFDEF TEST_BLENDMEMRGB128SSE4}
- FID_BLENDMEMRGB128 = 37;
- {$ENDIF}
- //------------------------------------------------------------------------------
- //
- // Blending related lookup tables
- //
- //------------------------------------------------------------------------------
- type
- TLUT8 = array[byte] of byte;
- PLUT8 = ^TLUT8;
- TLUT88 = array [byte] of TLUT8;
- var
- //
- // DivMul255Table contains the result of a *division* of two values, specified
- // in the byte range:
- //
- // DivMul255Table[a, b] = Round(b * 255 / a)
- //
- // It is commonly used to perform the division of the merge operation:
- //
- // ResultColor = DivMul255Table[ResultAlpha, Color] = Color / ResultAlpha
- //
- // or unpremultiplication:
- //
- // Color = DivMul255Table[Alpha, PremultColor] = PremultColor / Alpha
- //
- DivMul255Table: TLUT88;
- //
- // MulDiv255Table contains the result of a *multiplication* of two values,
- // specified in the byte range:
- //
- // MulDiv255Table[a, b] = Round(a * b / 255)
- //
- // It is commonly used to perform the multiplications of the blend or merge operations:
- //
- // TempColor = MulDiv255Table[Color, Alpha] = Color * Alpha
- //
- // or premultiplication:
- //
- // PremultColor = MulDiv255Table[Color, Alpha] = Color * Alpha
- //
- MulDiv255Table: TLUT88;
- // RcTable and DivTable are the old names of the above two tables.
- // They are kept for backward compatibility and should be considered deprecated.
- var
- RcTable: TLUT88 absolute DivMul255Table;
- DivTable: TLUT88 absolute MulDiv255Table;
- //------------------------------------------------------------------------------
- type
- TMultEntry = array[0..3] of TColor32Entry;
- PMultEntry = ^TMultEntry;
- TMultTable = array[byte] of TMultEntry;
- PMultTable = ^TMultTable;
- var
- //
- // alpha_ptr: Pointer to a 16-byte aligned array[256] of 4 cardinal values.
- // The table is used to implement vectorized division by 255 in SIMD functions:
- //
- // (x div 255) = ((x + 128) shr 8)
- // = ((alpha_ptr[x] + bias_ptr^) shr 8)
- //
- alpha_ptr: PMultTable;
- //
- // bias_ptr points to the middle entry of the alpha_ptr table.
- // The entry contains the 4 cardinal values 00000080 00000080 00000080 00000080.
- //
- bias_ptr: PMultEntry;
- //------------------------------------------------------------------------------
- //
- // Backward compatibility
- //
- //------------------------------------------------------------------------------
- procedure MergeLine1(F: TColor32; B: PColor32; Count: Integer); {$IFDEF USEINLINING} inline; {$ENDIF} deprecated 'Use MergeMems';
- procedure BlendLine1(F: TColor32; B: PColor32; Count: Integer); {$IFDEF USEINLINING} inline; {$ENDIF} deprecated 'Use BlendMems';
- procedure EMMS; {$if defined(PUREPASCAL) or ((not defined(TARGET_X64)) and (not defined(TARGET_X86)))} {$IFDEF USEINLINING} inline; {$ENDIF} {$ifend} deprecated 'Graphics32 no longer supports MMX so calling EMMS is not necessary anymore';
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- implementation
- uses
- GR32_System,
- {$IFNDEF PUREPASCAL}
- GR32.Blend.Assembler,
- {$IFNDEF OMIT_SSE2}
- GR32.Blend.SSE2,
- {$ENDIF}
- {$ENDIF}
- GR32.Blend.Pascal;
- //------------------------------------------------------------------------------
- //
- // GenAlphaTable
- //
- //------------------------------------------------------------------------------
- var
- AlphaTable: Pointer;
- procedure GenAlphaTable;
- var
- i: Integer;
- Color: TColor32Entry;
- begin
- GetMem(AlphaTable, SizeOf(TMultTable) + 16); // + 16 bytes for alignment
- // Align to 16 bytes
- alpha_ptr := pointer((NativeUInt(AlphaTable) + $F) and (not $F));
- // Values for division by 255: (x div 255) = ((alpha_ptr[x] + 128) shl 8)
- // Originally 2 entries per value for ASM and MMX.
- // Later expanded to 4 entries per value so the table can also be used with SSE.
- for i := Low(TMultTable) to High(TMultTable) do
- begin
- Color.Planes[0] := i;
- Color.Planes[1] := 0;
- Color.Planes[2] := i;
- Color.Planes[3] := 0;
- alpha_ptr[i][0] := Color;
- alpha_ptr[i][1] := Color;
- alpha_ptr[i][2] := Color;
- alpha_ptr[i][3] := Color;
- end;
- // bias_ptr points to ($80, 0, $80, 0)
- bias_ptr := @alpha_ptr[128][0];
- end;
- procedure FreeAlphaTable;
- begin
- if (AlphaTable <> nil) then
- FreeMem(AlphaTable);
- end;
- //------------------------------------------------------------------------------
- //
- // MakeMergeTables
- //
- //------------------------------------------------------------------------------
- procedure MakeMergeTables;
- var
- i, j: Integer;
- begin
- for j := 0 to 255 do
- begin
- for i := j to 255 do
- begin
- MulDiv255Table[i, j] := Round(i * j * COne255th);
- if (i <> j) then
- MulDiv255Table[j, i] := MulDiv255Table[i, j]; // a*b = b*a
- end;
- DivMul255Table[0, j] := 0;
- for i := 1 to 255 do
- begin
- if i > j then
- DivMul255Table[i, j] := Round(j * 255 / i)
- else
- DivMul255Table[i, j] := 255;
- end;
- end;
- end;
- //------------------------------------------------------------------------------
- //
- // Backward compatibility
- //
- //------------------------------------------------------------------------------
- procedure MergeLine1(F: TColor32; B: PColor32; Count: Integer);
- begin
- MergeMems(F, B, Count);
- end;
- procedure BlendLine1(F: TColor32; B: PColor32; Count: Integer);
- begin
- BlendMems(F, B, Count);
- end;
- {$if defined(PUREPASCAL) or ((not defined(TARGET_X64)) and (not defined(TARGET_X86)))}
- procedure EMMS;
- begin
- end;
- {$else}
- procedure EMMS; {$IFDEF FPC} assembler; nostackframe; {$ENDIF}
- asm
- EMMS
- end;
- {$ifend}
- //------------------------------------------------------------------------------
- //
- // Function bindings
- //
- //------------------------------------------------------------------------------
- procedure RegisterBindings;
- begin
- BlendRegistry.RegisterBinding(FID_BLENDREG, @@BlendReg, 'BlendReg');
- BlendRegistry.RegisterBinding(FID_BLENDMEM, @@BlendMem, 'BlendMem');
- BlendRegistry.RegisterBinding(FID_BLENDMEMS, @@BlendMems, 'BlendMems');
- BlendRegistry.RegisterBinding(FID_BLENDLINE, @@BlendLine, 'BlendLine');
- BlendRegistry.RegisterBinding(FID_BLENDREGEX, @@BlendRegEx, 'BlendRegEx');
- BlendRegistry.RegisterBinding(FID_BLENDMEMEX, @@BlendMemEx, 'BlendMemEx');
- BlendRegistry.RegisterBinding(FID_BLENDLINEEX, @@BlendLineEx, 'BlendLineEx');
- BlendRegistry.RegisterBinding(FID_BLENDREGRGB, @@BlendRegRGB, 'BlendRegRGB');
- BlendRegistry.RegisterBinding(FID_BLENDMEMRGB, @@BlendMemRGB, 'BlendMemRGB');
- {$IFDEF TEST_BLENDMEMRGB128SSE4}
- BlendRegistry.RegisterBinding(FID_BLENDMEMRGB128, @@BlendMemRGB128, 'BlendMemRGB128');
- {$ENDIF}
- BlendRegistry.RegisterBinding(FID_MERGEREG, @@MergeReg, 'MergeReg');
- BlendRegistry.RegisterBinding(FID_MERGEMEM, @@MergeMem, 'MergeMem');
- BlendRegistry.RegisterBinding(FID_MERGEMEMS, @@MergeMems, 'MergeMems');
- BlendRegistry.RegisterBinding(FID_MERGELINE, @@MergeLine, 'MergeLine');
- BlendRegistry.RegisterBinding(FID_MERGEREGEX, @@MergeRegEx, 'MergeRegEx');
- BlendRegistry.RegisterBinding(FID_MERGEMEMEX, @@MergeMemEx, 'MergeMemEx');
- BlendRegistry.RegisterBinding(FID_MERGELINEEX, @@MergeLineEx, 'MergeLineEx');
- BlendRegistry.RegisterBinding(FID_COMBINEREG, @@CombineReg, 'CombineReg');
- BlendRegistry.RegisterBinding(FID_COMBINEMEM, @@CombineMem, 'CombineMem');
- BlendRegistry.RegisterBinding(FID_COMBINELINE, @@CombineLine, 'CombineLine');
- BlendRegistry.RegisterBinding(FID_COLORMAX, @@ColorMax, 'ColorMax');
- BlendRegistry.RegisterBinding(FID_COLORMIN, @@ColorMin, 'ColorMin');
- BlendRegistry.RegisterBinding(FID_COLORAVERAGE, @@ColorAverage, 'ColorAverage');
- BlendRegistry.RegisterBinding(FID_COLORADD, @@ColorAdd, 'ColorAdd');
- BlendRegistry.RegisterBinding(FID_COLORSUB, @@ColorSub, 'ColorSub');
- BlendRegistry.RegisterBinding(FID_COLORDIV, @@ColorDiv, 'ColorDiv');
- BlendRegistry.RegisterBinding(FID_COLORMODULATE, @@ColorModulate, 'ColorModulate');
- BlendRegistry.RegisterBinding(FID_COLORDIFFERENCE, @@ColorDifference, 'ColorDifference');
- BlendRegistry.RegisterBinding(FID_COLOREXCLUSION, @@ColorExclusion, 'ColorExclusion');
- BlendRegistry.RegisterBinding(FID_COLORSCALE, @@ColorScale, 'ColorScale');
- BlendRegistry.RegisterBinding(FID_COLORSCREEN, @@ColorScreen, 'ColorScreen');
- BlendRegistry.RegisterBinding(FID_COLORDODGE, @@ColorDodge, 'ColorDodge');
- BlendRegistry.RegisterBinding(FID_COLORBURN, @@ColorBurn, 'ColorBurn');
- BlendRegistry.RegisterBinding(FID_BLENDCOLORADD, @@BlendColorAdd, 'BlendColorAdd');
- BlendRegistry.RegisterBinding(FID_BLENDCOLORMODULATE, @@BlendColorModulate, 'BlendColorModulate');
- BlendRegistry.RegisterBinding(FID_LIGHTEN, @@LightenReg, 'LightenReg');
- BlendRegistry.RegisterBinding(@@ScaleMems, 'ScaleMems');
- end;
- var
- FBlendRegistry: TFunctionRegistry = nil;
- function BlendRegistry: TFunctionRegistry;
- begin
- if (FBlendRegistry = nil) then
- begin
- FBlendRegistry := NewRegistry('GR32_Blend bindings');
- RegisterBindings;
- end;
- Result := FBlendRegistry;
- end;
- //------------------------------------------------------------------------------
- initialization
- BlendRegistry.RebindAll;
- MakeMergeTables;
- AlphaTable := nil;
- if [isSSE2] * CPU.InstructionSupport <> [] then
- GenAlphaTable;
- finalization
- FreeAlphaTable;
- end.
|