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