source: trunk/Packages/Graphics32/GR32_Blend.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 30.9 KB
Line 
1unit GR32_Blend;
2
3(* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1 or LGPL 2.1 with linking exception
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of the
17 * Free Pascal modified version of the GNU Lesser General Public License
18 * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
19 * of this license are applicable instead of those above.
20 * Please see the file LICENSE.txt for additional information concerning this
21 * license.
22 *
23 * The Original Code is Graphics32
24 *
25 * The Initial Developer of the Original Code is
26 * Alex A. Denisov
27 *
28 * Portions created by the Initial Developer are Copyright (C) 2000-2009
29 * the Initial Developer. All Rights Reserved.
30 *
31 * Contributor(s):
32 * Mattias Andersson
33 * - 2004/07/07 - MMX Blendmodes
34 * - 2004/12/10 - _MergeReg, M_MergeReg
35 *
36 * Michael Hansen <dyster_tid@hotmail.com>
37 * - 2004/07/07 - Pascal Blendmodes, function setup
38 * - 2005/08/19 - New merge table concept and reference implementations
39 *
40 * Bob Voigt
41 * - 2004/08/25 - ColorDiv
42 *
43 * Christian-W. Budde
44 * - 2019/04/01 - Refactoring
45 *
46 * ***** END LICENSE BLOCK ***** *)
47
48interface
49
50{$I GR32.inc}
51
52uses
53 GR32, GR32_Bindings, SysUtils;
54
55var
56 MMX_ACTIVE: Boolean;
57
58type
59{ Function Prototypes }
60 TBlendReg = function(F, B: TColor32): TColor32;
61 TBlendMem = procedure(F: TColor32; var B: TColor32);
62 TBlendMems = procedure(F: TColor32; B: PColor32; Count: Integer);
63 TBlendRegEx = function(F, B, M: TColor32): TColor32;
64 TBlendMemEx = procedure(F: TColor32; var B: TColor32; M: TColor32);
65 TBlendRegRGB = function(F, B, W: TColor32): TColor32;
66 TBlendMemRGB = procedure(F: TColor32; var B: TColor32; W: TColor32);
67{$IFDEF TEST_BLENDMEMRGB128SSE4}
68 TBlendMemRGB128 = procedure(F: TColor32; var B: TColor32; W: UInt64);
69{$ENDIF}
70 TBlendLine = procedure(Src, Dst: PColor32; Count: Integer);
71 TBlendLineEx = procedure(Src, Dst: PColor32; Count: Integer; M: TColor32);
72 TBlendLine1 = procedure(Src: TColor32; Dst: PColor32; Count: Integer);
73 TCombineReg = function(X, Y, W: TColor32): TColor32;
74 TCombineMem = procedure(X: TColor32; var Y: TColor32; W: TColor32);
75 TCombineLine = procedure(Src, Dst: PColor32; Count: Integer; W: TColor32);
76 TLightenReg = function(C: TColor32; Amount: Integer): TColor32;
77
78var
79{$IFNDEF OMIT_MMX}
80 EMMS: procedure;
81{$ENDIF}
82
83{ Function Variables }
84 BlendReg: TBlendReg;
85 BlendMem: TBlendMem;
86 BlendMems: TBlendMems;
87
88 BlendRegEx: TBlendRegEx;
89 BlendMemEx: TBlendMemEx;
90
91 BlendRegRGB: TBlendRegRGB;
92 BlendMemRGB: TBlendMemRGB;
93{$IFDEF TEST_BLENDMEMRGB128SSE4}
94 BlendMemRGB128: TBlendMemRGB128;
95{$ENDIF}
96
97 BlendLine: TBlendLine;
98 BlendLineEx: TBlendLineEx;
99 BlendLine1: TBlendLine1;
100
101 CombineReg: TCombineReg;
102 CombineMem: TCombineMem;
103 CombineLine: TCombineLine;
104
105 MergeReg: TBlendReg;
106 MergeMem: TBlendMem;
107
108 MergeRegEx: TBlendRegEx;
109 MergeMemEx: TBlendMemEx;
110
111 MergeLine: TBlendLine;
112 MergeLineEx: TBlendLineEx;
113 MergeLine1: TBlendLine1;
114
115{ Color algebra functions }
116 ColorAdd: TBlendReg;
117 ColorSub: TBlendReg;
118 ColorDiv: TBlendReg;
119 ColorModulate: TBlendReg;
120 ColorMax: TBlendReg;
121 ColorMin: TBlendReg;
122 ColorDifference: TBlendReg;
123 ColorAverage: TBlendReg;
124 ColorExclusion: TBlendReg;
125 ColorScale: TBlendReg;
126 ColorScreen: TBlendReg;
127 ColorDodge: TBlendReg;
128 ColorBurn: TBlendReg;
129
130{ Blended color algebra functions }
131 BlendColorAdd: TBlendReg;
132 BlendColorModulate: TBlendReg;
133
134{ Special LUT pointers }
135 AlphaTable: Pointer;
136 bias_ptr: Pointer;
137 alpha_ptr: Pointer;
138
139
140{ Misc stuff }
141 LightenReg: TLightenReg;
142
143function Lighten(C: TColor32; Amount: Integer): TColor32; {$IFDEF USEINLINING} inline; {$ENDIF}
144
145{ Access to alpha composite functions corresponding to a combine mode }
146
147type
148 PBlendReg = ^TBlendReg;
149 PBlendMem = ^TBlendMem;
150 PBlendRegEx = ^TBlendRegEx;
151 PBlendMemEx = ^TBlendMemEx;
152 PBlendLine = ^TBlendLine;
153 PBlendLineEx = ^TBlendLineEx;
154
155 TBlendRegCombineModeArray = array[TCombineMode] of PBlendReg;
156 TBlendMemCombineModeArray = array[TCombineMode] of PBlendMem;
157 TBlendRegExCombineModeArray = array[TCombineMode] of PBlendRegEx;
158 TBlendMemExCombineModeArray = array[TCombineMode] of PBlendMemEx;
159 TBlendLineCombineModeArray = array[TCombineMode] of PBlendLine;
160 TBlendLineExCombineModeArray = array[TCombineMode] of PBlendLineEx;
161
162const
163 BLEND_REG: TBlendRegCombineModeArray = ((@@BlendReg),(@@MergeReg));
164 BLEND_MEM: TBlendMemCombineModeArray = ((@@BlendMem),(@@MergeMem));
165 BLEND_REG_EX: TBlendRegExCombineModeArray = ((@@BlendRegEx),(@@MergeRegEx));
166 BLEND_MEM_EX: TBlendMemExCombineModeArray = ((@@BlendMemEx),(@@MergeMemEx));
167 BLEND_LINE: TBlendLineCombineModeArray = ((@@BlendLine),(@@MergeLine));
168 BLEND_LINE_EX: TBlendLineExCombineModeArray = ((@@BlendLineEx),(@@MergeLineEx));
169
170var
171 BlendRegistry: TFunctionRegistry;
172
173{$IFDEF OMIT_MMX}
174procedure EMMS; {$IFDEF USEINLINING} inline; {$ENDIF}
175{$ENDIF}
176
177var
178 RcTable: array [Byte, Byte] of Byte;
179 DivTable: array [Byte, Byte] of Byte;
180
181implementation
182
183uses
184 GR32_LowLevel,
185{$IFNDEF PUREPASCAL}
186 GR32_BlendASM,
187{$IFNDEF OMIT_MMX}
188 GR32_BlendMMX,
189{$ENDIF}
190{$IFNDEF OMIT_SSE2}
191 GR32_BlendSSE2,
192{$ENDIF}
193{$ENDIF}
194 GR32_System;
195
196{$IFDEF OMIT_MMX}
197procedure EMMS;
198begin
199end;
200{$ENDIF}
201
202{ Pure Pascal }
203
204function BlendReg_Pas(F, B: TColor32): TColor32;
205var
206 FX: TColor32Entry absolute F;
207 BX: TColor32Entry absolute B;
208 Af, Ab: PByteArray;
209 FA : Byte;
210begin
211 FA := FX.A;
212
213 if FA = 0 then
214 begin
215 Result := B;
216 Exit;
217 end;
218
219 if FA = $FF then
220 begin
221 Result := F;
222 Exit;
223 end;
224
225 Af := @DivTable[FA];
226 Ab := @DivTable[not FA];
227 with BX do
228 begin
229 R := Af[FX.R] + Ab[R];
230 G := Af[FX.G] + Ab[G];
231 B := Af[FX.B] + Ab[B];
232 A := $FF;
233 end;
234 Result := B;
235end;
236
237procedure BlendMem_Pas(F: TColor32; var B: TColor32);
238var
239 FX: TColor32Entry absolute F;
240 BX: TColor32Entry absolute B;
241 Af, Ab: PByteArray;
242 FA : Byte;
243begin
244 FA := FX.A;
245
246 if FA = 0 then Exit;
247
248 if FA = $FF then
249 begin
250 B := F;
251 Exit;
252 end;
253
254 Af := @DivTable[FA];
255 Ab := @DivTable[not FA];
256 with BX do
257 begin
258 R := Af[FX.R] + Ab[R];
259 G := Af[FX.G] + Ab[G];
260 B := Af[FX.B] + Ab[B];
261 A := $FF;
262 end;
263end;
264
265procedure BlendMems_Pas(F: TColor32; B: PColor32; Count: Integer);
266begin
267 while Count > 0 do
268 begin
269 BlendMem(F, B^);
270 Inc(B);
271 Dec(Count);
272 end;
273end;
274
275function BlendRegEx_Pas(F, B, M: TColor32): TColor32;
276var
277 FX: TColor32Entry absolute F;
278 BX: TColor32Entry absolute B;
279 Af, Ab: PByteArray;
280begin
281 Af := @DivTable[M];
282
283 M := Af[FX.A];
284
285 if M = 0 then
286 begin
287 Result := B;
288 Exit;
289 end;
290
291 if M = $FF then
292 begin
293 Result := F;
294 Exit;
295 end;
296
297 Ab := @DivTable[255 - M];
298 with BX do
299 begin
300 R := Af[FX.R] + Ab[R];
301 G := Af[FX.G] + Ab[G];
302 B := Af[FX.B] + Ab[B];
303 A := $FF;
304 end;
305 Result := B;
306end;
307
308procedure BlendMemEx_Pas(F: TColor32; var B: TColor32; M: TColor32);
309var
310 FX: TColor32Entry absolute F;
311 BX: TColor32Entry absolute B;
312 Af, Ab: PByteArray;
313begin
314 Af := @DivTable[M];
315
316 M := Af[FX.A];
317
318 if M = 0 then
319 begin
320 Exit;
321 end;
322
323 if M = $FF then
324 begin
325 B := F;
326 Exit;
327 end;
328
329 Ab := @DivTable[255 - M];
330 with BX do
331 begin
332 R := Af[FX.R] + Ab[R];
333 G := Af[FX.G] + Ab[G];
334 B := Af[FX.B] + Ab[B];
335 A := $FF;
336 end;
337end;
338
339function BlendRegRGB_Pas(F, B, W: TColor32): TColor32;
340var
341 FX: TColor32Entry absolute F;
342 BX: TColor32Entry absolute B;
343 WX: TColor32Entry absolute W;
344 RX: TColor32Entry absolute Result;
345begin
346 RX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
347 RX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
348 RX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
349end;
350
351procedure BlendMemRGB_Pas(F: TColor32; var B: TColor32; W: TColor32);
352var
353 FX: TColor32Entry absolute F;
354 BX: TColor32Entry absolute B;
355 WX: TColor32Entry absolute W;
356begin
357 BX.R := (FX.R - BX.R) * WX.B div 255 + BX.R;
358 BX.G := (FX.G - BX.G) * WX.G div 255 + BX.G;
359 BX.B := (FX.B - BX.B) * WX.R div 255 + BX.B;
360end;
361
362procedure BlendLine1_Pas(Src: TColor32; Dst: PColor32; Count: Integer);
363begin
364 while Count > 0 do
365 begin
366 BlendMem(Src, Dst^);
367 Inc(Dst);
368 Dec(Count);
369 end;
370end;
371
372procedure BlendLine_Pas(Src, Dst: PColor32; Count: Integer);
373begin
374 while Count > 0 do
375 begin
376 BlendMem(Src^, Dst^);
377 Inc(Src);
378 Inc(Dst);
379 Dec(Count);
380 end;
381end;
382
383procedure BlendLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: TColor32);
384begin
385 while Count > 0 do
386 begin
387 BlendMemEx(Src^, Dst^, M);
388 Inc(Src);
389 Inc(Dst);
390 Dec(Count);
391 end;
392end;
393
394function CombineReg_Pas(X, Y, W: TColor32): TColor32;
395var
396 Xe: TColor32Entry absolute X;
397 Ye: TColor32Entry absolute Y;
398 Af, Ab: PByteArray;
399begin
400 if W = 0 then
401 begin
402 Result := Y;
403 Exit;
404 end;
405
406 if W >= $FF then
407 begin
408 Result := X;
409 Exit;
410 end;
411
412 Af := @DivTable[W];
413 Ab := @DivTable[255 - W];
414 with Xe do
415 begin
416 R := Ab[Ye.R] + Af[R];
417 G := Ab[Ye.G] + Af[G];
418 B := Ab[Ye.B] + Af[B];
419 A := Ab[Ye.A] + Af[A];
420 end;
421 Result := X;
422end;
423
424procedure CombineMem_Pas(X: TColor32; var Y: TColor32; W: TColor32);
425var
426 Xe: TColor32Entry absolute X;
427 Ye: TColor32Entry absolute Y;
428 Af, Ab: PByteArray;
429begin
430 if W = 0 then
431 begin
432 Exit;
433 end;
434
435 if W >= $FF then
436 begin
437 Y := X;
438 Exit;
439 end;
440
441 Af := @DivTable[W];
442 Ab := @DivTable[255 - W];
443 with Xe do
444 begin
445 R := Ab[Ye.R] + Af[R];
446 G := Ab[Ye.G] + Af[G];
447 B := Ab[Ye.B] + Af[B];
448 A := Ab[Ye.A] + Af[A];
449 end;
450 Y := X;
451end;
452
453procedure CombineLine_Pas(Src, Dst: PColor32; Count: Integer; W: TColor32);
454begin
455 while Count > 0 do
456 begin
457 CombineMem(Src^, Dst^, W);
458 Inc(Src);
459 Inc(Dst);
460 Dec(Count);
461 end;
462end;
463
464function MergeReg_Pas(F, B: TColor32): TColor32;
465var
466 Fa, Ba, Wa: TColor32;
467 Fw, Bw: PByteArray;
468 Fx: TColor32Entry absolute F;
469 Bx: TColor32Entry absolute B;
470 Rx: TColor32Entry absolute Result;
471begin
472 Fa := F shr 24;
473 Ba := B shr 24;
474 if Fa = $FF then
475 Result := F
476 else if Fa = $0 then
477 Result := B
478 else if Ba = $0 then
479 Result := F
480 else
481 begin
482 Rx.A := DivTable[Fa xor 255, Ba xor 255] xor 255;
483 Wa := RcTable[Rx.A, Fa];
484 Fw := @DivTable[Wa];
485 Bw := @DivTable[Wa xor $FF];
486 Rx.R := Fw[Fx.R] + Bw[Bx.R];
487 Rx.G := Fw[Fx.G] + Bw[Bx.G];
488 Rx.B := Fw[Fx.B] + Bw[Bx.B];
489 end;
490end;
491
492function MergeRegEx_Pas(F, B, M: TColor32): TColor32;
493begin
494 Result := MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
495end;
496
497procedure MergeMem_Pas(F: TColor32; var B: TColor32);
498begin
499 B := MergeReg(F, B);
500end;
501
502procedure MergeMemEx_Pas(F: TColor32; var B: TColor32; M: TColor32);
503begin
504 B := MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
505end;
506
507procedure MergeLine1_Pas(Src: TColor32; Dst: PColor32; Count: Integer);
508begin
509 while Count > 0 do
510 begin
511 Dst^ := MergeReg(Src, Dst^);
512 Inc(Dst);
513 Dec(Count);
514 end;
515end;
516
517procedure MergeLine_Pas(Src, Dst: PColor32; Count: Integer);
518begin
519 while Count > 0 do
520 begin
521 Dst^ := MergeReg(Src^, Dst^);
522 Inc(Src);
523 Inc(Dst);
524 Dec(Count);
525 end;
526end;
527
528procedure MergeLineEx_Pas(Src, Dst: PColor32; Count: Integer; M: TColor32);
529var
530 PM: PByteArray absolute M;
531begin
532 PM := @DivTable[M];
533 while Count > 0 do
534 begin
535 Dst^ := MergeReg((PM[Src^ shr 24] shl 24) or (Src^ and $00FFFFFF), Dst^);
536 Inc(Src);
537 Inc(Dst);
538 Dec(Count);
539 end;
540end;
541
542procedure EMMS_Pas;
543begin
544 // Dummy
545end;
546
547function LightenReg_Pas(C: TColor32; Amount: Integer): TColor32;
548var
549 r, g, b: Integer;
550 CX: TColor32Entry absolute C;
551 RX: TColor32Entry absolute Result;
552begin
553 r := CX.R;
554 g := CX.G;
555 b := CX.B;
556
557 Inc(r, Amount);
558 Inc(g, Amount);
559 Inc(b, Amount);
560
561 if r > 255 then r := 255 else if r < 0 then r := 0;
562 if g > 255 then g := 255 else if g < 0 then g := 0;
563 if b > 255 then b := 255 else if b < 0 then b := 0;
564
565 // preserve alpha
566 RX.A := CX.A;
567 RX.R := r;
568 RX.G := g;
569 RX.B := b;
570end;
571
572{ Color algebra }
573
574function ColorAdd_Pas(C1, C2: TColor32): TColor32;
575var
576 Xe: TColor32Entry absolute C1;
577 Ye: TColor32Entry absolute C2;
578 R: TColor32Entry absolute Result;
579begin
580 R.A := Clamp(Xe.A + Ye.A, 255);
581 R.R := Clamp(Xe.R + Ye.R, 255);
582 R.G := Clamp(Xe.G + Ye.G, 255);
583 R.B := Clamp(Xe.B + Ye.B, 255);
584end;
585
586function ColorSub_Pas(C1, C2: TColor32): TColor32;
587var
588 Xe: TColor32Entry absolute C1;
589 Ye: TColor32Entry absolute C2;
590 R: TColor32Entry absolute Result;
591 Temp: SmallInt;
592begin
593 Temp := Xe.A - Ye.A;
594 if Temp < 0 then
595 R.A := 0
596 else
597 R.A := Temp;
598 Temp := Xe.R - Ye.R;
599 if Temp < 0 then
600 R.R := 0
601 else
602 R.R := Temp;
603 Temp := Xe.G - Ye.G;
604 if Temp < 0 then
605 R.G := 0
606 else
607 R.G := Temp;
608 Temp := Xe.B - Ye.B;
609 if Temp < 0 then
610 R.B := 0
611 else
612 R.B := Temp;
613end;
614
615function ColorDiv_Pas(C1, C2: TColor32): TColor32;
616var
617 C1e: TColor32Entry absolute C1;
618 C2e: TColor32Entry absolute C2;
619 Re: TColor32Entry absolute Result;
620 Temp: Word;
621begin
622 if C1e.A = 0 then
623 Re.A := $FF
624 else
625 begin
626 Temp := (C2e.A shl 8) div C1e.A;
627 if Temp > $FF then
628 Re.A := $FF
629 else
630 Re.A := Temp;
631 end;
632
633 if C1e.R = 0 then
634 Re.R := $FF
635 else
636 begin
637 Temp := (C2e.R shl 8) div C1e.R;
638 if Temp > $FF then
639 Re.R := $FF
640 else
641 Re.R := Temp;
642 end;
643
644 if C1e.G = 0 then
645 Re.G := $FF
646 else
647 begin
648 Temp := (C2e.G shl 8) div C1e.G;
649 if Temp > $FF then
650 Re.G := $FF
651 else
652 Re.G := Temp;
653 end;
654
655 if C1e.B = 0 then
656 Re.B := $FF
657 else
658 begin
659 Temp := (C2e.B shl 8) div C1e.B;
660 if Temp > $FF then
661 Re.B := $FF
662 else
663 Re.B := Temp;
664 end;
665end;
666
667function ColorModulate_Pas(C1, C2: TColor32): TColor32;
668var
669 C1e: TColor32Entry absolute C2;
670 C2e: TColor32Entry absolute C2;
671 Re: TColor32Entry absolute Result;
672begin
673 Re.A := (C2e.A * C1e.A + $80) shr 8;
674 Re.R := (C2e.R * C1e.R + $80) shr 8;
675 Re.G := (C2e.G * C1e.G + $80) shr 8;
676 Re.B := (C2e.B * C1e.B + $80) shr 8;
677end;
678
679function ColorMax_Pas(C1, C2: TColor32): TColor32;
680var
681 REnt: TColor32Entry absolute Result;
682 C2Ent: TColor32Entry absolute C2;
683begin
684 Result := C1;
685 with C2Ent do
686 begin
687 if A > REnt.A then REnt.A := A;
688 if R > REnt.R then REnt.R := R;
689 if G > REnt.G then REnt.G := G;
690 if B > REnt.B then REnt.B := B;
691 end;
692end;
693
694function ColorMin_Pas(C1, C2: TColor32): TColor32;
695var
696 REnt: TColor32Entry absolute Result;
697 C2Ent: TColor32Entry absolute C2;
698begin
699 Result := C1;
700 with C2Ent do
701 begin
702 if A < REnt.A then REnt.A := A;
703 if R < REnt.R then REnt.R := R;
704 if G < REnt.G then REnt.G := G;
705 if B < REnt.B then REnt.B := B;
706 end;
707end;
708
709function ColorDifference_Pas(C1, C2: TColor32): TColor32;
710var
711 Xe: TColor32Entry absolute C1;
712 Ye: TColor32Entry absolute C2;
713 R: TColor32Entry absolute Result;
714begin
715 R.A := Abs(Xe.A - Ye.A);
716 R.R := Abs(Xe.R - Ye.R);
717 R.G := Abs(Xe.G - Ye.G);
718 R.B := Abs(Xe.B - Ye.B);
719end;
720
721function ColorExclusion_Pas(C1, C2: TColor32): TColor32;
722var
723 Xe: TColor32Entry absolute C1;
724 Ye: TColor32Entry absolute C2;
725 R: TColor32Entry absolute Result;
726begin
727 R.A := Xe.A + Ye.A - ((Xe.A * Ye.A) shl 7);
728 R.R := Xe.R + Ye.R - ((Xe.R * Ye.R) shr 7);
729 R.G := Xe.G + Ye.G - ((Xe.G * Ye.G) shr 7);
730 R.B := Xe.B + Ye.B - ((Xe.B * Ye.B) shr 7);
731end;
732
733function ColorAverage_Pas(C1, C2: TColor32): TColor32;
734//(A + B)/2 = (A and B) + (A xor B)/2
735var
736 C3 : TColor32;
737begin
738 C3 := C1;
739 C1 := C1 xor C2;
740 C1 := C1 shr 1;
741 C1 := C1 and $7F7F7F7F;
742 C3 := C3 and C2;
743 Result := C3 + C1;
744end;
745
746function ColorScale_Pas(C, W: TColor32): TColor32;
747var
748 Ce: TColor32Entry absolute C;
749var
750 r1, g1, b1, a1: Cardinal;
751begin
752 a1 := Ce.A * W shr 8;
753 r1 := Ce.R * W shr 8;
754 g1 := Ce.G * W shr 8;
755 b1 := Ce.B * W shr 8;
756
757 if a1 > 255 then a1 := 255;
758 if r1 > 255 then r1 := 255;
759 if g1 > 255 then g1 := 255;
760 if b1 > 255 then b1 := 255;
761
762 Result := a1 shl 24 + r1 shl 16 + g1 shl 8 + b1;
763end;
764
765function ColorScreen_Pas(B, S: TColor32): TColor32;
766var
767 Be: TColor32Entry absolute B;
768 Se: TColor32Entry absolute S;
769 R: TColor32Entry absolute Result;
770begin
771 R.A := Be.A + Se.A - (Be.A * Se.A) div 255;
772 R.R := Be.R + Se.R - (Be.R * Se.R) div 255;
773 R.G := Be.G + Se.G - (Be.G * Se.G) div 255;
774 R.B := Be.B + Se.B - (Be.B * Se.B) div 255;
775end;
776
777function ColorDodge_Pas(B, S: TColor32): TColor32;
778
779 function Dodge(B, S: Byte): Byte;
780 begin
781 if B = 0 then
782 Result := 0
783 else
784 if S = 255 then
785 Result := 255
786 else
787 Result := Clamp((255 * B) div (255 - S), 255);
788 end;
789
790var
791 Be: TColor32Entry absolute B;
792 Se: TColor32Entry absolute S;
793 R: TColor32Entry absolute Result;
794begin
795 R.A := Dodge(Be.A, Se.A);
796 R.R := Dodge(Be.R, Se.R);
797 R.G := Dodge(Be.G, Se.G);
798 R.B := Dodge(Be.B, Se.B);
799end;
800
801function ColorBurn_Pas(B, S: TColor32): TColor32;
802
803 function Burn(B, S: Byte): Byte;
804 begin
805 if B = 255 then
806 Result := 255
807 else
808 if S = 0 then
809 Result := 0
810 else
811 Result := 255 - Clamp(255 * (255 - B) div S, 255);
812 end;
813
814var
815 Be: TColor32Entry absolute B;
816 Se: TColor32Entry absolute S;
817 R: TColor32Entry absolute Result;
818begin
819 R.A := Burn(Be.A, Se.A);
820 R.R := Burn(Be.R, Se.R);
821 R.G := Burn(Be.G, Se.G);
822 R.B := Burn(Be.B, Se.B);
823end;
824
825
826{ Blended color algebra }
827
828function BlendColorAdd_Pas(C1, C2: TColor32): TColor32;
829var
830 Xe: TColor32Entry absolute C1;
831 Ye: TColor32Entry absolute C2;
832 R: TColor32Entry absolute Result;
833 Af, Ab: PByteArray;
834begin
835 Af := @DivTable[Xe.A];
836 Ab := @DivTable[not Xe.A];
837 R.A := Af[Clamp(Xe.A + Ye.A, 255)] + Ab[Ye.A];
838 R.R := Af[Clamp(Xe.R + Ye.R, 255)] + Ab[Ye.R];
839 R.G := Af[Clamp(Xe.G + Ye.G, 255)] + Ab[Ye.G];
840 R.B := Af[Clamp(Xe.B + Ye.B, 255)] + Ab[Ye.B];
841end;
842
843function BlendColorModulate_Pas(C1, C2: TColor32): TColor32;
844var
845 C1e: TColor32Entry absolute C1;
846 C2e: TColor32Entry absolute C2;
847 R: TColor32Entry absolute Result;
848 Af, Ab: PByteArray;
849begin
850 Af := @DivTable[C1e.A];
851 Ab := @DivTable[not C1e.A];
852 R.A := Af[(C2e.A * C1e.A + $80) shr 8] + Ab[C2e.A];
853 R.R := Af[(C2e.R * C1e.R + $80) shr 8] + Ab[C2e.R];
854 R.G := Af[(C2e.G * C1e.G + $80) shr 8] + Ab[C2e.G];
855 R.B := Af[(C2e.B * C1e.B + $80) shr 8] + Ab[C2e.B];
856end;
857
858{$IFNDEF PUREPASCAL}
859
860procedure GenAlphaTable;
861var
862 I: Integer;
863 L: LongWord;
864 P: PLongWord;
865begin
866 GetMem(AlphaTable, 257 * 8 * SizeOf(Cardinal));
867 {$IFDEF HAS_NATIVEINT}
868 alpha_ptr := Pointer(NativeUInt(AlphaTable) and (not $F));
869 if NativeUInt(alpha_ptr) < NativeUInt(AlphaTable) then
870 alpha_ptr := Pointer(NativeUInt(alpha_ptr) + 16);
871 {$ELSE}
872 alpha_ptr := Pointer(Cardinal(AlphaTable) and (not $F));
873 if Cardinal(alpha_ptr) < Cardinal(AlphaTable) then
874 Inc(Cardinal(alpha_ptr), 16);
875 {$ENDIF}
876 P := alpha_ptr;
877 for I := 0 to 255 do
878 begin
879 L := I + I shl 16;
880 P^ := L;
881 Inc(P);
882 P^ := L;
883 Inc(P);
884 P^ := L;
885 Inc(P);
886 P^ := L;
887 Inc(P);
888 end;
889 bias_ptr := alpha_ptr;
890 Inc(PLongWord(bias_ptr), 4 * $80);
891end;
892
893procedure FreeAlphaTable;
894begin
895 FreeMem(AlphaTable);
896end;
897{$ENDIF}
898
899{ Misc stuff }
900
901function Lighten(C: TColor32; Amount: Integer): TColor32;
902begin
903 Result := LightenReg(C, Amount);
904end;
905
906procedure MakeMergeTables;
907var
908 I, J: Integer;
909begin
910 for J := 0 to 255 do
911 begin
912 DivTable[0, J] := 0;
913 RcTable[0, J] := 0;
914 end;
915 for J := 0 to 255 do
916 for I := 1 to 255 do
917 begin
918 DivTable[I, J] := Round(I * J * COne255th);
919 RcTable[I, J] := Round(J * 255 / I)
920 end;
921end;
922
923const
924 FID_EMMS = 0;
925 FID_MERGEREG = 1;
926 FID_MERGEMEM = 2;
927 FID_MERGELINE = 3;
928 FID_MERGELINE1 = 4;
929 FID_MERGEREGEX = 5;
930 FID_MERGEMEMEX = 6;
931 FID_MERGELINEEX = 7;
932 FID_COMBINEREG = 8;
933 FID_COMBINEMEM = 9;
934 FID_COMBINELINE = 10;
935
936 FID_BLENDREG = 11;
937 FID_BLENDMEM = 12;
938 FID_BLENDMEMS = 13;
939 FID_BLENDLINE = 14;
940 FID_BLENDREGEX = 15;
941 FID_BLENDMEMEX = 16;
942 FID_BLENDLINEEX = 17;
943 FID_BLENDLINE1 = 18;
944
945 FID_COLORMAX = 19;
946 FID_COLORMIN = 20;
947 FID_COLORAVERAGE = 21;
948 FID_COLORADD = 22;
949 FID_COLORSUB = 23;
950 FID_COLORDIV = 24;
951 FID_COLORMODULATE = 25;
952 FID_COLORDIFFERENCE = 26;
953 FID_COLOREXCLUSION = 27;
954 FID_COLORSCALE = 28;
955 FID_COLORSCREEN = 29;
956 FID_COLORDODGE = 30;
957 FID_COLORBURN = 31;
958 FID_BLENDCOLORADD = 32;
959 FID_BLENDCOLORMODULATE = 33;
960 FID_LIGHTEN = 34;
961
962 FID_BLENDREGRGB = 35;
963 FID_BLENDMEMRGB = 36;
964{$IFDEF TEST_BLENDMEMRGB128SSE4}
965 FID_BLENDMEMRGB128 = 37;
966{$ENDIF}
967
968const
969 BlendBindingFlagPascal = $0001;
970
971
972procedure RegisterBindings;
973begin
974 BlendRegistry := NewRegistry('GR32_Blend bindings');
975{$IFNDEF OMIT_MMX}
976 BlendRegistry.RegisterBinding(FID_EMMS, @@EMMS);
977{$ENDIF}
978 BlendRegistry.RegisterBinding(FID_MERGEREG, @@MergeReg);
979 BlendRegistry.RegisterBinding(FID_MERGEMEM, @@MergeMem);
980 BlendRegistry.RegisterBinding(FID_MERGELINE, @@MergeLine);
981 BlendRegistry.RegisterBinding(FID_MERGEREGEX, @@MergeRegEx);
982 BlendRegistry.RegisterBinding(FID_MERGEMEMEX, @@MergeMemEx);
983 BlendRegistry.RegisterBinding(FID_MERGELINEEX, @@MergeLineEx);
984 BlendRegistry.RegisterBinding(FID_COMBINEREG, @@CombineReg);
985 BlendRegistry.RegisterBinding(FID_COMBINEMEM, @@CombineMem);
986 BlendRegistry.RegisterBinding(FID_COMBINELINE, @@CombineLine);
987
988 BlendRegistry.RegisterBinding(FID_BLENDREG, @@BlendReg);
989 BlendRegistry.RegisterBinding(FID_BLENDMEM, @@BlendMem);
990 BlendRegistry.RegisterBinding(FID_BLENDMEMS, @@BlendMems);
991 BlendRegistry.RegisterBinding(FID_BLENDLINE, @@BlendLine);
992 BlendRegistry.RegisterBinding(FID_BLENDREGEX, @@BlendRegEx);
993 BlendRegistry.RegisterBinding(FID_BLENDMEMEX, @@BlendMemEx);
994 BlendRegistry.RegisterBinding(FID_BLENDLINEEX, @@BlendLineEx);
995 BlendRegistry.RegisterBinding(FID_BLENDLINE1, @@BlendLine1);
996
997 BlendRegistry.RegisterBinding(FID_COLORMAX, @@ColorMax);
998 BlendRegistry.RegisterBinding(FID_COLORMIN, @@ColorMin);
999 BlendRegistry.RegisterBinding(FID_COLORAVERAGE, @@ColorAverage);
1000 BlendRegistry.RegisterBinding(FID_COLORADD, @@ColorAdd);
1001 BlendRegistry.RegisterBinding(FID_COLORSUB, @@ColorSub);
1002 BlendRegistry.RegisterBinding(FID_COLORDIV, @@ColorDiv);
1003 BlendRegistry.RegisterBinding(FID_COLORMODULATE, @@ColorModulate);
1004 BlendRegistry.RegisterBinding(FID_COLORDIFFERENCE, @@ColorDifference);
1005 BlendRegistry.RegisterBinding(FID_COLOREXCLUSION, @@ColorExclusion);
1006 BlendRegistry.RegisterBinding(FID_COLORSCALE, @@ColorScale);
1007 BlendRegistry.RegisterBinding(FID_COLORSCREEN, @@ColorScreen);
1008 BlendRegistry.RegisterBinding(FID_COLORDODGE, @@ColorDodge);
1009 BlendRegistry.RegisterBinding(FID_COLORBURN, @@ColorBurn);
1010
1011 BlendRegistry.RegisterBinding(FID_BLENDCOLORADD, @@BlendColorAdd);
1012 BlendRegistry.RegisterBinding(FID_BLENDCOLORMODULATE, @@BlendColorModulate);
1013
1014 BlendRegistry.RegisterBinding(FID_LIGHTEN, @@LightenReg);
1015 BlendRegistry.RegisterBinding(FID_BLENDREGRGB, @@BlendRegRGB);
1016 BlendRegistry.RegisterBinding(FID_BLENDMEMRGB, @@BlendMemRGB);
1017{$IFDEF TEST_BLENDMEMRGB128SSE4}
1018 BlendRegistry.RegisterBinding(FID_BLENDMEMRGB128, @@BlendMemRGB128);
1019{$ENDIF}
1020
1021 // pure pascal
1022 BlendRegistry.Add(FID_EMMS, @EMMS_Pas, [], BlendBindingFlagPascal);
1023 BlendRegistry.Add(FID_MERGEREG, @MergeReg_Pas, [], BlendBindingFlagPascal);
1024 BlendRegistry.Add(FID_MERGEMEM, @MergeMem_Pas, [], BlendBindingFlagPascal);
1025 BlendRegistry.Add(FID_MERGEMEMEX, @MergeMemEx_Pas, [], BlendBindingFlagPascal);
1026 BlendRegistry.Add(FID_MERGEREGEX, @MergeRegEx_Pas, [], BlendBindingFlagPascal);
1027 BlendRegistry.Add(FID_MERGELINE, @MergeLine_Pas, [], BlendBindingFlagPascal);
1028 BlendRegistry.Add(FID_MERGELINEEX, @MergeLineEx_Pas, [], BlendBindingFlagPascal);
1029 BlendRegistry.Add(FID_MERGELINE1, @MergeLine1_Pas, [], BlendBindingFlagPascal);
1030 BlendRegistry.Add(FID_COLORDIV, @ColorDiv_Pas, [], BlendBindingFlagPascal);
1031 BlendRegistry.Add(FID_COLORAVERAGE, @ColorAverage_Pas, [], BlendBindingFlagPascal);
1032 BlendRegistry.Add(FID_COMBINEREG, @CombineReg_Pas, [], BlendBindingFlagPascal);
1033 BlendRegistry.Add(FID_COMBINEMEM, @CombineMem_Pas, [], BlendBindingFlagPascal);
1034 BlendRegistry.Add(FID_COMBINELINE, @CombineLine_Pas, [], BlendBindingFlagPascal);
1035 BlendRegistry.Add(FID_BLENDREG, @BlendReg_Pas, [], BlendBindingFlagPascal);
1036 BlendRegistry.Add(FID_BLENDMEM, @BlendMem_Pas, [], BlendBindingFlagPascal);
1037 BlendRegistry.Add(FID_BLENDMEMS, @BlendMems_Pas, [], BlendBindingFlagPascal);
1038 BlendRegistry.Add(FID_BLENDLINE, @BlendLine_Pas, [], BlendBindingFlagPascal);
1039 BlendRegistry.Add(FID_BLENDREGEX, @BlendRegEx_Pas, [], BlendBindingFlagPascal);
1040 BlendRegistry.Add(FID_BLENDMEMEX, @BlendMemEx_Pas, [], BlendBindingFlagPascal);
1041 BlendRegistry.Add(FID_BLENDLINEEX, @BlendLineEx_Pas, [], BlendBindingFlagPascal);
1042 BlendRegistry.Add(FID_BLENDLINE1, @BlendLine1_Pas, [], BlendBindingFlagPascal);
1043 BlendRegistry.Add(FID_COLORMAX, @ColorMax_Pas, [], BlendBindingFlagPascal);
1044 BlendRegistry.Add(FID_COLORMIN, @ColorMin_Pas, [], BlendBindingFlagPascal);
1045 BlendRegistry.Add(FID_COLORADD, @ColorAdd_Pas, [], BlendBindingFlagPascal);
1046 BlendRegistry.Add(FID_COLORSUB, @ColorSub_Pas, [], BlendBindingFlagPascal);
1047 BlendRegistry.Add(FID_COLORMODULATE, @ColorModulate_Pas, [], BlendBindingFlagPascal);
1048 BlendRegistry.Add(FID_COLORDIFFERENCE, @ColorDifference_Pas, [], BlendBindingFlagPascal);
1049 BlendRegistry.Add(FID_COLOREXCLUSION, @ColorExclusion_Pas, [], BlendBindingFlagPascal);
1050 BlendRegistry.Add(FID_COLORSCALE, @ColorScale_Pas, [], BlendBindingFlagPascal);
1051 BlendRegistry.Add(FID_COLORSCREEN, @ColorScreen_Pas, [], BlendBindingFlagPascal);
1052 BlendRegistry.Add(FID_COLORDODGE, @ColorDodge_Pas, [], BlendBindingFlagPascal);
1053 BlendRegistry.Add(FID_COLORBURN, @ColorBurn_Pas, [], BlendBindingFlagPascal);
1054 BlendRegistry.Add(FID_BLENDCOLORADD, @BlendColorAdd_Pas, [], BlendBindingFlagPascal);
1055 BlendRegistry.Add(FID_BLENDCOLORMODULATE, @BlendColorModulate_Pas, [], BlendBindingFlagPascal);
1056 BlendRegistry.Add(FID_LIGHTEN, @LightenReg_Pas, [], BlendBindingFlagPascal);
1057 BlendRegistry.Add(FID_BLENDREGRGB, @BlendRegRGB_Pas, [], BlendBindingFlagPascal);
1058 BlendRegistry.Add(FID_BLENDMEMRGB, @BlendMemRGB_Pas, [], BlendBindingFlagPascal);
1059
1060{$IFNDEF PUREPASCAL}
1061 BlendRegistry.Add(FID_EMMS, @EMMS_ASM, []);
1062 BlendRegistry.Add(FID_COMBINEREG, @CombineReg_ASM, []);
1063 BlendRegistry.Add(FID_COMBINEMEM, @CombineMem_ASM, []);
1064 BlendRegistry.Add(FID_BLENDREG, @BlendReg_ASM, []);
1065 BlendRegistry.Add(FID_BLENDMEM, @BlendMem_ASM, []);
1066 BlendRegistry.Add(FID_BLENDMEMS, @BlendMems_ASM, []);
1067 BlendRegistry.Add(FID_BLENDREGEX, @BlendRegEx_ASM, []);
1068 BlendRegistry.Add(FID_BLENDMEMEX, @BlendMemEx_ASM, []);
1069 BlendRegistry.Add(FID_BLENDLINE, @BlendLine_ASM, []);
1070 BlendRegistry.Add(FID_BLENDLINE1, @BlendLine1_ASM, []);
1071{$IFNDEF TARGET_x64}
1072 BlendRegistry.Add(FID_MERGEREG, @MergeReg_ASM, []);
1073{$ENDIF}
1074{$IFNDEF OMIT_MMX}
1075 BlendRegistry.Add(FID_EMMS, @EMMS_MMX, [ciMMX]);
1076 BlendRegistry.Add(FID_COMBINEREG, @CombineReg_MMX, [ciMMX]);
1077 BlendRegistry.Add(FID_COMBINEMEM, @CombineMem_MMX, [ciMMX]);
1078 BlendRegistry.Add(FID_COMBINELINE, @CombineLine_MMX, [ciMMX]);
1079 BlendRegistry.Add(FID_BLENDREG, @BlendReg_MMX, [ciMMX]);
1080 BlendRegistry.Add(FID_BLENDMEM, @BlendMem_MMX, [ciMMX]);
1081 BlendRegistry.Add(FID_BLENDREGEX, @BlendRegEx_MMX, [ciMMX]);
1082 BlendRegistry.Add(FID_BLENDMEMEX, @BlendMemEx_MMX, [ciMMX]);
1083 BlendRegistry.Add(FID_BLENDLINE, @BlendLine_MMX, [ciMMX]);
1084 BlendRegistry.Add(FID_BLENDLINEEX, @BlendLineEx_MMX, [ciMMX]);
1085 BlendRegistry.Add(FID_COLORMAX, @ColorMax_EMMX, [ciEMMX]);
1086 BlendRegistry.Add(FID_COLORMIN, @ColorMin_EMMX, [ciEMMX]);
1087 BlendRegistry.Add(FID_COLORADD, @ColorAdd_MMX, [ciMMX]);
1088 BlendRegistry.Add(FID_COLORSUB, @ColorSub_MMX, [ciMMX]);
1089 BlendRegistry.Add(FID_COLORMODULATE, @ColorModulate_MMX, [ciMMX]);
1090 BlendRegistry.Add(FID_COLORDIFFERENCE, @ColorDifference_MMX, [ciMMX]);
1091 BlendRegistry.Add(FID_COLOREXCLUSION, @ColorExclusion_MMX, [ciMMX]);
1092 BlendRegistry.Add(FID_COLORSCALE, @ColorScale_MMX, [ciMMX]);
1093 BlendRegistry.Add(FID_LIGHTEN, @LightenReg_MMX, [ciMMX]);
1094 BlendRegistry.Add(FID_BLENDREGRGB, @BlendRegRGB_MMX, [ciMMX]);
1095 BlendRegistry.Add(FID_BLENDMEMRGB, @BlendMemRGB_MMX, [ciMMX]);
1096{$ENDIF}
1097{$IFNDEF OMIT_SSE2}
1098 BlendRegistry.Add(FID_EMMS, @EMMS_SSE2, [ciSSE2]);
1099 BlendRegistry.Add(FID_MERGEREG, @MergeReg_SSE2, [ciSSE2]);
1100 BlendRegistry.Add(FID_COMBINEREG, @CombineReg_SSE2, [ciSSE2]);
1101 BlendRegistry.Add(FID_COMBINEMEM, @CombineMem_SSE2, [ciSSE2]);
1102 BlendRegistry.Add(FID_COMBINELINE, @CombineLine_SSE2, [ciSSE2]);
1103 BlendRegistry.Add(FID_BLENDREG, @BlendReg_SSE2, [ciSSE2]);
1104 BlendRegistry.Add(FID_BLENDMEM, @BlendMem_SSE2, [ciSSE2]);
1105 BlendRegistry.Add(FID_BLENDMEMS, @BlendMems_SSE2, [ciSSE2]);
1106 BlendRegistry.Add(FID_BLENDMEMEX, @BlendMemEx_SSE2, [ciSSE2]);
1107 BlendRegistry.Add(FID_BLENDLINE, @BlendLine_SSE2, [ciSSE2]);
1108 BlendRegistry.Add(FID_BLENDLINEEX, @BlendLineEx_SSE2, [ciSSE2]);
1109 BlendRegistry.Add(FID_BLENDREGEX, @BlendRegEx_SSE2, [ciSSE2]);
1110 BlendRegistry.Add(FID_COLORMAX, @ColorMax_SSE2, [ciSSE2]);
1111 BlendRegistry.Add(FID_COLORMIN, @ColorMin_SSE2, [ciSSE2]);
1112 BlendRegistry.Add(FID_COLORADD, @ColorAdd_SSE2, [ciSSE2]);
1113 BlendRegistry.Add(FID_COLORSUB, @ColorSub_SSE2, [ciSSE2]);
1114 BlendRegistry.Add(FID_COLORMODULATE, @ColorModulate_SSE2, [ciSSE2]);
1115 BlendRegistry.Add(FID_COLORDIFFERENCE, @ColorDifference_SSE2, [ciSSE2]);
1116 BlendRegistry.Add(FID_COLOREXCLUSION, @ColorExclusion_SSE2, [ciSSE2]);
1117 BlendRegistry.Add(FID_COLORSCALE, @ColorScale_SSE2, [ciSSE2]);
1118 BlendRegistry.Add(FID_LIGHTEN, @LightenReg_SSE2, [ciSSE]);
1119 BlendRegistry.Add(FID_BLENDREGRGB, @BlendRegRGB_SSE2, [ciSSE2]);
1120 BlendRegistry.Add(FID_BLENDMEMRGB, @BlendMemRGB_SSE2, [ciSSE2]);
1121{$IFDEF TEST_BLENDMEMRGB128SSE4}
1122 BlendRegistry.Add(FID_BLENDMEMRGB128, @BlendMemRGB128_SSE4, [ciSSE2]);
1123{$ENDIF}
1124{$ENDIF}
1125{$ENDIF}
1126
1127 BlendRegistry.RebindAll;
1128end;
1129
1130initialization
1131 BlendColorAdd := BlendColorAdd_Pas;
1132
1133 RegisterBindings;
1134 MakeMergeTables;
1135
1136{$IFNDEF PUREPASCAL}
1137 MMX_ACTIVE := (ciMMX in CPUFeatures);
1138 if [ciMMX, ciSSE2] * CPUFeatures <> [] then
1139 GenAlphaTable;
1140{$ELSE}
1141 MMX_ACTIVE := False;
1142{$ENDIF}
1143
1144finalization
1145{$IFNDEF PUREPASCAL}
1146 if [ciMMX, ciSSE2] * CPUFeatures <> [] then
1147 FreeAlphaTable;
1148{$ENDIF}
1149
1150end.
Note: See TracBrowser for help on using the repository browser.