📄 gr32_blend.pas
字号:
SHR EBX,8 // EBX <- 00 Ba 00 Bg
IMUL EBX,ECX // EBX <- Qa 00 Qg **
ADD ESI,bias
AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
SHR ESI,8 // ESI <- 00 Qr ** Qb
ADD EBX,bias
AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
OR EBX,ESI // EBX <- 00 Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX,EBX // EAX <- 00 Zr Zg Zb
MOV [EDX],EAX
POP ESI
POP EBX
@1: RET
@2: MOV [EDX],EAX
RET
end;
function _BlendReg(F, B: TColor32): TColor32;
asm
// blend foregrownd color (F) to a background color (B),
// using alpha channel value of F
// Result Z = Fa * Frgb + (1 - Fa) * Brgb
// EAX <- F
// EDX <- B
// Test Fa = 255 ?
CMP EAX,$FF000000 // Fa = 255 ? => Result = EAX
JNC @2
// Test Fa = 0 ?
TEST EAX,$FF000000 // Fa = 0 ? => Result = EDX
JZ @1
// Get weight W = Fa * M
MOV ECX,EAX // ECX <- Fa Fr Fg Fb
SHR ECX,24 // ECX <- 00 00 00 Fa
PUSH EBX
// 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
XOR ECX,$000000FF // ECX <- 1 - ECX
MOV EBX,EDX // EBX <- Ba Br Bg Bb
AND EDX,$00FF00FF // EDX <- 00 Br 00 Bb
AND EBX,$FF00FF00 // EBX <- Ba 00 Bg 00
IMUL EDX,ECX // EDX <- Qr ** Qb **
SHR EBX,8 // EBX <- 00 Ba 00 Bg
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;
procedure _BlendMem(F: TColor32; var B: TColor32);
asm
// EAX <- F
// [EDX] <- B
// Test Fa = 0 ?
TEST EAX,$FF000000 // Fa = 0 ? => do not write
JZ @2
// 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 @1
PUSH EBX
PUSH ESI
// 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 ESI,[EDX]
XOR ECX,$000000FF // ECX <- 1 - ECX
MOV EBX,ESI // EBX <- Ba Br Bg Bb
AND ESI,$00FF00FF // ESI <- 00 Br 00 Bb
AND EBX,$FF00FF00 // EBX <- Ba 00 Bg 00
IMUL ESI,ECX // ESI <- Qr ** Qb **
SHR EBX,8 // EBX <- 00 Ba 00 Bg
IMUL EBX,ECX // EBX <- Qa ** Qg **
ADD ESI,bias
AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
SHR ESI,8 // ESI <- 00 Qr ** Qb
ADD EBX,bias
AND EBX,$FF00FF00 // EBX <- Qa 00 Qg 00
OR EBX,ESI // EBX <- Qa Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX,EBX // EAX <- Za Zr Zg Zb
MOV [EDX],EAX
POP ESI
POP EBX
RET
@1: MOV [EDX],EAX
@2: RET
end;
function _BlendRegEx(F, B, M: TColor32): TColor32;
asm
// blend foregrownd 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 when Graphics32 uses BlendReg
// Result Z = Fa * M * Frgb + (1 - Fa * M) * Brgb
// EAX <- F
// EDX <- B
// ECX <- M
// Check Fa > 0 ?
TEST EAX,$FF000000 // Fa = 0? => Result := EDX
JZ @2
PUSH EBX
// Get weight W = Fa * M
MOV EBX,EAX // EBX <- Fa Fr Fg Fb
INC ECX // 255:256 range bias
SHR EBX,24 // EBX <- 00 00 00 Fa
IMUL ECX,EBX // ECX <- 00 00 W **
SHR ECX,8 // ECX <- 00 00 00 W
JZ @1 // W = 0 ? => Result := EDX
// P = W * F
MOV EBX,EAX // EBX <- ** Fr Fg Fb
AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
AND EBX,$0000FF00 // EBX <- 00 00 Fg 00
IMUL EAX,ECX // EAX <- Pr ** Pb **
SHR EBX,8 // EBX <- 00 00 00 Fg
IMUL EBX,ECX // EBX <- 00 00 Pg **
ADD EAX,bias
AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
SHR EAX,8 // EAX <- 00 Pr ** Pb
ADD EBX,bias
AND EBX,$0000FF00 // EBX <- 00 00 Pg 00
OR EAX,EBX // EAX <- 00 Pr Pg Pb
// W = 1 - W; Q = W * B
XOR ECX,$000000FF // ECX <- 1 - ECX
MOV EBX,EDX // EBX <- 00 Br Bg Bb
AND EDX,$00FF00FF // EDX <- 00 Br 00 Bb
AND EBX,$0000FF00 // EBX <- 00 00 Bg 00
IMUL EDX,ECX // EDX <- Qr ** Qb **
SHR EBX,8 // EBX <- 00 00 00 Bg
IMUL EBX,ECX // EBX <- 00 00 Qg **
ADD EDX,bias
AND EDX,$FF00FF00 // EDX <- Qr 00 Qb 00
SHR EDX,8 // EDX <- 00 Qr ** Qb
ADD EBX,bias
AND EBX,$0000FF00 // EBX <- 00 00 Qg 00
OR EBX,EDX // EBX <- 00 Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX,EBX // EAX <- 00 Zr Zg Zb
POP EBX
RET
@1: POP EBX
@2: MOV EAX,EDX
RET
end;
procedure _BlendMemEx(F: TColor32; var B: TColor32; M: TColor32);
asm
// EAX <- F
// [EDX] <- B
// ECX <- M
// Check Fa > 0 ?
TEST EAX,$FF000000 // Fa = 0? => write nothing
JZ @2
PUSH EBX
// Get weight W = Fa * M
MOV EBX,EAX // EBX <- Fa Fr Fg Fb
INC ECX // 255:256 range bias
SHR EBX,24 // EBX <- 00 00 00 Fa
IMUL ECX,EBX // ECX <- 00 00 W **
SHR ECX,8 // ECX <- 00 00 00 W
JZ @1 // W = 0 ? => write nothing
PUSH ESI
// P = W * F
MOV EBX,EAX // EBX <- ** Fr Fg Fb
AND EAX,$00FF00FF // EAX <- 00 Fr 00 Fb
AND EBX,$0000FF00 // EBX <- 00 00 Fg 00
IMUL EAX,ECX // EAX <- Pr ** Pb **
SHR EBX,8 // EBX <- 00 00 00 Fg
IMUL EBX,ECX // EBX <- 00 00 Pg **
ADD EAX,bias
AND EAX,$FF00FF00 // EAX <- Pr 00 Pb 00
SHR EAX,8 // EAX <- 00 Pr ** Pb
ADD EBX,bias
AND EBX,$0000FF00 // EBX <- 00 00 Pg 00
OR EAX,EBX // EAX <- 00 Pr Pg Pb
// W = 1 - W; Q = W * B
MOV ESI,[EDX]
XOR ECX,$000000FF // ECX <- 1 - ECX
MOV EBX,ESI // EBX <- 00 Br Bg Bb
AND ESI,$00FF00FF // ESI <- 00 Br 00 Bb
AND EBX,$0000FF00 // EBX <- 00 00 Bg 00
IMUL ESI,ECX // ESI <- Qr ** Qb **
SHR EBX,8 // EBX <- 00 00 00 Bg
IMUL EBX,ECX // EBX <- 00 00 Qg **
ADD ESI,bias
AND ESI,$FF00FF00 // ESI <- Qr 00 Qb 00
SHR ESI,8 // ESI <- 00 Qr ** Qb
ADD EBX,bias
AND EBX,$0000FF00 // EBX <- 00 00 Qg 00
OR EBX,ESI // EBX <- 00 Qr Qg Qb
// Z = P + Q (assuming no overflow at each byte)
ADD EAX,EBX // EAX <- 00 Zr Zg Zb
MOV [EDX],EAX
POP ESI
@1: POP EBX
@2: RET
end;
procedure _BlendLine(Src, Dst: PColor32; Count: Integer);
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;
procedure _CombineLine(Src, Dst: PColor32; Count: Integer; W: TColor32);
begin
while Count > 0 do
begin
_CombineMem(Src^, Dst^, W);
Inc(Src);
Inc(Dst);
Dec(Count);
end;
end;
{ MMX versions }
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);
end;
procedure EMMS;
begin
if MMX_ACTIVE then
asm
db $0F,$77 /// EMMS
end;
end;
function M_CombineReg(X, Y, W: TColor32): TColor32;
asm
// EAX - Color X
// EDX - Color Y
// ECX - Weight of X [0..255]
// Result := W * (X - Y) + Y
db $0F,$6E,$C8 /// MOVD MM1,EAX
db $0F,$EF,$C0 /// PXOR MM0,MM0
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -