📄 gr32_blend.pas
字号:
unit GR32_Blend;
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Graphics32
*
* The Initial Developer of the Original Code is
* Alex A. Denisov
*
* Portions created by the Initial Developer are Copyright (C) 2000-2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mattias Andersson
* - 2004/07/07 - MMX Blendmodes
* - 2004/12/10 - _MergeReg, M_MergeReg
*
* Michael Hansen <dyster_tid@hotmail.com>
* - 2004/07/07 - Pascal Blendmodes, function setup
* - 2005/08/19 - New merge table concept and reference implementations
*
* Bob Voigt
* - 2004/08/25 - ColorDiv
*
* ***** END LICENSE BLOCK ***** *)
interface
{$I GR32.inc}
uses
GR32, SysUtils;
var
MMX_ACTIVE: Boolean;
procedure EMMS;
type
{ Function Prototypes }
TCombineReg = function(X, Y, W: TColor32): TColor32;
TCombineMem = procedure(F: TColor32; var B: TColor32; W: TColor32);
TBlendReg = function(F, B: TColor32): TColor32;
TBlendMem = procedure(F: TColor32; var B: TColor32);
TBlendRegEx = function(F, B, M: TColor32): TColor32;
TBlendMemEx = procedure(F: TColor32; var B: TColor32; M: TColor32);
TBlendLine = procedure(Src, Dst: PColor32; Count: Integer);
TBlendLineEx = procedure(Src, Dst: PColor32; Count: Integer; M: TColor32);
TCombineLine = procedure(Src, Dst: PColor32; Count: Integer; W: TColor32);
var
{ Function Variables }
CombineReg: TCombineReg;
CombineMem: TCombineMem;
BlendReg: TBlendReg;
BlendMem: TBlendMem;
BlendRegEx: TBlendRegEx;
BlendMemEx: TBlendMemEx;
BlendLine: TBlendLine;
BlendLineEx: TBlendLineEx;
CombineLine: TCombineLine;
MergeReg: TBlendReg;
MergeMem: TBlendMem;
MergeRegEx: TBlendRegEx;
MergeMemEx: TBlendMemEx;
MergeLine: TBlendLine;
MergeLineEx: TBlendLineEx;
{ Access to alpha composite functions corresponding to a combine mode }
BLEND_REG: array[TCombineMode] of TBlendReg;
BLEND_MEM: array[TCombineMode] of TBlendMem;
BLEND_REG_EX: array[TCombineMode] of TBlendRegEx;
BLEND_MEM_EX: array[TCombineMode] of TBlendMemEx;
BLEND_LINE: array[TCombineMode] of TBlendLine;
BLEND_LINE_EX: array[TCombineMode] of TBlendLineEx;
{ Color algebra functions }
ColorAdd: TBlendReg;
ColorSub: TBlendReg;
ColorDiv: TBlendReg;
ColorModulate: TBlendReg;
ColorMax: TBlendReg;
ColorMin: TBlendReg;
ColorDifference: TBlendReg;
ColorAverage: TBlendReg;
ColorExclusion: TBlendReg;
ColorScale: TBlendReg;
{ Special LUT pointers }
AlphaTable: Pointer;
bias_ptr: Pointer;
alpha_ptr: Pointer;
{ Misc stuff }
function Lighten(C: TColor32; Amount: Integer): TColor32;
//SAARIXX
var
RcTable: array [Byte, Byte] of Byte;
DivTable: array [Byte, Byte] of Byte;
implementation
uses Math, GR32_System, GR32_LowLevel, GR32_Math;
{ Merge }
function _MergeReg(F, B: TColor32): TColor32;
asm
// EAX <- F
// EDX <- B
// GR32_Blend.pas.156: if F.A = 0 then
test eax,$ff000000
jz @exit0
// GR32_Blend.pas.160: else if B.A = 255 then
cmp edx,$ff000000
jnc @blend
// GR32_Blend.pas.158: else if F.A = 255 then
cmp eax,$ff000000
jnc @exit
// else if B.A = 0 then
test edx,$ff000000
jz @exit
@4:
push ebx
push esi
push edi
add esp,-$0c
mov [esp+$04],edx
mov [esp],eax
// AH <- F.A
// DL, CL <- B.A
shr eax,16
and eax,$0000ff00
shr edx,24
mov cl,dl
nop
nop
nop
// EDI <- PF
// EDX <- PB
// ESI <- PR
// GR32_Blend.pas.164: PF := @DivTable[F.A];
lea edi,[eax+DivTable]
// GR32_Blend.pas.165: PB := @DivTable[B.A];
shl edx,$08
lea edx,[edx+DivTable]
// GR32_Blend.pas.166: Result.A := B.A + F.A - PB[F.A];
shr eax,8
//add cl,al
add ecx,eax
//sub cl,[edx+eax]
sub ecx,[edx+eax]
mov [esp+$0b],cl
// GR32_Blend.pas.167: PR := @RcTable[Result.A];
shl ecx,$08
and ecx,$0000ffff
lea esi,[ecx+RcTable]
{ Red component }
// GR32_Blend.pas.169: Result.R := PB[B.R];
xor eax,eax
mov al,[esp+$06]
mov cl,[edx+eax]
mov [esp+$0a],cl
// GR32_Blend.pas.170: X := F.R - Result.R;
mov al,[esp+$02]
xor ebx,ebx
mov bl,cl
sub eax,ebx
// GR32_Blend.pas.171: if X >= 0 then
jl @5
// GR32_Blend.pas.172: Result.R := PR[PF[X] + Result.R]
movzx eax,byte ptr[edi+eax]
and ecx,$000000ff
add eax,ecx
mov al,[esi+eax]
mov [esp+$0a],al
jmp @6
@5:
// GR32_Blend.pas.252: Result.R := PR[Result.R - PF[-X]];
neg eax
movzx eax,byte ptr[edi+eax]
xor ecx,ecx
mov cl,[esp+$0a]
sub ecx,eax
mov al,[esi+ecx]
mov [esp+$0a],al
{ Green component }
@6:
// GR32_Blend.pas.176: Result.G := PB[B.G];
xor eax,eax
mov al,[esp+$05]
mov cl,[edx+eax]
mov [esp+$09],cl
// GR32_Blend.pas.177: X := F.G - Result.G;
mov al,[esp+$01]
xor ebx,ebx
mov bl,cl
sub eax,ebx
// GR32_Blend.pas.178: if X >= 0 then
jl @7
// GR32_Blend.pas.179: Result.G := PR[PF[X] + Result.G]
movzx eax,byte ptr[edi+eax]
and ecx,$000000ff
add eax,ecx
mov al,[esi+eax]
mov [esp+$09],al
jmp @8
@7:
// GR32_Blend.pas.259: Result.G := PR[Result.G - PF[-X]];
neg eax
movzx eax,byte ptr[edi+eax]
xor ecx,ecx
mov cl,[esp+$09]
sub ecx,eax
mov al,[esi+ecx]
mov [esp+$09],al
{ Blue component }
@8:
// GR32_Blend.pas.183: Result.B := PB[B.B];
xor eax,eax
mov al,[esp+$04]
mov cl,[edx+eax]
mov [esp+$08],cl
// GR32_Blend.pas.184: X := F.B - Result.B;
mov al,[esp]
xor edx,edx
mov dl,cl
sub eax,edx
// GR32_Blend.pas.185: if X >= 0 then
jl @9
// GR32_Blend.pas.186: Result.B := PR[PF[X] + Result.B]
movzx eax,byte ptr[edi+eax]
xor edx,edx
mov dl,cl
add eax,edx
mov al,[esi+eax]
mov [esp+$08],al
jmp @10
@9:
// GR32_Blend.pas.266: Result.B := PR[Result.B - PF[-X]];
neg eax
movzx eax,byte ptr[edi+eax]
xor edx,edx
mov dl,cl
sub edx,eax
mov al,[esi+edx]
mov [esp+$08],al
@10:
// EAX <- Result
mov eax,[esp+$08]
// GR32_Blend.pas.190: end;
add esp,$0c
pop edi
pop esi
pop ebx
ret
@blend:
call dword ptr [BlendReg]
or eax,$ff000000
ret
@exit0:
mov eax,edx
@exit:
end;
function _MergeRegEx(F, B, M: TColor32): TColor32;
begin
Result := _MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
end;
procedure _MergeMem(F: TColor32; var B: TColor32);
begin
B := _MergeReg(F, B);
end;
procedure _MergeMemEx(F: TColor32; var B: TColor32; M: TColor32);
begin
B := _MergeReg(DivTable[M, F shr 24] shl 24 or F and $00FFFFFF, B);
end;
procedure _MergeLine(Src, Dst: PColor32; Count: Integer);
begin
while Count > 0 do
begin
Dst^ := _MergeReg(Src^, Dst^);
Inc(Src);
Inc(Dst);
Dec(Count);
end;
end;
procedure _MergeLineEx(Src, Dst: PColor32; Count: Integer; M: TColor32);
var
PM: PByteArray absolute M;
begin
PM := @DivTable[M];
while Count > 0 do
begin
Dst^ := _MergeReg(PM[Src^ shr 24] shl 24 or Src^ and $00FFFFFF, Dst^);
Inc(Src);
Inc(Dst);
Dec(Count);
end;
end;
{ Non-MMX versions }
const bias = $00800080;
function _CombineReg(X, Y, W: TColor32): TColor32;
asm
// 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)
// EAX <- X
// EDX <- Y
// ECX <- W
// W = 0 or $FF?
JCXZ @1 // CX = 0 ? => Result := EDX
CMP ECX,$FF // CX = $FF ? => Result := EDX
JE @2
PUSH EBX
// P = W * X
MOV EBX,EAX // EBX <- Xa Xr Xg Xb
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 <- Pa 00 Pg 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;
procedure _CombineMem(F: TColor32; var B: TColor32; W: TColor32);
asm
// EAX <- F
// [EDX] <- B
// ECX <- W
// Check W
JCXZ @1 // W = 0 ? => write nothing
CMP ECX,$FF // W = 255? => write F
JZ @2
PUSH EBX
PUSH ESI
// P = W * F
MOV EBX,EAX // EBX <- ** 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 <- 00 00 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 <- 00 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 **
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -