📄 _graphutils.pas
字号:
AND EAX, $00FF00FF // EAX <- 00 Xr 00 Xb
AND EBX, $FF00FF00 // EBX <- Xa 00 Xg 00
IMUL EAX, ECX // EAX <- Pr ** Pb **
SHR EBX, 8 // EBX <- 00 Xa 00 Xg
IMUL EBX, ECX // EBX <- Pa ** Pg **
ADD EAX, Bias
AND EAX, $FF00FF00 // EAX <- Pr 00 Pb 00
SHR EAX, 8 // EAX <- 00 Pr 00 Pb
ADD EBX, Bias
AND EBX, $FF00FF00 // EBX <- Pa 00 Pg 00
OR EAX, EBX // EAX <- Pa Pr Pg Pb
// W = 1 - W; Q = W * Y
XOR ECX, $000000FF // ECX <- 1 - ECX
MOV EBX, EDX // EBX <- Ya Yr Yg Yb
AND EDX, $00FF00FF // EDX <- 00 Yr 00 Yb
AND EBX, $FF00FF00 // EBX <- Ya 00 Yg 00
IMUL EDX, ECX // EDX <- Qr ** Qb **
SHR EBX, 8 // EBX <- 00 Ya 00 Yg
IMUL EBX, ECX // EBX <- Qa ** Qg **
ADD EDX, Bias
AND EDX, $FF00FF00 // EDX <- Qr 00 Qb 00
SHR EDX, 8 // EDX <- 00 Qr ** Qb
ADD EBX, Bias
AND EBX, $FF00FF00 // EBX <- Qa 00 Qg 00
OR EBX, EDX // EBX <- Qa Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX, EBX // EAX <- Za Zr Zg Zb
POP EBX
RET
@1: MOV EAX, EDX
@2: RET
end;}
begin
// combine RGBA channels of colors X and Y with the weight of X given in W
// Result Z = W * X + (1 - W) * Y (all channels are combined, including alpha)
if W = 0 then
Result := Y //May be if W <= 0 ???
else
if W = $FF then Result := X //May be if W >= $FF ??? Or if W > $FF ???
else
begin
Result :=
(((((X shr 8 {00Xa00Xg}) and $00FF00FF {00X100X2}) * W {P1**P2**}) +
Bias) and $FF00FF00 {P100P200}) {Pa00Pg00} or
(((((X {00Xr00Xb} and $00FF00FF {00X100X2}) * W {P1**P2**}) + Bias) and
$FF00FF00 {P100P200}) shr 8 {00Pr00Pb}) {PaPrPgPb};
W := W xor $FF; // W := 1 - W;
//W := $100 - W; // May be so ???
Result := Result {PaPrPgPb} + (
(((((Y shr 8 {00Ya00Yg}) and $00FF00FF {00X100X2}) * W {P1**P2**}) +
Bias) and $FF00FF00 {P100P200}) {Qa00Qg00} or
(((((Y {00Yr00Yb} and $00FF00FF {00X100X2}) * W {P1**P2**}) + Bias) and
$FF00FF00 {P100P200}) shr 8 {00Qr00Qb}) {QaQrQgQb}
) {ZaZrZgZb};
end;
end;
procedure _CombineMem(F: TColor32; var B: TColor32; W: TColor32);
{asm
// EAX <- F
// [EDX] <- B
// ECX <- W
PUSH EDX
MOV EDX, [EDX]
CALL _CombineReg
POP EDX
MOV [EDX], EAX
end;}
begin
B := _CombineReg(F, B, W);
end;
function _BlendReg(F, B: TColor32): TColor32;
{asm
// blend foreground color (F) to a background color (B),
// using alpha channel value of F
// Result Z = Fa * Frgb + (1 - Fa) * Brgb
// EAX <- F
// EDX <- B
MOV ECX, EAX // ECX <- Fa Fr Fg Fb
SHR ECX, 24 // ECX <- 00 00 00 Fa
JMP _CombineReg
end;}
begin
Result := _CombineReg(F, B, F shr 24);
end;
procedure _BlendMem(F: TColor32; var B: TColor32);
{asm
// EAX <- F
// [EDX] <- B
PUSH EDX
MOV ECX, EAX // ECX <- Fa Fr Fg Fb
SHR ECX, 24 // ECX <- 00 00 00 Fa
MOV EDX, [EDX]
CALL _CombineReg
POP EDX
MOV [EDX], EAX
end;}
begin
B := _CombineReg(F, B, F shr 24);
end;
function _BlendRegEx(F, B, M: TColor32): TColor32;
{asm
// blend foreground color (F) to a background color (B),
// using alpha channel value of F multiplied by master alpha (M)
// no checking for M = $FF, if this is the case Graphics32 uses BlendReg
// Result Z = Fa * M * Frgb + (1 - Fa * M) * Brgb
// EAX <- F
// EDX <- B
// ECX <- M
MOV EBX, EAX // EBX <- Fa Fr Fg Fb
SHR EBX, 24 // EBX <- 00 00 00 Fa
IMUL ECX, EBX // ECX <- 00 00 W **
SHR ECX, 8 // ECX <- 00 00 00 W
JMP _CombineReg
end;}
begin
Result := _CombineReg(F, B, ((F shr 24) * M) shr 8);
end;
procedure _BlendMemEx(F: TColor32; var B: TColor32; M: TColor32);
{asm
// EAX <- F
// [EDX] <- B
// ECX <- M
PUSH EBX
MOV EBX, EAX // EBX <- Fa Fr Fg Fb
SHR EBX, 24 // EBX <- 00 00 00 Fa
IMUL ECX, EBX // ECX <- 00 00 W **
SHR ECX, 8 // ECX <- 00 00 00 W
MOV EBX, EDX
MOV EDX, [EDX]
CALL _BlendRegEx
MOV [EBX], EAX
POP EBX
end;}
begin
B := _CombineReg(F, B, ((F shr 24) * M) shr 8);
end;
procedure _BlendLine(Src, Dst: PColor32; Count: Integer); assembler;
asm
// EAX <- Src
// EDX <- Dst
// ECX <- Count
// test the counter for zero or negativity
TEST ECX, ECX
JS @4
PUSH EBX
PUSH ESI
PUSH EDI
MOV ESI, EAX // ESI <- Src
MOV EDI, EDX // EDI <- Dst
// loop start
@1: MOV EAX, [ESI]
TEST EAX, $FF000000
JZ @3 // complete transparency, proceed to next point
PUSH ECX // store counter
// Get weight W = Fa * M
MOV ECX, EAX // ECX <- Fa Fr Fg Fb
SHR ECX, 24 // ECX <- 00 00 00 Fa
// Test Fa = 255 ?
CMP ECX, $FF
JZ @2
// P = W * F
MOV EBX, EAX // EBX <- Fa Fr Fg Fb
AND EAX, $00FF00FF // EAX <- 00 Fr 00 Fb
AND EBX, $FF00FF00 // EBX <- Fa 00 Fg 00
IMUL EAX, ECX // EAX <- Pr ** Pb **
SHR EBX, 8 // EBX <- 00 Fa 00 Fg
IMUL EBX, ECX // EBX <- Pa ** Pg **
ADD EAX, Bias
AND EAX, $FF00FF00 // EAX <- Pr 00 Pb 00
SHR EAX, 8 // EAX <- 00 Pr ** Pb
ADD EBX, Bias
AND EBX, $FF00FF00 // EBX <- Pa 00 Pg 00
OR EAX, EBX // EAX <- Pa Pr Pg Pb
// W = 1 - W; Q = W * B
MOV EDX, [EDI]
XOR ECX, $000000FF // ECX <- 1 - ECX
MOV EBX, EDX // EBX <- Ba Br Bg Bb
AND EDX, $00FF00FF // ESI <- 00 Br 00 Bb
AND EBX, $FF00FF00 // EBX <- Ba 00 Bg 00
IMUL EDX, ECX // ESI <- Qr ** Qb **
SHR EBX, 8 // EBX <- 00 Ba 00 Bg
IMUL EBX, ECX // EBX <- Qa ** Qg **
ADD EDX, Bias
AND EDX, $FF00FF00 // ESI <- Qr 00 Qb 00
SHR EDX, 8 // ESI <- 00 Qr ** Qb
ADD EBX, Bias
AND EBX, $FF00FF00 // EBX <- Qa 00 Qg 00
OR EBX, EDX // EBX <- Qa Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX, EBX // EAX <- Za Zr Zg Zb
@2: MOV [EDI], EAX
POP ECX // restore counter
@3: ADD ESI, 4
ADD EDI, 4
// loop end
DEC ECX
JNZ @1
POP EDI
POP ESI
POP EBX
@4: RET
end;
procedure _BlendLineEx(Src, Dst: PColor32; Count: Integer; M: TColor32);
begin
while Count > 0 do
begin
_BlendMemEx(Src^, Dst^, M);
Inc(Src);
Inc(Dst);
Dec(Count);
end;
end;
{ MMX versions }
var
AlphaTable: Pointer;
bias_ptr: Pointer;
alpha_ptr: Pointer;
procedure GenAlphaTable;
var
I: Integer;
L: Longword;
P: ^Longword;
begin
GetMem(AlphaTable, 257 * 8);
alpha_ptr := Pointer(Integer(AlphaTable) and $FFFFFFF8);
if Integer(alpha_ptr) < Integer(AlphaTable) then
alpha_ptr := Pointer(Integer(alpha_ptr) + 8);
P := alpha_ptr;
for I := 0 to 255 do
begin
L := I + I shl 16;
P^ := L;
Inc(P);
P^ := L;
Inc(P);
end;
bias_ptr := Pointer(Integer(alpha_ptr) + $80 * 8);
end;
procedure FreeAlphaTable;
begin
FreeMem(AlphaTable);
AlphaTable := nil;
end;
procedure EMMS;
begin
if MMX_ACTIVE then
asm
db $0F, $77 // EMMS
end;
end;
function M_CombineReg(X, Y, W: TColor32): TColor32; assembler;
asm
// EAX - Color X
// EDX - Color Y
// ECX - Weight of X [0..255]
// Result := W * (X - Y) + Y
db $0F, $EF, $C0 // PXOR MM0, MM0
db $0F, $6E, $C8 // MOVD MM1, EAX
SHL ECX, 3
db $0F, $6E, $D2 // MOVD MM2, EDX
db $0F, $60, $C8 // PUNPCKLBW MM1, MM0
db $0F, $60, $D0 // PUNPCKLBW MM2, MM0
ADD ECX, alpha_ptr
db $0F, $F9, $CA // PSUBW MM1, MM2
db $0F, $D5, $09 // PMULLW MM1, [ECX]
db $0F, $71, $F2,$08 // PSLLW MM2, 8
MOV ECX, bias_ptr
db $0F, $FD, $11 // PADDW MM2, [ECX]
db $0F, $FD, $CA // PADDW MM1, MM2
db $0F, $71, $D1, $08 // PSRLW MM1, 8
db $0F, $67, $C8 // PACKUSWB MM1, MM0
db $0F, $7E, $C8 // MOVD EAX, MM1
end;
procedure M_CombineMem(F: TColor32; var B: TColor32; W: TColor32);
{asm
// EAX - Color X
// [EDX] - Color Y
// ECX - Weight of X [0..255]
// Result := W * (X - Y) + Y
PUSH EDX
MOV EDX, [EDX]
CALL M_CombineReg
POP EDX
MOV [EDX], EAX
end;}
begin
B := M_CombineReg(F, B, W);
end;
function M_BlendReg(F, B: TColor32): TColor32; assembler;
asm
// blend foreground color (F) to a background color (B),
// using alpha channel value of F
// EAX <- F
// EDX <- B
// Result := Fa * (Frgb - Brgb) + Brgb
db $0F, $EF, $DB // PXOR MM3, MM3
db $0F, $6E, $C0 // MOVD MM0, EAX
db $0F, $6E, $D2 // MOVD MM2, EDX
db $0F, $60, $C3 // PUNPCKLBW MM0, MM3
MOV ECX, bias_ptr
db $0F, $60, $D3 // PUNPCKLBW MM2, MM3
db $0F, $6F, $C8 // MOVQ MM1, MM0
db $0F, $69, $C9 // PUNPCKHWD MM1, MM1
db $0F, $F9, $C2 // PSUBW MM0, MM2
db $0F, $6A, $C9 // PUNPCKHDQ MM1, MM1
db $0F, $71, $F2, $08 // PSLLW MM2, 8
db $0F, $D5, $C1 // PMULLW MM0, MM1
db $0F, $FD, $11 // PADDW MM2, [ECX]
db $0F, $FD, $D0 // PADDW MM2, MM0
db $0F, $71, $D2, $08 // PSRLW MM2, 8
db $0F, $67, $D3 // PACKUSWB MM2, MM3
db $0F, $7E, $D0 // MOVD EAX, MM2
end;
procedure M_BlendMem(F: TColor32; var B: TColor32);
{asm
// EAX - Color X
// [EDX] - Color Y
// Result := W * (X - Y) + Y
PUSH EDX
MOV EDX, [EDX]
CALL M_BlendReg
POP EDX
MOV [EDX], EAX
end;}
begin
B := M_BlendReg(F, B);
end;
function M_BlendRegEx(F, B, M: TColor32): TColor32; assembler;
asm
// blend foreground color (F) to a background color (B),
// using alpha channel value of F
// EAX <- F
// EDX <- B
// ECX <- M
// Result := M * Fa * (Frgb - Brgb) + Brgb
PUSH EBX
MOV EBX, EAX
SHR EBX, 24
IMUL ECX, EBX
SHR ECX, 8
JZ @1
db $0F, $EF, $C0 // PXOR MM0, MM0
db $0F, $6E, $C8 // MOVD MM1, EAX
SHL ECX, 3
db $0F, $6E, $D2 // MOVD MM2, EDX
db $0F, $60, $C8 // PUNPCKLBW MM1, MM0
db $0F, $60, $D0 // PUNPCKLBW MM2, MM0
ADD ECX, alpha_ptr
db $0F, $F9, $CA // PSUBW MM1, MM2
db $0F, $D5, $09 // PMULLW MM1, [ECX]
db $0F, $71, $F2, $08 // PSLLW MM2, 8
MOV ECX, bias_ptr
db $0F, $FD, $11 // PADDW MM2, [ECX]
db $0F, $FD, $CA // PADDW MM1, MM2
db $0F, $71, $D1, $08 // PSRLW MM1, 8
db $0F, $67, $C8 // PACKUSWB MM1, MM0
db $0F, $7E, $C8 // MOVD EAX, MM1
@1: MOV EAX, EDX
POP EBX
end;
procedure M_BlendMemEx(F: TColor32; var B: TColor32; M: TColor32);
{asm
// blend foreground color (F) to a background color (B),
// using alpha channel value of F
// EAX <- F
// [EDX] <- B
// ECX <- M
// Result := M * Fa * (Frgb - Brgb) + Brgb
PUSH EDX
MOV EDX, [EDX]
CALL M_BlendRegEx
POP EDX
MOV [EDX], EAX
end;}
begin
B := M_BlendRegEx(F, B, M);
end;
procedure M_BlendLine(Src, Dst: PColor32; Count: Integer); assembler;
asm
// EAX <- Src
// EDX <- Dst
// ECX <- Count
// test the counter for zero or negativity
TEST ECX, ECX
JS @4
PUSH ESI
PUSH EDI
MOV ESI, EAX // ESI <- Src
MOV EDI, EDX // EDI <- Dst
// loop start
@1: MOV EAX, [ESI]
TEST EAX, $FF000000
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -