| 1 | unit BGRABlend;
|
|---|
| 2 |
|
|---|
| 3 | { This unit contains pixel blending functions. They take a destination adress as parameter,
|
|---|
| 4 | and draw pixels at this address with different blending modes. These functions are used
|
|---|
| 5 | by many functions in BGRABitmap library to do the low level drawing. }
|
|---|
| 6 |
|
|---|
| 7 | {$mode objfpc}{$H+}
|
|---|
| 8 |
|
|---|
| 9 | interface
|
|---|
| 10 |
|
|---|
| 11 | uses
|
|---|
| 12 | BGRABitmapTypes;
|
|---|
| 13 |
|
|---|
| 14 | { Draw one pixel with alpha blending }
|
|---|
| 15 | procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
|
|---|
| 16 | procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte); inline; overload;
|
|---|
| 17 | procedure DrawExpandedPixelInlineWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel); inline; overload;
|
|---|
| 18 | procedure DrawPixelInlineExpandedOrNotWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; c: TBGRAPixel); inline; overload; //alpha in 'c' parameter
|
|---|
| 19 | procedure DrawPixelInlineNoAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
|
|---|
| 20 | procedure DrawExpandedPixelInlineNoAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; calpha: byte); inline; overload;
|
|---|
| 21 | procedure ClearTypeDrawPixel(pdest: PBGRAPixel; Cr, Cg, Cb: byte; Color: TBGRAPixel); inline;
|
|---|
| 22 | procedure InterpolateBilinear(pUpLeft,pUpRight,pDownLeft,pDownRight: PBGRAPixel;
|
|---|
| 23 | iFactX,iFactY: Integer; ADest: PBGRAPixel);
|
|---|
| 24 |
|
|---|
| 25 | procedure CopyPixelsWithOpacity(dest,src: PBGRAPixel; opacity: byte; Count: integer); inline;
|
|---|
| 26 | function ApplyOpacity(opacity1,opacity2: byte): byte; inline;
|
|---|
| 27 | function FastRoundDiv255(value: cardinal): cardinal; inline;
|
|---|
| 28 |
|
|---|
| 29 | { Draw a series of pixels with alpha blending }
|
|---|
| 30 | procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer; mode: TDrawMode; AOpacity:byte);
|
|---|
| 31 | procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline; overload;
|
|---|
| 32 | procedure DrawExpandedPixelsInline(dest: PBGRAPixel; ec: TExpandedPixel; Count: integer); inline; overload;
|
|---|
| 33 | procedure DrawPixelsInlineExpandedOrNot(dest: PBGRAPixel; ec: TExpandedPixel; c: TBGRAPixel; Count: integer); inline; overload; //alpha in 'c' parameter
|
|---|
| 34 |
|
|---|
| 35 | { Draw one pixel with linear alpha blending }
|
|---|
| 36 | procedure FastBlendPixelInline(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
|
|---|
| 37 | procedure FastBlendPixelInline(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte); inline; overload;
|
|---|
| 38 |
|
|---|
| 39 | { Draw a series of pixels with linear alpha blending }
|
|---|
| 40 | procedure FastBlendPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
|
|---|
| 41 |
|
|---|
| 42 | { Replace a series of pixels }
|
|---|
| 43 | procedure FillInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
|
|---|
| 44 |
|
|---|
| 45 | { Xor a series of pixels }
|
|---|
| 46 | procedure XorInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
|
|---|
| 47 | procedure XorPixels(pdest, psrc: PBGRAPixel; count: integer);
|
|---|
| 48 |
|
|---|
| 49 | { Set alpha value for a series of pixels }
|
|---|
| 50 | procedure AlphaFillInline(dest: PBGRAPixel; alpha: byte; Count: integer); inline;
|
|---|
| 51 |
|
|---|
| 52 | { Erase a series of pixels, i.e. decrease alpha value }
|
|---|
| 53 | procedure ErasePixelInline(dest: PBGRAPixel; alpha: byte); inline;
|
|---|
| 54 |
|
|---|
| 55 | { Draw a pixel to the extent the current pixel is close enough to compare value.
|
|---|
| 56 | It should not be called on pixels that have not been checked to be close enough }
|
|---|
| 57 | procedure DrawPixelInlineDiff(dest: PBGRAPixel; c, compare: TBGRAPixel;
|
|---|
| 58 | maxDiff: byte); inline;
|
|---|
| 59 | { Draw a series of pixel to the extent the current pixel is close enough to compare value }
|
|---|
| 60 | procedure DrawPixelsInlineDiff(dest: PBGRAPixel; c: TBGRAPixel;
|
|---|
| 61 | Count: integer; compare: TBGRAPixel; maxDiff: byte); inline;
|
|---|
| 62 |
|
|---|
| 63 | { Blend pixels with scanner content }
|
|---|
| 64 | procedure ScannerPutPixels(scan: IBGRAScanner; pdest: PBGRAPixel; count: integer; mode: TDrawMode);
|
|---|
| 65 |
|
|---|
| 66 | { Perform advanced blending operation }
|
|---|
| 67 | procedure BlendPixels(pdest: PBGRAPixel; psrc: PBGRAPixel;
|
|---|
| 68 | blendOp: TBlendOperation; Count: integer);
|
|---|
| 69 |
|
|---|
| 70 | { Perform blending operation and merge over destination }
|
|---|
| 71 | procedure BlendPixelsOver(pdest: PBGRAPixel; psrc: PBGRAPixel;
|
|---|
| 72 | blendOp: TBlendOperation; Count: integer; opacity: byte; linearBlend: boolean = false);
|
|---|
| 73 |
|
|---|
| 74 | //layer blend modes
|
|---|
| 75 | //- http://www.pegtop.net/delphi/articles/blendmodes/
|
|---|
| 76 | //- http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/#comp-op
|
|---|
| 77 | //- http://docs.gimp.org/en/gimp-concepts-layer-modes.html
|
|---|
| 78 | procedure LinearMultiplyPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 79 | procedure AddPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 80 | procedure LinearAddPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 81 | procedure ColorBurnPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 82 | procedure ColorDodgePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 83 | procedure DividePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 84 | procedure ReflectPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 85 | procedure NonLinearReflectPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 86 | procedure GlowPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 87 | procedure NiceGlowPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 88 | procedure OverlayPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 89 | procedure LinearOverlayPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 90 | procedure DifferencePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 91 | procedure LinearDifferencePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 92 | procedure ExclusionPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 93 | procedure LinearExclusionPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 94 | procedure LinearSubtractPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 95 | procedure LinearSubtractInversePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 96 | procedure SubtractPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 97 | procedure SubtractInversePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 98 | procedure NegationPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 99 | procedure LinearNegationPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 100 | procedure LightenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 101 | procedure DarkenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 102 | procedure ScreenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 103 | procedure SoftLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 104 | procedure SvgSoftLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 105 | procedure HardLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 106 | procedure BlendXorPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
|
|---|
| 107 | procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
|
|---|
| 108 | procedure BGRAFillClearTypeRGBMask(dest: TBGRACustomBitmap; x, y: integer;
|
|---|
| 109 | mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner;
|
|---|
| 110 | KeepRGBOrder: boolean);
|
|---|
| 111 | procedure BGRAFillClearTypeMaskPtr(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; maskData: PByte; maskPixelSize: NativeInt; maskRowSize: NativeInt; maskWidth,maskHeight: integer; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
|
|---|
| 112 |
|
|---|
| 113 | implementation
|
|---|
| 114 |
|
|---|
| 115 | procedure BGRAFillClearTypeMaskPtr(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; maskData: PByte; maskPixelSize: NativeInt; maskRowSize: NativeInt; maskWidth,maskHeight: integer; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
|
|---|
| 116 | var
|
|---|
| 117 | pdest: PBGRAPixel;
|
|---|
| 118 | ClearTypePixel: array[0..2] of byte;
|
|---|
| 119 | curThird: integer;
|
|---|
| 120 |
|
|---|
| 121 | procedure OutputPixel; inline;
|
|---|
| 122 | begin
|
|---|
| 123 | if texture <> nil then
|
|---|
| 124 | color := texture.ScanNextPixel;
|
|---|
| 125 | if RGBOrder then
|
|---|
| 126 | ClearTypeDrawPixel(pdest, ClearTypePixel[0],ClearTypePixel[1],ClearTypePixel[2], color)
|
|---|
| 127 | else
|
|---|
| 128 | ClearTypeDrawPixel(pdest, ClearTypePixel[2],ClearTypePixel[1],ClearTypePixel[0], color);
|
|---|
| 129 | end;
|
|---|
| 130 |
|
|---|
| 131 | procedure NextAlpha(alphaValue: byte); inline;
|
|---|
| 132 | begin
|
|---|
| 133 | ClearTypePixel[curThird] := alphaValue;
|
|---|
| 134 | inc(curThird);
|
|---|
| 135 | if curThird = 3 then
|
|---|
| 136 | begin
|
|---|
| 137 | OutputPixel;
|
|---|
| 138 | curThird := 0;
|
|---|
| 139 | Fillchar(ClearTypePixel, sizeof(ClearTypePixel),0);
|
|---|
| 140 | inc(pdest);
|
|---|
| 141 | end;
|
|---|
| 142 | end;
|
|---|
| 143 |
|
|---|
| 144 | procedure EndRow; inline;
|
|---|
| 145 | begin
|
|---|
| 146 | if curThird > 0 then OutputPixel;
|
|---|
| 147 | end;
|
|---|
| 148 |
|
|---|
| 149 | var
|
|---|
| 150 | yMask,n: integer;
|
|---|
| 151 | a: byte;
|
|---|
| 152 | pmask: PByte;
|
|---|
| 153 | dx:integer;
|
|---|
| 154 | miny,maxy,minx,minxThird,maxx,alphaMinX,alphaMaxX,alphaLineLen: integer;
|
|---|
| 155 | leftOnSide, rightOnSide: boolean;
|
|---|
| 156 | countBetween: integer;
|
|---|
| 157 | v1,v2,v3: byte;
|
|---|
| 158 |
|
|---|
| 159 | procedure StartRow; inline;
|
|---|
| 160 | begin
|
|---|
| 161 | pdest := dest.Scanline[yMask+y]+minx;
|
|---|
| 162 | if texture <> nil then
|
|---|
| 163 | texture.ScanMoveTo(minx,yMask+y);
|
|---|
| 164 |
|
|---|
| 165 | curThird := minxThird;
|
|---|
| 166 | ClearTypePixel[0] := 0;
|
|---|
| 167 | ClearTypePixel[1] := 0;
|
|---|
| 168 | ClearTypePixel[2] := 0;
|
|---|
| 169 | end;
|
|---|
| 170 |
|
|---|
| 171 | begin
|
|---|
| 172 | alphaLineLen := maskWidth+2;
|
|---|
| 173 |
|
|---|
| 174 | xThird -= 1; //for first subpixel
|
|---|
| 175 |
|
|---|
| 176 | if xThird >= 0 then dx := xThird div 3
|
|---|
| 177 | else dx := -((-xThird+2) div 3);
|
|---|
| 178 | x += dx;
|
|---|
| 179 | xThird -= dx*3;
|
|---|
| 180 |
|
|---|
| 181 | if y >= dest.ClipRect.Top then miny := 0
|
|---|
| 182 | else miny := dest.ClipRect.Top-y;
|
|---|
| 183 | if y+maskHeight-1 < dest.ClipRect.Bottom then
|
|---|
| 184 | maxy := maskHeight-1 else
|
|---|
| 185 | maxy := dest.ClipRect.Bottom-1-y;
|
|---|
| 186 |
|
|---|
| 187 | if x >= dest.ClipRect.Left then
|
|---|
| 188 | begin
|
|---|
| 189 | minx := x;
|
|---|
| 190 | minxThird := xThird;
|
|---|
| 191 | alphaMinX := 0;
|
|---|
| 192 | leftOnSide := false;
|
|---|
| 193 | end else
|
|---|
| 194 | begin
|
|---|
| 195 | minx := dest.ClipRect.Left;
|
|---|
| 196 | minxThird := 0;
|
|---|
| 197 | alphaMinX := (dest.ClipRect.Left-x)*3 - xThird;
|
|---|
| 198 | leftOnSide := true;
|
|---|
| 199 | end;
|
|---|
| 200 |
|
|---|
| 201 | if x*3+xThird+maskWidth-1 < dest.ClipRect.Right*3 then
|
|---|
| 202 | begin
|
|---|
| 203 | maxx := (x*3+xThird+maskWidth-1) div 3;
|
|---|
| 204 | alphaMaxX := alphaLineLen-1;
|
|---|
| 205 | rightOnSide := false;
|
|---|
| 206 | end else
|
|---|
| 207 | begin
|
|---|
| 208 | maxx := dest.ClipRect.Right-1;
|
|---|
| 209 | alphaMaxX := maxx*3+2 - (x*3+xThird);
|
|---|
| 210 | rightOnSide := true;
|
|---|
| 211 | end;
|
|---|
| 212 |
|
|---|
| 213 | countBetween := alphaMaxX-alphaMinX-1;
|
|---|
| 214 |
|
|---|
| 215 | if (alphaMinX <= alphaMaxX) then
|
|---|
| 216 | begin
|
|---|
| 217 | for yMask := miny to maxy do
|
|---|
| 218 | begin
|
|---|
| 219 | StartRow;
|
|---|
| 220 |
|
|---|
| 221 | if leftOnSide then
|
|---|
| 222 | begin
|
|---|
| 223 | pmask := maskData + (yMask*maskRowSize)+ (alphaMinX-1)*maskPixelSize;
|
|---|
| 224 | a := pmask^ div 3;
|
|---|
| 225 | v1 := a+a;
|
|---|
| 226 | v2 := a;
|
|---|
| 227 | v3 := 0;
|
|---|
| 228 | inc(pmask, maskPixelSize);
|
|---|
| 229 | end else
|
|---|
| 230 | begin
|
|---|
| 231 | pmask := maskData + (yMask*maskRowSize);
|
|---|
| 232 | v1 := 0;
|
|---|
| 233 | v2 := 0;
|
|---|
| 234 | v3 := 0;
|
|---|
| 235 | end;
|
|---|
| 236 |
|
|---|
| 237 | for n := countBetween-1 downto 0 do
|
|---|
| 238 | begin
|
|---|
| 239 | a := pmask^ div 3;
|
|---|
| 240 | v1 += a;
|
|---|
| 241 | v2 += a;
|
|---|
| 242 | v3 += a;
|
|---|
| 243 | inc(pmask, maskPixelSize);
|
|---|
| 244 |
|
|---|
| 245 | NextAlpha(v1);
|
|---|
| 246 | v1 := v2;
|
|---|
| 247 | v2 := v3;
|
|---|
| 248 | v3 := 0;
|
|---|
| 249 | end;
|
|---|
| 250 |
|
|---|
| 251 | if rightOnSide then
|
|---|
| 252 | begin
|
|---|
| 253 | a := pmask^ div 3;
|
|---|
| 254 | v1 += a;
|
|---|
| 255 | v2 += a+a;
|
|---|
| 256 | end;
|
|---|
| 257 |
|
|---|
| 258 | NextAlpha(v1);
|
|---|
| 259 | NextAlpha(v2);
|
|---|
| 260 |
|
|---|
| 261 | EndRow;
|
|---|
| 262 | end;
|
|---|
| 263 | end;
|
|---|
| 264 | end;
|
|---|
| 265 |
|
|---|
| 266 | procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
|
|---|
| 267 | var delta: NativeInt;
|
|---|
| 268 | begin
|
|---|
| 269 | delta := mask.Width*sizeof(TBGRAPixel);
|
|---|
| 270 | if mask.LineOrder = riloBottomToTop then
|
|---|
| 271 | delta := -delta;
|
|---|
| 272 | BGRAFillClearTypeMaskPtr(dest,x,y,xThird,pbyte(mask.ScanLine[0])+1,sizeof(TBGRAPixel),delta,mask.Width,mask.Height,color,texture,RGBOrder);
|
|---|
| 273 | end;
|
|---|
| 274 |
|
|---|
| 275 | procedure BGRAFillClearTypeRGBMask(dest: TBGRACustomBitmap; x, y: integer;
|
|---|
| 276 | mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner;
|
|---|
| 277 | KeepRGBOrder: boolean);
|
|---|
| 278 | var
|
|---|
| 279 | minx,miny,maxx,maxy,countx,n,yb: integer;
|
|---|
| 280 | pdest,psrc: PBGRAPixel;
|
|---|
| 281 | begin
|
|---|
| 282 | if y >= dest.ClipRect.Top then miny := 0
|
|---|
| 283 | else miny := dest.ClipRect.Top-y;
|
|---|
| 284 | if y+mask.Height-1 < dest.ClipRect.Bottom then
|
|---|
| 285 | maxy := mask.Height-1 else
|
|---|
| 286 | maxy := dest.ClipRect.Bottom-1-y;
|
|---|
| 287 |
|
|---|
| 288 | if x >= dest.ClipRect.Left then minx := 0
|
|---|
| 289 | else minx := dest.ClipRect.Left-x;
|
|---|
| 290 | if x+mask.Width-1 < dest.ClipRect.Right then
|
|---|
| 291 | maxx := mask.Width-1 else
|
|---|
| 292 | maxx := dest.ClipRect.Right-1-x;
|
|---|
| 293 |
|
|---|
| 294 | countx := maxx-minx+1;
|
|---|
| 295 | if countx <= 0 then exit;
|
|---|
| 296 |
|
|---|
| 297 | for yb := miny to maxy do
|
|---|
| 298 | begin
|
|---|
| 299 | pdest := dest.ScanLine[y+yb]+(x+minx);
|
|---|
| 300 | psrc := mask.ScanLine[yb]+minx;
|
|---|
| 301 | if texture <> nil then
|
|---|
| 302 | texture.ScanMoveTo(x+minx, y+yb);
|
|---|
| 303 | if KeepRGBOrder then
|
|---|
| 304 | begin
|
|---|
| 305 | for n := countx-1 downto 0 do
|
|---|
| 306 | begin
|
|---|
| 307 | if texture <> nil then color := texture.ScanNextPixel;
|
|---|
| 308 | ClearTypeDrawPixel(pdest, psrc^.red, psrc^.green, psrc^.blue, color);
|
|---|
| 309 | inc(pdest);
|
|---|
| 310 | inc(psrc);
|
|---|
| 311 | end;
|
|---|
| 312 | end else
|
|---|
| 313 | begin
|
|---|
| 314 | for n := countx-1 downto 0 do
|
|---|
| 315 | begin
|
|---|
| 316 | if texture <> nil then color := texture.ScanNextPixel;
|
|---|
| 317 | ClearTypeDrawPixel(pdest, psrc^.blue, psrc^.green, psrc^.red, color);
|
|---|
| 318 | inc(pdest);
|
|---|
| 319 | inc(psrc);
|
|---|
| 320 | end;
|
|---|
| 321 | end;
|
|---|
| 322 | end;
|
|---|
| 323 | end;
|
|---|
| 324 |
|
|---|
| 325 | procedure ClearTypeDrawPixel(pdest: PBGRAPixel; Cr, Cg, Cb: byte; Color: TBGRAPixel);
|
|---|
| 326 | var merge,mergeClearType: TBGRAPixel;
|
|---|
| 327 | acc: word;
|
|---|
| 328 | keep,dont_keep: byte;
|
|---|
| 329 | begin
|
|---|
| 330 | Cr := ApplyOpacity(Cr,color.alpha);
|
|---|
| 331 | Cg := ApplyOpacity(Cg,color.alpha);
|
|---|
| 332 | Cb := ApplyOpacity(Cb,color.alpha);
|
|---|
| 333 | acc := Cr+Cg+Cb;
|
|---|
| 334 | if acc = 0 then exit;
|
|---|
| 335 |
|
|---|
| 336 | merge := pdest^;
|
|---|
| 337 | mergeClearType.red := GammaCompressionTab[(GammaExpansionTab[merge.red] * (not byte(Cr)) +
|
|---|
| 338 | GammaExpansionTab[color.red] * Cr + 128) div 255];
|
|---|
| 339 | mergeClearType.green := GammaCompressionTab[(GammaExpansionTab[merge.green] * (not byte(Cg)) +
|
|---|
| 340 | GammaExpansionTab[color.green] * Cg + 128) div 255];
|
|---|
| 341 | mergeClearType.blue := GammaCompressionTab[(GammaExpansionTab[merge.blue] * (not byte(Cb)) +
|
|---|
| 342 | GammaExpansionTab[color.blue] * Cb + 128) div 255];
|
|---|
| 343 | mergeClearType.alpha := merge.alpha;
|
|---|
| 344 |
|
|---|
| 345 | if (mergeClearType.alpha = 255) then
|
|---|
| 346 | pdest^:= mergeClearType
|
|---|
| 347 | else
|
|---|
| 348 | begin
|
|---|
| 349 | if Cg <> 0 then
|
|---|
| 350 | DrawPixelInlineWithAlphaCheck(@merge, color, Cg);
|
|---|
| 351 | dont_keep := mergeClearType.alpha;
|
|---|
| 352 | if dont_keep > 0 then
|
|---|
| 353 | begin
|
|---|
| 354 | keep := not dont_keep;
|
|---|
| 355 | merge.red := GammaCompressionTab[(GammaExpansionTab[merge.red] * keep + GammaExpansionTab[mergeClearType.red] * dont_keep) div 255];
|
|---|
| 356 | merge.green := GammaCompressionTab[(GammaExpansionTab[merge.green] * keep + GammaExpansionTab[mergeClearType.green] * dont_keep) div 255];
|
|---|
| 357 | merge.blue := GammaCompressionTab[(GammaExpansionTab[merge.blue] * keep + GammaExpansionTab[mergeClearType.blue] * dont_keep) div 255];
|
|---|
| 358 | merge.alpha := mergeClearType.alpha + ApplyOpacity(merge.alpha, not mergeClearType.alpha);
|
|---|
| 359 | end;
|
|---|
| 360 | pdest^ := merge;
|
|---|
| 361 | end;
|
|---|
| 362 | end;
|
|---|
| 363 |
|
|---|
| 364 | procedure InterpolateBilinear(pUpLeft, pUpRight, pDownLeft,
|
|---|
| 365 | pDownRight: PBGRAPixel; iFactX,iFactY: Integer; ADest: PBGRAPixel);
|
|---|
| 366 | var
|
|---|
| 367 | w1,w2,w3,w4,alphaW: cardinal;
|
|---|
| 368 | rSum, gSum, bSum: cardinal; //rgbDiv = aSum
|
|---|
| 369 | aSum, aDiv: cardinal;
|
|---|
| 370 | begin
|
|---|
| 371 | rSum := 0;
|
|---|
| 372 | gSum := 0;
|
|---|
| 373 | bSum := 0;
|
|---|
| 374 | aSum := 0;
|
|---|
| 375 | aDiv := 0;
|
|---|
| 376 |
|
|---|
| 377 | w4 := (iFactX*iFactY+127) shr 8;
|
|---|
| 378 | w3 := iFactY-w4;
|
|---|
| 379 | {$PUSH}{$HINTS OFF}
|
|---|
| 380 | w1 := (256-iFactX)-w3;
|
|---|
| 381 | {$POP}
|
|---|
| 382 | w2 := iFactX-w4;
|
|---|
| 383 |
|
|---|
| 384 | { For each pixel around the coordinate, compute
|
|---|
| 385 | the weight for it and multiply values by it before
|
|---|
| 386 | adding to the sum }
|
|---|
| 387 | if pUpLeft <> nil then
|
|---|
| 388 | with pUpLeft^ do
|
|---|
| 389 | begin
|
|---|
| 390 | alphaW := alpha * w1;
|
|---|
| 391 | aDiv += w1;
|
|---|
| 392 | aSum += alphaW;
|
|---|
| 393 | rSum += red * alphaW;
|
|---|
| 394 | gSum += green * alphaW;
|
|---|
| 395 | bSum += blue * alphaW;
|
|---|
| 396 | end;
|
|---|
| 397 | if pUpRight <> nil then
|
|---|
| 398 | with pUpRight^ do
|
|---|
| 399 | begin
|
|---|
| 400 | alphaW := alpha * w2;
|
|---|
| 401 | aDiv += w2;
|
|---|
| 402 | aSum += alphaW;
|
|---|
| 403 | rSum += red * alphaW;
|
|---|
| 404 | gSum += green * alphaW;
|
|---|
| 405 | bSum += blue * alphaW;
|
|---|
| 406 | end;
|
|---|
| 407 | if pDownLeft <> nil then
|
|---|
| 408 | with pDownLeft^ do
|
|---|
| 409 | begin
|
|---|
| 410 | alphaW := alpha * w3;
|
|---|
| 411 | aDiv += w3;
|
|---|
| 412 | aSum += alphaW;
|
|---|
| 413 | rSum += red * alphaW;
|
|---|
| 414 | gSum += green * alphaW;
|
|---|
| 415 | bSum += blue * alphaW;
|
|---|
| 416 | end;
|
|---|
| 417 | if pDownRight <> nil then
|
|---|
| 418 | with pDownRight^ do
|
|---|
| 419 | begin
|
|---|
| 420 | alphaW := alpha * w4;
|
|---|
| 421 | aDiv += w4;
|
|---|
| 422 | aSum += alphaW;
|
|---|
| 423 | rSum += red * alphaW;
|
|---|
| 424 | gSum += green * alphaW;
|
|---|
| 425 | bSum += blue * alphaW;
|
|---|
| 426 | end;
|
|---|
| 427 |
|
|---|
| 428 | if aSum < 128 then //if there is no alpha
|
|---|
| 429 | ADest^ := BGRAPixelTransparent
|
|---|
| 430 | else
|
|---|
| 431 | with ADest^ do
|
|---|
| 432 | begin
|
|---|
| 433 | red := (rSum + aSum shr 1) div aSum;
|
|---|
| 434 | green := (gSum + aSum shr 1) div aSum;
|
|---|
| 435 | blue := (bSum + aSum shr 1) div aSum;
|
|---|
| 436 | if aDiv = 256 then
|
|---|
| 437 | alpha := (aSum + 128) shr 8
|
|---|
| 438 | else
|
|---|
| 439 | alpha := (aSum + aDiv shr 1) div aDiv;
|
|---|
| 440 | end;
|
|---|
| 441 | end;
|
|---|
| 442 |
|
|---|
| 443 | procedure ScannerPutPixels(scan: IBGRAScanner; pdest: PBGRAPixel; count: integer; mode: TDrawMode);
|
|---|
| 444 | var c : TBGRAPixel;
|
|---|
| 445 | i: Integer;
|
|---|
| 446 | scanNextFunc: function(): TBGRAPixel of object;
|
|---|
| 447 | begin
|
|---|
| 448 | if scan.IsScanPutPixelsDefined then
|
|---|
| 449 | scan.ScanPutPixels(pdest,count,mode) else
|
|---|
| 450 | begin
|
|---|
| 451 | scanNextFunc := @scan.ScanNextPixel;
|
|---|
| 452 | case mode of
|
|---|
| 453 | dmLinearBlend:
|
|---|
| 454 | for i := 0 to count-1 do
|
|---|
| 455 | begin
|
|---|
| 456 | FastBlendPixelInline(pdest, scanNextFunc());
|
|---|
| 457 | inc(pdest);
|
|---|
| 458 | end;
|
|---|
| 459 | dmDrawWithTransparency:
|
|---|
| 460 | for i := 0 to count-1 do
|
|---|
| 461 | begin
|
|---|
| 462 | DrawPixelInlineWithAlphaCheck(pdest, scanNextFunc());
|
|---|
| 463 | inc(pdest);
|
|---|
| 464 | end;
|
|---|
| 465 | dmSet:
|
|---|
| 466 | for i := 0 to count-1 do
|
|---|
| 467 | begin
|
|---|
| 468 | pdest^ := scanNextFunc();
|
|---|
| 469 | inc(pdest);
|
|---|
| 470 | end;
|
|---|
| 471 | dmXor:
|
|---|
| 472 | for i := 0 to count-1 do
|
|---|
| 473 | begin
|
|---|
| 474 | PDWord(pdest)^ := PDWord(pdest)^ xor DWord(scanNextFunc());
|
|---|
| 475 | inc(pdest);
|
|---|
| 476 | end;
|
|---|
| 477 | dmSetExceptTransparent:
|
|---|
| 478 | for i := 0 to count-1 do
|
|---|
| 479 | begin
|
|---|
| 480 | c := scanNextFunc();
|
|---|
| 481 | if c.alpha = 255 then pdest^ := c;
|
|---|
| 482 | inc(pdest);
|
|---|
| 483 | end;
|
|---|
| 484 | end;
|
|---|
| 485 | end;
|
|---|
| 486 | end;
|
|---|
| 487 |
|
|---|
| 488 | procedure XorInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
|
|---|
| 489 | begin
|
|---|
| 490 | while Count > 0 do
|
|---|
| 491 | begin
|
|---|
| 492 | PDWord(dest)^ := PDWord(dest)^ xor DWord(c);
|
|---|
| 493 | Inc(dest);
|
|---|
| 494 | Dec(Count);
|
|---|
| 495 | end;
|
|---|
| 496 | end;
|
|---|
| 497 |
|
|---|
| 498 | procedure XorPixels(pdest, psrc: PBGRAPixel; count: integer);
|
|---|
| 499 | begin
|
|---|
| 500 | while Count > 0 do
|
|---|
| 501 | begin
|
|---|
| 502 | PDWord(pdest)^ := PDWord(psrc)^ xor PDWord(pdest)^;
|
|---|
| 503 | Inc(pdest);
|
|---|
| 504 | Inc(psrc);
|
|---|
| 505 | Dec(Count);
|
|---|
| 506 | end;
|
|---|
| 507 | end;
|
|---|
| 508 |
|
|---|
| 509 | {$i blendpixels.inc}
|
|---|
| 510 |
|
|---|
| 511 | procedure AlphaFillInline(dest: PBGRAPixel; alpha: byte; Count: integer); inline;
|
|---|
| 512 | begin
|
|---|
| 513 | while Count > 0 do
|
|---|
| 514 | begin
|
|---|
| 515 | dest^.alpha := alpha;
|
|---|
| 516 | Inc(dest);
|
|---|
| 517 | Dec(Count);
|
|---|
| 518 | end;
|
|---|
| 519 | end;
|
|---|
| 520 |
|
|---|
| 521 | procedure FillInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
|
|---|
| 522 | begin
|
|---|
| 523 | FillDWord(dest^, Count, DWord(c));
|
|---|
| 524 | end;
|
|---|
| 525 |
|
|---|
| 526 | procedure FastBlendPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
|
|---|
| 527 | var
|
|---|
| 528 | n: integer;
|
|---|
| 529 | begin
|
|---|
| 530 | if c.alpha = 0 then exit;
|
|---|
| 531 | for n := Count - 1 downto 0 do
|
|---|
| 532 | begin
|
|---|
| 533 | FastBlendPixelInline(dest, c);
|
|---|
| 534 | Inc(dest);
|
|---|
| 535 | end;
|
|---|
| 536 | end;
|
|---|
| 537 |
|
|---|
| 538 | procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer;
|
|---|
| 539 | mode: TDrawMode; AOpacity: byte);
|
|---|
| 540 | var i: integer; tempPixel: TBGRAPixel;
|
|---|
| 541 | begin
|
|---|
| 542 | case mode of
|
|---|
| 543 | dmSet:
|
|---|
| 544 | begin
|
|---|
| 545 | if AOpacity <> 255 then
|
|---|
| 546 | CopyPixelsWithOpacity(pdest, psource, AOpacity, copycount)
|
|---|
| 547 | else
|
|---|
| 548 | begin
|
|---|
| 549 | copycount *= sizeof(TBGRAPixel);
|
|---|
| 550 | move(psource^, pdest^, copycount);
|
|---|
| 551 | end;
|
|---|
| 552 | end;
|
|---|
| 553 | dmSetExceptTransparent:
|
|---|
| 554 | begin
|
|---|
| 555 | if AOpacity <> 255 then
|
|---|
| 556 | begin
|
|---|
| 557 | for i := copycount - 1 downto 0 do
|
|---|
| 558 | begin
|
|---|
| 559 | if psource^.alpha = 255 then
|
|---|
| 560 | begin
|
|---|
| 561 | tempPixel := psource^;
|
|---|
| 562 | tempPixel.alpha := ApplyOpacity(tempPixel.alpha,AOpacity);
|
|---|
| 563 | FastBlendPixelInline(pdest,tempPixel);
|
|---|
| 564 | end;
|
|---|
| 565 | Inc(pdest);
|
|---|
| 566 | Inc(psource);
|
|---|
| 567 | end;
|
|---|
| 568 | end else
|
|---|
| 569 | for i := copycount - 1 downto 0 do
|
|---|
| 570 | begin
|
|---|
| 571 | if psource^.alpha = 255 then
|
|---|
| 572 | pdest^ := psource^;
|
|---|
| 573 | Inc(pdest);
|
|---|
| 574 | Inc(psource);
|
|---|
| 575 | end;
|
|---|
| 576 | end;
|
|---|
| 577 | dmDrawWithTransparency:
|
|---|
| 578 | begin
|
|---|
| 579 | if AOpacity <> 255 then
|
|---|
| 580 | begin
|
|---|
| 581 | for i := copycount - 1 downto 0 do
|
|---|
| 582 | begin
|
|---|
| 583 | DrawPixelInlineWithAlphaCheck(pdest, psource^, AOpacity);
|
|---|
| 584 | Inc(pdest);
|
|---|
| 585 | Inc(psource);
|
|---|
| 586 | end;
|
|---|
| 587 | end
|
|---|
| 588 | else
|
|---|
| 589 | for i := copycount - 1 downto 0 do
|
|---|
| 590 | begin
|
|---|
| 591 | DrawPixelInlineWithAlphaCheck(pdest, psource^);
|
|---|
| 592 | Inc(pdest);
|
|---|
| 593 | Inc(psource);
|
|---|
| 594 | end;
|
|---|
| 595 | end;
|
|---|
| 596 | dmFastBlend:
|
|---|
| 597 | begin
|
|---|
| 598 | if AOpacity <> 255 then
|
|---|
| 599 | begin
|
|---|
| 600 | for i := copycount - 1 downto 0 do
|
|---|
| 601 | begin
|
|---|
| 602 | FastBlendPixelInline(pdest, psource^, AOpacity);
|
|---|
| 603 | Inc(pdest);
|
|---|
| 604 | Inc(psource);
|
|---|
| 605 | end;
|
|---|
| 606 | end else
|
|---|
| 607 | for i := copycount - 1 downto 0 do
|
|---|
| 608 | begin
|
|---|
| 609 | FastBlendPixelInline(pdest, psource^);
|
|---|
| 610 | Inc(pdest);
|
|---|
| 611 | Inc(psource);
|
|---|
| 612 | end;
|
|---|
| 613 | end;
|
|---|
| 614 | dmXor:
|
|---|
| 615 | begin
|
|---|
| 616 | if AOpacity <> 255 then
|
|---|
| 617 | begin
|
|---|
| 618 | for i := copycount - 1 downto 0 do
|
|---|
| 619 | begin
|
|---|
| 620 | FastBlendPixelInline(pdest, TBGRAPixel(PDWord(pdest)^ xor PDword(psource)^), AOpacity);
|
|---|
| 621 | Inc(pdest);
|
|---|
| 622 | Inc(psource);
|
|---|
| 623 | end;
|
|---|
| 624 | end else
|
|---|
| 625 | XorPixels(pdest, psource, copycount);
|
|---|
| 626 | end;
|
|---|
| 627 | end;
|
|---|
| 628 | end;
|
|---|
| 629 |
|
|---|
| 630 | procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
|
|---|
| 631 | var
|
|---|
| 632 | n: integer;
|
|---|
| 633 | ec: TExpandedPixel;
|
|---|
| 634 | begin
|
|---|
| 635 | if c.alpha = 0 then exit;
|
|---|
| 636 | if c.alpha = 255 then
|
|---|
| 637 | begin
|
|---|
| 638 | filldword(dest^,count,longword(c));
|
|---|
| 639 | exit;
|
|---|
| 640 | end;
|
|---|
| 641 | ec := GammaExpansion(c);
|
|---|
| 642 | for n := Count - 1 downto 0 do
|
|---|
| 643 | begin
|
|---|
| 644 | DrawExpandedPixelInlineNoAlphaCheck(dest, ec,c.alpha);
|
|---|
| 645 | Inc(dest);
|
|---|
| 646 | end;
|
|---|
| 647 | end;
|
|---|
| 648 |
|
|---|
| 649 | procedure DrawExpandedPixelsInline(dest: PBGRAPixel; ec: TExpandedPixel;
|
|---|
| 650 | Count: integer);
|
|---|
| 651 | var
|
|---|
| 652 | n: integer;
|
|---|
| 653 | c: TBGRAPixel;
|
|---|
| 654 | begin
|
|---|
| 655 | if ec.alpha < $0100 then exit;
|
|---|
| 656 | if ec.alpha >= $FF00 then
|
|---|
| 657 | begin
|
|---|
| 658 | c := GammaCompression(ec);
|
|---|
| 659 | filldword(dest^,count,longword(c));
|
|---|
| 660 | exit;
|
|---|
| 661 | end;
|
|---|
| 662 | for n := Count - 1 downto 0 do
|
|---|
| 663 | begin
|
|---|
| 664 | DrawExpandedPixelInlineNoAlphaCheck(dest, ec, ec.alpha shr 8);
|
|---|
| 665 | Inc(dest);
|
|---|
| 666 | end;
|
|---|
| 667 | end;
|
|---|
| 668 |
|
|---|
| 669 | procedure DrawPixelsInlineExpandedOrNot(dest: PBGRAPixel; ec: TExpandedPixel; c: TBGRAPixel; Count: integer);
|
|---|
| 670 | var
|
|---|
| 671 | n: integer;
|
|---|
| 672 | begin
|
|---|
| 673 | if c.alpha = 0 then exit;
|
|---|
| 674 | if c.alpha = 255 then
|
|---|
| 675 | begin
|
|---|
| 676 | filldword(dest^,count,longword(c));
|
|---|
| 677 | exit;
|
|---|
| 678 | end;
|
|---|
| 679 | for n := Count - 1 downto 0 do
|
|---|
| 680 | begin
|
|---|
| 681 | DrawExpandedPixelInlineNoAlphaCheck(dest, ec, c.alpha);
|
|---|
| 682 | Inc(dest);
|
|---|
| 683 | end;
|
|---|
| 684 | end;
|
|---|
| 685 |
|
|---|
| 686 | procedure DrawPixelsInlineDiff(dest: PBGRAPixel; c: TBGRAPixel;
|
|---|
| 687 | Count: integer; compare: TBGRAPixel; maxDiff: byte); inline;
|
|---|
| 688 | var
|
|---|
| 689 | n: integer;
|
|---|
| 690 | begin
|
|---|
| 691 | for n := Count - 1 downto 0 do
|
|---|
| 692 | begin
|
|---|
| 693 | DrawPixelInlineDiff(dest, c, compare, maxDiff);
|
|---|
| 694 | Inc(dest);
|
|---|
| 695 | end;
|
|---|
| 696 | end;
|
|---|
| 697 |
|
|---|
| 698 | procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel);
|
|---|
| 699 | begin
|
|---|
| 700 | case c.alpha of
|
|---|
| 701 | 0: ;
|
|---|
| 702 | 255: dest^ := c;
|
|---|
| 703 | else
|
|---|
| 704 | DrawPixelInlineNoAlphaCheck(dest,c);
|
|---|
| 705 | end;
|
|---|
| 706 | end;
|
|---|
| 707 |
|
|---|
| 708 | procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte);
|
|---|
| 709 | begin
|
|---|
| 710 | c.alpha := ApplyOpacity(c.alpha,appliedOpacity);
|
|---|
| 711 | DrawPixelInlineWithAlphaCheck(dest, c);
|
|---|
| 712 | end;
|
|---|
| 713 |
|
|---|
| 714 | procedure CopyPixelsWithOpacity(dest, src: PBGRAPixel; opacity: byte;
|
|---|
| 715 | Count: integer);
|
|---|
| 716 | begin
|
|---|
| 717 | while count > 0 do
|
|---|
| 718 | begin
|
|---|
| 719 | dest^ := MergeBGRAWithGammaCorrection(src^,opacity,dest^,not opacity);
|
|---|
| 720 | inc(src);
|
|---|
| 721 | inc(dest);
|
|---|
| 722 | dec(count);
|
|---|
| 723 | end;
|
|---|
| 724 | end;
|
|---|
| 725 |
|
|---|
| 726 | function ApplyOpacity(opacity1, opacity2: byte): byte;
|
|---|
| 727 | begin
|
|---|
| 728 | result := opacity1*(opacity2+1) shr 8;
|
|---|
| 729 | end;
|
|---|
| 730 |
|
|---|
| 731 | function FastRoundDiv255(value: cardinal): cardinal; inline;
|
|---|
| 732 | begin
|
|---|
| 733 | result := (value + (value shr 7)) shr 8;
|
|---|
| 734 | end;
|
|---|
| 735 |
|
|---|
| 736 | procedure DrawExpandedPixelInlineWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel);
|
|---|
| 737 | var
|
|---|
| 738 | calpha: byte;
|
|---|
| 739 | begin
|
|---|
| 740 | calpha := ec.alpha shr 8;
|
|---|
| 741 | case calpha of
|
|---|
| 742 | 0: ;
|
|---|
| 743 | 255: dest^ := GammaCompression(ec);
|
|---|
| 744 | else
|
|---|
| 745 | DrawExpandedPixelInlineNoAlphaCheck(dest,ec,calpha);
|
|---|
| 746 | end;
|
|---|
| 747 | end;
|
|---|
| 748 |
|
|---|
| 749 | procedure DrawPixelInlineExpandedOrNotWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; c: TBGRAPixel);
|
|---|
| 750 | begin
|
|---|
| 751 | case c.alpha of
|
|---|
| 752 | 0: ;
|
|---|
| 753 | 255: dest^ := c;
|
|---|
| 754 | else
|
|---|
| 755 | DrawExpandedPixelInlineNoAlphaCheck(dest,ec,c.alpha);
|
|---|
| 756 | end;
|
|---|
| 757 | end;
|
|---|
| 758 |
|
|---|
| 759 | procedure DrawPixelInlineNoAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel);
|
|---|
| 760 | var
|
|---|
| 761 | a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
|
|---|
| 762 | begin
|
|---|
| 763 | case dest^.alpha of
|
|---|
| 764 | 0: dest^ := c;
|
|---|
| 765 | 255:
|
|---|
| 766 | begin
|
|---|
| 767 | alphaCorr := c.alpha;
|
|---|
| 768 | if alphaCorr >= 128 then alphaCorr += 1;
|
|---|
| 769 | dest^.red := GammaCompressionTab[(GammaExpansionTab[dest^.red] * NativeUInt(256-alphaCorr) + GammaExpansionTab[c.red]*alphaCorr) shr 8];
|
|---|
| 770 | dest^.green := GammaCompressionTab[(GammaExpansionTab[dest^.green] * NativeUInt(256-alphaCorr) + GammaExpansionTab[c.green]*alphaCorr) shr 8];
|
|---|
| 771 | dest^.blue := GammaCompressionTab[(GammaExpansionTab[dest^.blue] * NativeUInt(256-alphaCorr) + GammaExpansionTab[c.blue]*alphaCorr) shr 8];
|
|---|
| 772 | end;
|
|---|
| 773 | else
|
|---|
| 774 | begin
|
|---|
| 775 | {$HINTS OFF}
|
|---|
| 776 | a12 := 65025 - (not dest^.alpha) * (not c.alpha);
|
|---|
| 777 | {$HINTS ON}
|
|---|
| 778 | a12m := a12 shr 1;
|
|---|
| 779 |
|
|---|
| 780 | a1f := dest^.alpha * (not c.alpha);
|
|---|
| 781 | a2f := (c.alpha shl 8) - c.alpha;
|
|---|
| 782 |
|
|---|
| 783 | PDWord(dest)^ := ((GammaCompressionTab[(GammaExpansionTab[dest^.red] * a1f +
|
|---|
| 784 | GammaExpansionTab[c.red] * a2f + a12m) div a12]) shl TBGRAPixel_RedShift) or
|
|---|
| 785 | ((GammaCompressionTab[(GammaExpansionTab[dest^.green] * a1f +
|
|---|
| 786 | GammaExpansionTab[c.green] * a2f + a12m) div a12]) shl TBGRAPixel_GreenShift) or
|
|---|
| 787 | ((GammaCompressionTab[(GammaExpansionTab[dest^.blue] * a1f +
|
|---|
| 788 | GammaExpansionTab[c.blue] * a2f + a12m) div a12]) shl TBGRAPixel_BlueShift) or
|
|---|
| 789 | (((a12 + a12 shr 7) shr 8) shl TBGRAPixel_AlphaShift);
|
|---|
| 790 | end;
|
|---|
| 791 | end;
|
|---|
| 792 | end;
|
|---|
| 793 |
|
|---|
| 794 | procedure DrawExpandedPixelInlineNoAlphaCheck(dest: PBGRAPixel;
|
|---|
| 795 | const ec: TExpandedPixel; calpha: byte);
|
|---|
| 796 | var
|
|---|
| 797 | a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
|
|---|
| 798 | begin
|
|---|
| 799 | case dest^.alpha of
|
|---|
| 800 | 0: begin
|
|---|
| 801 | dest^.red := GammaCompressionTab[ec.red];
|
|---|
| 802 | dest^.green := GammaCompressionTab[ec.green];
|
|---|
| 803 | dest^.blue := GammaCompressionTab[ec.blue];
|
|---|
| 804 | dest^.alpha := calpha;
|
|---|
| 805 | end;
|
|---|
| 806 | 255:
|
|---|
| 807 | begin
|
|---|
| 808 | alphaCorr := calpha;
|
|---|
| 809 | if alphaCorr >= 128 then alphaCorr += 1;
|
|---|
| 810 | dest^.red := GammaCompressionTab[(GammaExpansionTab[dest^.red] * NativeUInt(256-alphaCorr) + ec.red*alphaCorr) shr 8];
|
|---|
| 811 | dest^.green := GammaCompressionTab[(GammaExpansionTab[dest^.green] * NativeUInt(256-alphaCorr) + ec.green*alphaCorr) shr 8];
|
|---|
| 812 | dest^.blue := GammaCompressionTab[(GammaExpansionTab[dest^.blue] * NativeUInt(256-alphaCorr) + ec.blue*alphaCorr) shr 8];
|
|---|
| 813 | end;
|
|---|
| 814 | else
|
|---|
| 815 | begin
|
|---|
| 816 | {$HINTS OFF}
|
|---|
| 817 | a12 := 65025 - (not dest^.alpha) * (not calpha);
|
|---|
| 818 | {$HINTS ON}
|
|---|
| 819 | a12m := a12 shr 1;
|
|---|
| 820 |
|
|---|
| 821 | a1f := dest^.alpha * (not calpha);
|
|---|
| 822 | a2f := (calpha shl 8) - calpha;
|
|---|
| 823 |
|
|---|
| 824 | PDWord(dest)^ := ((GammaCompressionTab[(GammaExpansionTab[dest^.red] * a1f +
|
|---|
| 825 | ec.red * a2f + a12m) div a12]) shl TBGRAPixel_RedShift) or
|
|---|
| 826 | ((GammaCompressionTab[(GammaExpansionTab[dest^.green] * a1f +
|
|---|
| 827 | ec.green * a2f + a12m) div a12]) shl TBGRAPixel_GreenShift) or
|
|---|
| 828 | ((GammaCompressionTab[(GammaExpansionTab[dest^.blue] * a1f +
|
|---|
| 829 | ec.blue * a2f + a12m) div a12]) shl TBGRAPixel_BlueShift) or
|
|---|
| 830 | (((a12 + a12 shr 7) shr 8) shl TBGRAPixel_AlphaShift);
|
|---|
| 831 | end;
|
|---|
| 832 | end;
|
|---|
| 833 | end;
|
|---|
| 834 |
|
|---|
| 835 | procedure FastBlendPixelInline(dest: PBGRAPixel; const c: TBGRAPixel);
|
|---|
| 836 | var
|
|---|
| 837 | a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
|
|---|
| 838 | begin
|
|---|
| 839 | case c.alpha of
|
|---|
| 840 | 0: ;
|
|---|
| 841 | 255: dest^ := c;
|
|---|
| 842 | else
|
|---|
| 843 | begin
|
|---|
| 844 | case dest^.alpha of
|
|---|
| 845 | 0: dest^ := c;
|
|---|
| 846 | 255:
|
|---|
| 847 | begin
|
|---|
| 848 | alphaCorr := c.alpha;
|
|---|
| 849 | if alphaCorr >= 128 then alphaCorr += 1;
|
|---|
| 850 | dest^.red := (dest^.red * NativeUInt(256-alphaCorr) + c.red*(alphaCorr+1)) shr 8;
|
|---|
| 851 | dest^.green := (dest^.green * NativeUInt(256-alphaCorr) + c.green*(alphaCorr+1)) shr 8;
|
|---|
| 852 | dest^.blue := (dest^.blue * NativeUInt(256-alphaCorr) + c.blue*(alphaCorr+1)) shr 8;
|
|---|
| 853 | end;
|
|---|
| 854 | else
|
|---|
| 855 | begin
|
|---|
| 856 | {$HINTS OFF}
|
|---|
| 857 | a12 := 65025 - (not dest^.alpha) * (not c.alpha);
|
|---|
| 858 | {$HINTS ON}
|
|---|
| 859 | a12m := a12 shr 1;
|
|---|
| 860 |
|
|---|
| 861 | a1f := dest^.alpha * (not c.alpha);
|
|---|
| 862 | a2f := (c.alpha shl 8) - c.alpha;
|
|---|
| 863 |
|
|---|
| 864 | PDWord(dest)^ := (((dest^.red * a1f + c.red * a2f + a12m) div a12) shl TBGRAPixel_RedShift) or
|
|---|
| 865 | (((dest^.green * a1f + c.green * a2f + a12m) div a12) shl TBGRAPixel_GreenShift) or
|
|---|
| 866 | (((dest^.blue * a1f + c.blue * a2f + a12m) div a12) shl TBGRAPixel_BlueShift) or
|
|---|
| 867 | (((a12 + a12 shr 7) shr 8) shl TBGRAPixel_AlphaShift);
|
|---|
| 868 | end;
|
|---|
| 869 | end;
|
|---|
| 870 | end;
|
|---|
| 871 | end;
|
|---|
| 872 | end;
|
|---|
| 873 |
|
|---|
| 874 | procedure FastBlendPixelInline(dest: PBGRAPixel; c: TBGRAPixel;
|
|---|
| 875 | appliedOpacity: byte);
|
|---|
| 876 | begin
|
|---|
| 877 | c.alpha := ApplyOpacity(c.alpha,appliedOpacity);
|
|---|
| 878 | FastBlendPixelInline(dest,c);
|
|---|
| 879 | end;
|
|---|
| 880 |
|
|---|
| 881 | procedure DrawPixelInlineDiff(dest: PBGRAPixel; c, compare: TBGRAPixel;
|
|---|
| 882 | maxDiff: byte); inline;
|
|---|
| 883 | var alpha: NativeInt;
|
|---|
| 884 | begin
|
|---|
| 885 | alpha := (c.alpha * (maxDiff + 1 - BGRADiff(dest^, compare)) + (maxDiff + 1) shr 1) div
|
|---|
| 886 | (maxDiff + 1);
|
|---|
| 887 | if alpha > 0 then
|
|---|
| 888 | DrawPixelInlineWithAlphaCheck(dest, BGRA(c.red, c.green, c.blue, alpha));
|
|---|
| 889 | end;
|
|---|
| 890 |
|
|---|
| 891 | procedure ErasePixelInline(dest: PBGRAPixel; alpha: byte); inline;
|
|---|
| 892 | var
|
|---|
| 893 | newAlpha: byte;
|
|---|
| 894 | begin
|
|---|
| 895 | newAlpha := ApplyOpacity(dest^.alpha, not alpha);
|
|---|
| 896 | if newAlpha = 0 then
|
|---|
| 897 | dest^ := BGRAPixelTransparent
|
|---|
| 898 | else
|
|---|
| 899 | dest^.alpha := newAlpha;
|
|---|
| 900 | end;
|
|---|
| 901 |
|
|---|
| 902 | {$i blendpixelsover.inc}
|
|---|
| 903 |
|
|---|
| 904 | {$i blendpixelinline.inc}
|
|---|
| 905 |
|
|---|
| 906 | end.
|
|---|
| 907 |
|
|---|