source: trunk/Packages/bgrabitmap/bgrablend.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 28.1 KB
Line 
1unit 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
9interface
10
11uses
12 BGRABitmapTypes;
13
14{ Draw one pixel with alpha blending }
15procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
16procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte); inline; overload;
17procedure DrawExpandedPixelInlineWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel); inline; overload;
18procedure DrawPixelInlineExpandedOrNotWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; c: TBGRAPixel); inline; overload; //alpha in 'c' parameter
19procedure DrawPixelInlineNoAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
20procedure DrawExpandedPixelInlineNoAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; calpha: byte); inline; overload;
21procedure ClearTypeDrawPixel(pdest: PBGRAPixel; Cr, Cg, Cb: byte; Color: TBGRAPixel); inline;
22procedure InterpolateBilinear(pUpLeft,pUpRight,pDownLeft,pDownRight: PBGRAPixel;
23 iFactX,iFactY: Integer; ADest: PBGRAPixel);
24
25procedure CopyPixelsWithOpacity(dest,src: PBGRAPixel; opacity: byte; Count: integer); inline;
26function ApplyOpacity(opacity1,opacity2: byte): byte; inline;
27function FastRoundDiv255(value: cardinal): cardinal; inline;
28
29{ Draw a series of pixels with alpha blending }
30procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer; mode: TDrawMode; AOpacity:byte);
31procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline; overload;
32procedure DrawExpandedPixelsInline(dest: PBGRAPixel; ec: TExpandedPixel; Count: integer); inline; overload;
33procedure DrawPixelsInlineExpandedOrNot(dest: PBGRAPixel; ec: TExpandedPixel; c: TBGRAPixel; Count: integer); inline; overload; //alpha in 'c' parameter
34
35{ Draw one pixel with linear alpha blending }
36procedure FastBlendPixelInline(dest: PBGRAPixel; const c: TBGRAPixel); inline; overload;
37procedure FastBlendPixelInline(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte); inline; overload;
38
39{ Draw a series of pixels with linear alpha blending }
40procedure FastBlendPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
41
42{ Replace a series of pixels }
43procedure FillInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
44
45{ Xor a series of pixels }
46procedure XorInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
47procedure XorPixels(pdest, psrc: PBGRAPixel; count: integer);
48
49{ Set alpha value for a series of pixels }
50procedure AlphaFillInline(dest: PBGRAPixel; alpha: byte; Count: integer); inline;
51
52{ Erase a series of pixels, i.e. decrease alpha value }
53procedure 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 }
57procedure 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 }
60procedure DrawPixelsInlineDiff(dest: PBGRAPixel; c: TBGRAPixel;
61 Count: integer; compare: TBGRAPixel; maxDiff: byte); inline;
62
63{ Blend pixels with scanner content }
64procedure ScannerPutPixels(scan: IBGRAScanner; pdest: PBGRAPixel; count: integer; mode: TDrawMode);
65
66{ Perform advanced blending operation }
67procedure BlendPixels(pdest: PBGRAPixel; psrc: PBGRAPixel;
68 blendOp: TBlendOperation; Count: integer);
69
70{ Perform blending operation and merge over destination }
71procedure 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
78procedure LinearMultiplyPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
79procedure AddPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
80procedure LinearAddPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
81procedure ColorBurnPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
82procedure ColorDodgePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
83procedure DividePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
84procedure ReflectPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
85procedure NonLinearReflectPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
86procedure GlowPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
87procedure NiceGlowPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
88procedure OverlayPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
89procedure LinearOverlayPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
90procedure DifferencePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
91procedure LinearDifferencePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
92procedure ExclusionPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
93procedure LinearExclusionPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
94procedure LinearSubtractPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
95procedure LinearSubtractInversePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
96procedure SubtractPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
97procedure SubtractInversePixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
98procedure NegationPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
99procedure LinearNegationPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
100procedure LightenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
101procedure DarkenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
102procedure ScreenPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
103procedure SoftLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
104procedure SvgSoftLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
105procedure HardLightPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
106procedure BlendXorPixelInline(dest: PBGRAPixel; c: TBGRAPixel); inline;
107procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
108procedure BGRAFillClearTypeRGBMask(dest: TBGRACustomBitmap; x, y: integer;
109 mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner;
110 KeepRGBOrder: boolean);
111procedure BGRAFillClearTypeMaskPtr(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; maskData: PByte; maskPixelSize: NativeInt; maskRowSize: NativeInt; maskWidth,maskHeight: integer; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
112
113implementation
114
115procedure BGRAFillClearTypeMaskPtr(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; maskData: PByte; maskPixelSize: NativeInt; maskRowSize: NativeInt; maskWidth,maskHeight: integer; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
116var
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
149var
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
171begin
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;
264end;
265
266procedure BGRAFillClearTypeMask(dest: TBGRACustomBitmap; x,y: integer; xThird: integer; mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner; RGBOrder: boolean);
267var delta: NativeInt;
268begin
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);
273end;
274
275procedure BGRAFillClearTypeRGBMask(dest: TBGRACustomBitmap; x, y: integer;
276 mask: TBGRACustomBitmap; color: TBGRAPixel; texture: IBGRAScanner;
277 KeepRGBOrder: boolean);
278var
279 minx,miny,maxx,maxy,countx,n,yb: integer;
280 pdest,psrc: PBGRAPixel;
281begin
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;
323end;
324
325procedure ClearTypeDrawPixel(pdest: PBGRAPixel; Cr, Cg, Cb: byte; Color: TBGRAPixel);
326var merge,mergeClearType: TBGRAPixel;
327 acc: word;
328 keep,dont_keep: byte;
329begin
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;
362end;
363
364procedure InterpolateBilinear(pUpLeft, pUpRight, pDownLeft,
365 pDownRight: PBGRAPixel; iFactX,iFactY: Integer; ADest: PBGRAPixel);
366var
367 w1,w2,w3,w4,alphaW: cardinal;
368 rSum, gSum, bSum: cardinal; //rgbDiv = aSum
369 aSum, aDiv: cardinal;
370begin
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;
441end;
442
443procedure ScannerPutPixels(scan: IBGRAScanner; pdest: PBGRAPixel; count: integer; mode: TDrawMode);
444var c : TBGRAPixel;
445 i: Integer;
446 scanNextFunc: function(): TBGRAPixel of object;
447begin
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;
486end;
487
488procedure XorInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
489begin
490 while Count > 0 do
491 begin
492 PDWord(dest)^ := PDWord(dest)^ xor DWord(c);
493 Inc(dest);
494 Dec(Count);
495 end;
496end;
497
498procedure XorPixels(pdest, psrc: PBGRAPixel; count: integer);
499begin
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;
507end;
508
509{$i blendpixels.inc}
510
511procedure AlphaFillInline(dest: PBGRAPixel; alpha: byte; Count: integer); inline;
512begin
513 while Count > 0 do
514 begin
515 dest^.alpha := alpha;
516 Inc(dest);
517 Dec(Count);
518 end;
519end;
520
521procedure FillInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer); inline;
522begin
523 FillDWord(dest^, Count, DWord(c));
524end;
525
526procedure FastBlendPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
527var
528 n: integer;
529begin
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;
536end;
537
538procedure PutPixels(pdest: PBGRAPixel; psource: PBGRAPixel; copycount: integer;
539 mode: TDrawMode; AOpacity: byte);
540var i: integer; tempPixel: TBGRAPixel;
541begin
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;
628end;
629
630procedure DrawPixelsInline(dest: PBGRAPixel; c: TBGRAPixel; Count: integer);
631var
632 n: integer;
633 ec: TExpandedPixel;
634begin
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;
647end;
648
649procedure DrawExpandedPixelsInline(dest: PBGRAPixel; ec: TExpandedPixel;
650 Count: integer);
651var
652 n: integer;
653 c: TBGRAPixel;
654begin
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;
667end;
668
669procedure DrawPixelsInlineExpandedOrNot(dest: PBGRAPixel; ec: TExpandedPixel; c: TBGRAPixel; Count: integer);
670var
671 n: integer;
672begin
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;
684end;
685
686procedure DrawPixelsInlineDiff(dest: PBGRAPixel; c: TBGRAPixel;
687 Count: integer; compare: TBGRAPixel; maxDiff: byte); inline;
688var
689 n: integer;
690begin
691 for n := Count - 1 downto 0 do
692 begin
693 DrawPixelInlineDiff(dest, c, compare, maxDiff);
694 Inc(dest);
695 end;
696end;
697
698procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel);
699begin
700 case c.alpha of
701 0: ;
702 255: dest^ := c;
703 else
704 DrawPixelInlineNoAlphaCheck(dest,c);
705 end;
706end;
707
708procedure DrawPixelInlineWithAlphaCheck(dest: PBGRAPixel; c: TBGRAPixel; appliedOpacity: byte);
709begin
710 c.alpha := ApplyOpacity(c.alpha,appliedOpacity);
711 DrawPixelInlineWithAlphaCheck(dest, c);
712end;
713
714procedure CopyPixelsWithOpacity(dest, src: PBGRAPixel; opacity: byte;
715 Count: integer);
716begin
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;
724end;
725
726function ApplyOpacity(opacity1, opacity2: byte): byte;
727begin
728 result := opacity1*(opacity2+1) shr 8;
729end;
730
731function FastRoundDiv255(value: cardinal): cardinal; inline;
732begin
733 result := (value + (value shr 7)) shr 8;
734end;
735
736procedure DrawExpandedPixelInlineWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel);
737var
738 calpha: byte;
739begin
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;
747end;
748
749procedure DrawPixelInlineExpandedOrNotWithAlphaCheck(dest: PBGRAPixel; const ec: TExpandedPixel; c: TBGRAPixel);
750begin
751 case c.alpha of
752 0: ;
753 255: dest^ := c;
754 else
755 DrawExpandedPixelInlineNoAlphaCheck(dest,ec,c.alpha);
756 end;
757end;
758
759procedure DrawPixelInlineNoAlphaCheck(dest: PBGRAPixel; const c: TBGRAPixel);
760var
761 a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
762begin
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;
792end;
793
794procedure DrawExpandedPixelInlineNoAlphaCheck(dest: PBGRAPixel;
795 const ec: TExpandedPixel; calpha: byte);
796var
797 a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
798begin
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;
833end;
834
835procedure FastBlendPixelInline(dest: PBGRAPixel; const c: TBGRAPixel);
836var
837 a1f, a2f, a12, a12m, alphaCorr: NativeUInt;
838begin
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;
872end;
873
874procedure FastBlendPixelInline(dest: PBGRAPixel; c: TBGRAPixel;
875 appliedOpacity: byte);
876begin
877 c.alpha := ApplyOpacity(c.alpha,appliedOpacity);
878 FastBlendPixelInline(dest,c);
879end;
880
881procedure DrawPixelInlineDiff(dest: PBGRAPixel; c, compare: TBGRAPixel;
882 maxDiff: byte); inline;
883var alpha: NativeInt;
884begin
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));
889end;
890
891procedure ErasePixelInline(dest: PBGRAPixel; alpha: byte); inline;
892var
893 newAlpha: byte;
894begin
895 newAlpha := ApplyOpacity(dest^.alpha, not alpha);
896 if newAlpha = 0 then
897 dest^ := BGRAPixelTransparent
898 else
899 dest^.alpha := newAlpha;
900end;
901
902{$i blendpixelsover.inc}
903
904{$i blendpixelinline.inc}
905
906end.
907
Note: See TracBrowser for help on using the repository browser.