This routine is a windowed get/put-sprite emulation-routine. I'm Italian and I've not translated them. This routine is capable to flip-x-y the image before storing it in a 16 Byte aligned buffer. I omitted the precalculation routine for reasons of confidentiality. I learned thanks to the advice of Peter Cordes to fully use the LEA statement and is the first personal implementation of the ASSEMBLER 'BT' instruction:
Procedure Sub_MoveSprite; Assembler;
(* Sub-ROUTINE per MoveSprite (FlipX-FlipY).
INPUT:
EAX= Attributi immagine.
EBX= Scarto X per origine.
ECX= Quantità X di Pixel per LINEA.
EDX= Quantità Y di linee da trasf.
EBP= Scarto X per destinazione.
ESI= OFFSET per origine.
EDI= OFFSET per destinaz *)
Asm
Push EBP
Push EBX
Push ECX
BT EAX,Def_Target_DirX_D
SbB EBP,EBP
LEA EBP,[2*EBP+1]
BT EAX,Def_Source_DirX_D
SbB EBX,EBX
LEA EBX,[2*EBX+1]
@@01:Mov AL,[ESI]
Cmp AL,AH
JE @@00
Mov [EDI],AL
@@00:Add ESI,EBX
Add EDI,EBP
Loop @@01
Mov ECX,[ESP]
Add ESI,[ESP+4]
Add EDI,[ESP+8]
Dec EDX
JNE @@01
Add ESP,12
End;
How can it be optimized? For example, subdividing it into several sub-routines: In this case I don't flip on Y axis the image:
Procedure Sub_MoveSprite_FX0; Assembler;
{Sub-ROUTINE per MoveSprite (FlipY).
INPUT:
EAX= Attributi immagine.
EBX= Scarto X per origine.
ECX= Quantità X di Pixel per LINEA.
EDX= Quantità Y di linee da trasf.
EBP= Scarto X per destinazione.
ESI= OFFSET per origine.
EDI= OFFSET per destinaz}
Asm
ClD
Push ECX
@@01:LodSB
Cmp AL,AH
JE @@00
Mov [EDI],AL
@@00:Inc EDI
Loop @@01
Mov ECX,[ESP]
Add ESI,EBX
Add EDI,EBP
Dec EDX
JNE @@01
Add ESP,4
End;
Now there is here complete code of my optimization, without suggestions:
Procedure PutImage_FullClipp; Assembler;
{Calcola la CLIPPING REGION.
INPUT:
-----:
EAX : Byte_0 = BkCol, nuovo colore sfondo OBPVBuff (Ex simmetria verticale).
Byte_1 = SpCol, nuovo colore sfondo SPRITE.
Byte_2 = MaskCol, colore maschera/FIGURA.
Byte_3 = Attributi EXTRA:
Bit0= 0 -> Col. predef. dello sfondo di OBPVBuff.
1 -> Il Col. dello sfondo di OBPVBuff è BkCol.
Bit1= 0 -> Col. predef. dello sfondo.
1 -> Il Col. dello sfondo è SpCol.
Bit2= 0 -> Rappresenta lo SPRITE.
1 -> Rappresenta lo sfondo dello SPRITE.
Bit3= 0 -> L' immagine non è uno SPRITE.
1 -> L' immagine è uno SPRITE;
Bit4= 0 -> L' immag. non è uno maschera.
1 -> L' immag. è uno maschera di colore MaskCol.
Bit5= 0 -> Put-IMAGE.
1 -> Get-IMAGE.
Bit6= 0 -> Nessuna simmetria orizzontale.
1 -> Simmetria orizzontale.
Bit7= 0 -> Nessuna simmetria verticale.
1 -> Simmetria verticale.
EBX = Dimensioni X e Y della finestra sul BUFFER VIDEO
(specif. 0, la Dim. sarà consid. = a quella del BUFFER VIDEO).
ECX = COORDINATE X e Y dell' immagine OBP di origine.
EDX = COORDINATE X e Y della finestra sul BUFFER VIDEO.
ESI = PUNTATORE all' immagine OBP di origine.
EDI = PUNTATORE al BUFFER VIDEO OBP di destinazione.
OUTPUT:
------:
EAX : Byte_0 = Colore sfondo OBPVBuff.
Byte_1 = Colore sfondo SPRITE.
Byte_2 = MaskCol, colore maschera/FIGURA.
Byte_3 = Attributi EXTRA:
Bit0= 0 -> Il dithering inizia per 0.
1 -> Il dithering inizia per 1.
Bit1= 0 -> Col. predef. dello sfondo.
1 -> Il Col. dello sfondo è SpCol.
Bit2= 0 -> Rappresenta lo SPRITE.
1 -> Rappresenta lo sfondo dello SPRITE.
Bit3= 0 -> L' immagine non è uno SPRITE.
1 -> L' immagine è uno SPRITE;
Bit4= 0 -> L' immag. non è uno maschera.
1 -> L' immag. è uno maschera di colore MaskCol.
Bit5= 0 -> Put-IMAGE.
1 -> Get-IMAGE.
Bit6= 0 -> Incremento X destinazione = 1.
1 -> Incremento X destinazione (FlipX) = -1.
Bit7= 0 -> Incremento X origine = 1.
1 -> Incremento X origine (FlipX)= -1.
EBX = Scarto X per origine.
ECX = Quantità X di Pixel per LINEA.
EDX = Quantità Y di linee.
EBP = Scarto X per destinazione.
ESI = PUNTATORE ai dati da trasferire per l' origine.
EDI = PUNTATORE alla destinazione dei dati da trasferire.
FCarry = 1 -> ERRORE, i registri di OUTPUT
non contengono valori attendibili.
= 0 -> Ok, tutti i registri di OUTPUT
contengono valori attendibili}
Asm
Sub ESP,60 {Definisce le variabili locali sullo STACK}
(* Attr {[ESP+00]: Attributi SPRITE}
X {[ESP+04]: COORDINATA X immagine da trasferire}
Y {[ESP+08]: COORDINATA Y immagine da trasferire}
DimX {[ESP+12]: Dimensione X immagine da trasferire}
DimY {[ESP+16]: Dimensione Y immagine da trasferire}
WindX {[ESP+20]: COORDINATA X finestra sul BUFFER VIDEO}
WindY {[ESP+24]: COORDINATA Y finestra sul BUFFER VIDEO}
DimWindX {[ESP+28]: Dimensione X finestra sul BUFFER VIDEO}
DimWindY {[ESP+32]: Dimensione Y finestra sul BUFFER VIDEO}
ADimX {[ESP+36]: Dimens. X immagine da trasf. allineata ai 16 BYTE}
ADimScrX {[ESP+40]: Dimensione X BUFFER VIDEO allineata ai 16 BYTE}
SourcePtr {[ESP+44]: PUNTATORE all' immagine OBP di origine}
TargetPtr {[ESP+48]: PUNTATORE alla destinazione dei dati da trasferire}
FlipX {[ESP+52]: Maschera x simmetria orizzontale}
FlipY {[ESP+56]: Maschera x simmetria verticale} *)
{Preparazione iniziale e controllo coerenza parametri}
{ SI<1 | DI<1 | CL | FSign
-------+--------+----------+-------
0 | 0 | -0 -0 0 | 0
0 | 1 | -0 -1 -1 | 1
1 | 0 | -1 -0 -1 | 1
1 | 1 | -1 -1 -2 | 1
-------+--------+----------+-------}
Cmp ESI,1 {Se IMAGE=NIL, ...}
SbB EBP,EBP {... EBP vale -1, altrim. vale 0}
Cmp EDI,1 {Se OBPVBuff=NIL, ...}
SbB EBP,0 {... EBP vale EBP-1, altrim. vale EBP}
StC {Se IMAGE=NIL o se OBPVBuff=NIL, imposta FCarry=1 ...}
JS @@Ex {... ed esce}
{-----------------------------------}
Mov EBP,[ESI] {Carica Dim_XY(IMAGE) IN EBP}
Add ESI,DimOBP_H {ESI punta all' area dati di IMAGE}
Mov [ESP+44],ESI {Salva ESI su SourcePtr}
{-----------------------------------}
MovSX ESI,BP {Estende con SEGNO ...}
Or ESI,ESI {... la Dim. X di IMAGE IN ESI; ...}
StC {... se è <=0, imposta FCarry=1 ...}
JLE @@Ex {... ed esce}
Or EBP,EBP {Estende con SEGNO ...}
SAR EBP,16 {... la Dim. Y di IMAGE IN EBP; ...}
StC {... se è <=0, imposta FCarry=1 ...}
JLE @@Ex {... ed esce}
{-----------------------------------}
Mov [ESP+12],ESI {Salva la Dim. X di IMAGE con 0 esteso su DimX}
Mov [ESP+16],EBP {Salva la Dim. Y di IMAGE con 0 esteso su DimY}
{-----------------------------------}
Mov EBP,ESI {Calcola, IN EBP, la Dim. X di IMAGE ...}
And EBP,R_OBP_Al-1 {...}
Neg EBP {...}
Add EBP,R_OBP_Al {...}
And EBP,R_OBP_Al-1 {...}
Add EBP,ESI {... allineata ai 16 BYTE e ...}
Mov [ESP+36],EBP {... la salva su ADimX}
{-----------------------------------}
Mov ESI,[EDI] {Carica Dim_XY(OBPVBuff) IN ESI}
Add EDI,DimOBP_H {EDI punta all' area dati di OBPVBuff}
Mov [ESP+48],EDI {Salva EDI su TargetPtr}
{-----------------------------------}
MovSX EDI,SI {Estende con SEGNO ...}
Or EDI,EDI {... la Dim. X di OBPVBuff IN EDI; ...}
StC {... se è <=0, imposta FCarry=1 ...}
JLE @@Ex {... ed esce}
Or ESI,ESI {Estende con SEGNO ...}
SAR ESI,16 {... la Dim. Y di OBPVBuff IN ESI; ...}
StC {... se è <=0, imposta FCarry=1 ...}
JLE @@Ex {... ed esce}
{-----------------------------------}
Test EAX,_Def_Attr_New_BkCol {Se il Bit0 di Attr.MODE <> 0 ...}
JNE @@00 {... usa il nuovo colore dello sfondo di OBPVBuff}
Mov EBP,[ESP+48] {Carica TargetPtr IN EBP e ...}
Mov AL,[EBP] {... carica IN AL il colore sfondo di OBPVBuff}
@@00:Test EAX,_Def_Attr_New_SpCol {Se il Bit1 di Attr.MODE <> 0 ...}
JNE @@01 {... usa il nuovo colore dello sfondo di IMAGE}
Mov EBP,[ESP+44] {Carica SourcePtr IN EBP e ...}
Mov AH,[EBP] {... carica IN AH il colore sfondo di IMAGE}
@@01:BT EAX,Def_Attr_FlipY_D {Bit7(Attr.MODE)<>0? Si: FCarry=1; no: FCarry=0}
SbB EBP,EBP {Se Bit7 di Attr.MODE <>0, EBP=-1, altrim. EBP=0}
Mov [ESP+56],EBP {Imposta FlipY=EBP}
BT EAX,Def_Attr_FlipX_D {Bit6(Attr.MODE)<>0? Si: FCarry=1; no: FCarry=0}
SbB EBP,EBP {Se Bit6 di Attr.MODE <>0, EBP=-1, altrim. EBP=0}
Mov [ESP+52],EBP {Imposta FlipX=EBP}
And EBP,_Def_Target_DirX {EBP contiene il Bit6 di Attr.MODE}
And EAX,-1-_Def_Source_DirX-_Def_Dither {CANC. Bit0 e Bit7 di Attr.MODE}
Test EAX,_Def_Attr_Get_Image {Se il Bit5 di Attr.MODE=0 ...}
JE @@02 {... salta}
XChg AL,AH {Scambia i colori dello sfondo di IMAGE e OBPVBuff}
Add EAX,EBP {Scambia il Bit6 Col Bit7 di Attr.MODE}
@@02:Mov [ESP],EAX {Salva Attr.MODE su Attr}
{-----------------------------------}
Mov EAX,EDI {Calcola, IN EAX, la Dim. X di OBPVBuff ...}
And EAX,R_OBP_Al-1 {...}
Neg EAX {...}
Add EAX,R_OBP_Al {...}
And EAX,R_OBP_Al-1 {...}
Add EAX,EDI {... allineata ai 16 BYTE e ...}
Mov [ESP+40],EAX {... la salva su ADimScrX}
{-----------------------------------}
MovSX EAX,CX {Calcola, IN EAX, la coord. X di IMAGE, ...}
Mov [ESP+4],EAX {... con SEGNO esteso e la salva su X}
Or ECX,ECX {Calcola, IN ECX, la coord. Y di IMAGE, ...}
SAR ECX,16 {... con SEGNO esteso e ...}
Mov [ESP+8],ECX {... la salva su Y}
{-----------------------------------}
MovSX EAX,DX {Estende con SEGNO la coord. X ...}
Or EAX,EAX {... della finestra sul BUFFER VIDEO IN EAX; ...}
StC {... se è <0, imposta FCarry=1 ...}
JS @@Ex {... ed esce}
Or EDX,EDX {Estende con SEGNO la coord. Y ...}
SAR EDX,16 {... della finestra sul BUFFER VIDEO IN EDX; ...}
StC {... se è <0, imposta FCarry=1 ...}
JS @@Ex {... ed esce}
{-----------------------------------}
Mov [ESP+20],EAX {Salva la coord. X fin. BUFFER Vid. con 0 e. su WindX}
Mov [ESP+24],EDX {Salva la coord. Y fin. BUFFER Vid. con 0 e. su WindY}
{-----------------------------------}
MovSX ECX,BX {Estende con SEGNO la dimens. X ...}
Or ECX,ECX {... della finestra sul BUFFER VIDEO IN ECX; ...}
StC {... se è <0, imposta FCarry=1 ...}
JS @@Ex {... ed esce}
JNE @@03 {Se la dimens. X della finestra sul BUFFER VIDEO ...}
Mov ECX,EDI {... è =0, la imposta con la Dim. X di OBPVBuff}
@@03:Add EAX,ECX {Se la coord. X della finestra sul BUFFER VIDEO ...}
Cmp EDI,EAX {... più la Dim. X finestra sul BUFFER VIDEO ...}
JB @@Ex {... > Dim. X di OBPVBuff, esce (FCarry=1)}
{-----------------------------------}
Or EBX,EBX {Estende con SEGNO la dimens. Y ...}
SAR EBX,16 {... della finestra sul BUFFER VIDEO IN EBX ...}
StC {... se è <0, imposta FCarry=1 ...}
JS @@Ex {... ed esce}
JNE @@04 {Se la dimens. Y della finestra sul BUFFER VIDEO ...}
Mov EBX,ESI {... è =0, la imposta con Dim. Y di OBPVBuff}
@@04:Add EDX,EBX {Se la coord. Y della finestra sul BUFFER VIDEO ...}
Cmp ESI,EDX {... più la Dim. Y finestra sul BUFFER VIDEO ...}
JB @@Ex {... > Dim. Y di OBPVBuff, esce (FCarry=1)}
{-----------------------------------}
Mov [ESP+28],ECX {Salva la Dim.X fin. BUFFER Vid. con 0 e. su DimWindX}
Mov [ESP+32],EBX {Salva la Dim.Y fin. BUFFER Vid. con 0 e. su DimWindY}
{Calcola scarti XLow (ESI) e XHigh (ECX)}
Mov EDI,[ESP+4] {Carica, IN EDI, la coord. X di IMAGE}
Mov EBX,[ESP+12] {Carica, IN EBX, la Dim. X di IMAGE}
XOr ESI,ESI {Imposta XLow=0}
XOr ECX,ECX {Imposta XHigh=0}
Or EDI,EDI {Se EDI>=0 ...}
JNS @@05 {... salta}
Add EDI,EBX {Imposta EDI=EDI+EBX; ...}
StC {... se EDI<0, ...}
JS @@Ex {... imposta FCarry=1 ed esce}
Mov ESI,[ESP+4] {Imposta XLow con la coord. X di IMAGE}
Neg ESI {Imposta XLow=-XLow}
Mov DWord Ptr [ESP+4],0 {Imposta la coord. X di IMAGE a 0}
Jmp @@06 {Salta}
@@05:Cmp EDI,[ESP+28] {Se EDI>=Dim. X della finestra su OBPVBuff ...}
CmC {...}
JB @@Ex {... imposta FCarry=1 ed esce}
Add EDI,EBX {Imposta EDI=EDI+EBX}
@@06:Cmp EDI,[ESP+28] {Se EDI<=Dim. X della finestra su OBPVBuff ...}
JBE @@07 {... salta}
Mov ECX,EDI {Imposta ...}
Sub ECX,[ESP+28] {... XHigh=EDI-Dim. X della finestra su OBPVBuff}
{Calcola scarti YLow (EDI) e YHigh (EBX)}
@@07:Mov EAX,[ESP+8] {Carica, IN EAX, la coord. Y di IMAGE}
Mov EDX,[ESP+16] {Carica, IN EDX, la Dim. Y di IMAGE}
XOr EDI,EDI {Imposta YLow=0}
XOr EBX,EBX {Imposta YHigh=0}
Or EAX,EAX {Se EAX>=0 ...}
JNS @@08 {... salta}
Add EAX,EDX {Imposta EAX=EAX+EDX; ...}
StC {... se EAX<0, ...}
JS @@Ex {... imposta FCarry=1 ed esce}
Mov EDI,[ESP+8] {Imposta YLow con la coord. Y di IMAGE}
Neg EDI {Imposta YLow=-YLow}
Mov DWord Ptr [ESP+8],0 {Imposta la coord. Y di IMAGE a 0}
Jmp @@09 {Salta}
@@08:Cmp EAX,[ESP+32] {Se EAX>=Dim. Y della finestra su OBPVBuff ...}
CmC {...}
JB @@Ex {... imposta FCarry=1 ed esce}
Add EAX,EDX {Imposta EAX=EAX+EDX}
@@09:Cmp EAX,[ESP+32] {Se EAX<=Dim. Y della finestra su OBPVBuff ...}
JBE @@10 {... salta}
Mov EBX,EAX {Imposta ...}
Sub EBX,[ESP+32] {... YHigh=EAX-Dim. Y della finestra su OBPVBuff}
{Prepara i registri di OUTPUT EAX, EBX, ECX, EDX, EDI, ESI}
@@10:Cmp DWord Ptr [ESP+56],-1 {Se FlipY=-1 ...}
Mov EAX,EDI {...}
CMovE EDI,EBX {...}
CMovE EBX,EAX {... scambia YHigh con YLow}
{-----------------------------------}
Add EBX,EDI { EBX= YHigh+YLow}
Neg EBX { EBX= -YHigh-YLow}
Add EBX,[ESP+16] { EBX= DimY-YHigh-YLow; N.righe da trasf.}
StC {Se non CI sono righe da trasf., FCarry=1 ...}
JE @@Ex {... esce}
{-----------------------------------}
Cmp DWord Ptr [ESP+52],-1 {Se FlipX=-1 ...}
Mov EAX,ESI {...}
CMovE ESI,ECX {...}
CMovE ECX,EAX {... scambia XHigh con XLow}
{-----------------------------------}
Add ECX,ESI { ECX= XHigh+XLow}
Neg ECX { ECX= -XHigh-XLow}
Add ECX,[ESP+12] { ECX= DimX-XHigh-XLow; N.Col. da trasf.}
StC {Se non CI sono colonne da trasf., FCarry=1 ...}
JE @@Ex {... esce}
{-----------------------------------}
Mov EBP,ESI { EBP= XLow}
XOr EBP,EDI { EBP= XLow ^ YLow}
And EBP,1 { EBP= (XLow ^ YLow) & 1}
ShL EBP,Def_Dither_D { EBP= ((XLow ^ YLow) & 1)<<24}
Or [ESP],EBP { Attr.MODE= Attr.MODE | ((XLow ^ YLow) & 1)}
{-----------------------------------}
Mov EBP,ECX { EBP= -XLow-XHigh+DimX}
Dec EBP { EBP= -XLow-XHigh+DimX-1}
And EBP,[ESP+52] { EBP= (-XLow-XHigh+DimX-1) & FlipX}
Add EBP,[ESP+4] { EBP= X+[-XLow-XHigh+DimX-1]}
Add EBP,[ESP+20] { EBP= X+[-XLow-XHigh+DimX-1]+WindX}
Mov EAX,EBX { EAX= -YLow-YHigh+DimY}
Dec EAX { EAX= -YLow-YHigh+DimY-1}
And EAX,[ESP+56] { EAX= (-YLow-YHigh+DimY-1) & FlipY}
Add EAX,[ESP+8] { EAX= Y+[-YLow-YHigh+DimY-1]}
Add EAX,[ESP+24] { EAX= Y+[-YLow-YHigh+DimY-1]+WindY}
Mul DWord Ptr [ESP+40] {EDX:EAX= (Y+[-YLow-YHigh+DimY-1]+WindY)*ADimScrX}
Add EAX,EBP { EAX= (Y+[-YLow-YHigh+DimY-1]+WindY)*ADimScrX+ ...}
{... +X+[-XLow-XHigh+DimX-1]+WindX}
Add [ESP+48],EAX {TargetPtr=(Y+[-YLow-YHigh+DimY-1]+WindY)*ADimScrX+...}
{... +X+[-XLow-XHigh+DimX-1]+WindX+TargetPtr}
{-----------------------------------}
Mov EAX,EDI { EAX= YLow}
Mul DWord Ptr [ESP+36] {EDX:EAX= YLow*ADimX}
Add EAX,ESI { EAX= YLow*ADimX+XLow}
Add [ESP+44],EAX {SourcePtr=YLow*ADimX+XLow+SourcePtr}
{-----------------------------------}
Mov EDX,EBX { EDX= DimY-YHigh-YLow; N.righe da trasf.}
Mov EBX,ECX { EBX= DimX-XHigh-XLow}
Neg EBX { EBX= -DimX+XHigh+XLow}
Mov EAX,EBX { EAX= -DimX+XHigh+XLow}
Add EBX,[ESP+36] { EBX= -DimX+XHigh+XLow+ADimX; scarto X per Orig}
Add EAX,[ESP+40] { EAX=-DimX+XHigh+XLow+ADimScrX; scarto X per Dest}
(* SX= Scarto X per Dest. (EAX)
NCol= N.Col. da trasf. (ECX)
------+-------+---------------
FlipX | FlipY | ScartoXDest
0 | 0 | SX
0 | -1 | -2*NCol-SX)
-1 | 0 | 2*NCol+SX
-1 | -1 | -SX *)
LEA EDI,[2*ECX] { EDI= 2*ECX}
Mov EBP,[ESP+52] { ...}
XOr EBP,[ESP+56] {... EBP= FlipX ^ FlipY}
And EDI,EBP { EDI= 2*NCol & (FlipX ^ FlipY)}
Add EAX,EDI { EAX= SX+2*NCol & (FlipX ^ FlipY)}
XOr EAX,[ESP+56] {Se FlipY=-1 allora EAX=-EAX ...}
Sub EAX,[ESP+56] {... altrimenti EAX è inalterato}
Mov EBP,EAX { EBP= Scarto X per Dest}
Mov EDI,[ESP+48] { EDI= PTR Dest.}
Mov ESI,[ESP+44] { ESI= PTR Orig.}
Mov EAX,[ESP] { EAX= Attr}
Test EAX,_Def_Attr_Get_Image {Se il Bit5 di Attr.MODE=0 ...}
JE @@Ex {... salta}
XChg ESI,EDI { Scambia PTR Orig. con PTR Dest.}
XChg EBX,EBP { Scambia scarto X per Orig. con scarto X per Dest}
ClC { FCarry=0; nessun ERRORE}
{-----------------------------------}
@@Ex:LEA ESP,[ESP+60] { Reimposta lo STACK-POINTER; esce}
End;
Procedure MoveImage(Image:T_Image_Ptr;
Prop:T_Long_Attrib_Ptr;
OBPVBuff:Pointer;
Clipp:T_Clipp_Rect_Ptr); Assembler;
{Disegna un immagine con CLIPPING REGION.
INPUT:
EAX = PUNTATORE a RECORD di definizione dell' immagine.
EDX = PUNTATORE alle proprietà dell' immagine.
ECX = PUNTATORE al BUFFER VIDEO IN formato OBP.
Clipp = PUNTATORE al RECORD della CLIPPING REGION.
PARAMETERs order:
1°=EAX; 2°=EDX; 3°=ECX}
Asm
Push EBX
Push EDI
Push ESI
Push EBP
Mov ESI,Image {EAX}
Mov EBX,Prop {EDX}
Mov EDI,OBPVBuff {ECX}
Mov EDX,Clipp
Mov EAX,EBX
Or EBX,EBX
JE @@00
Mov EAX,[EBX]
Mov EBX,[EBX+4]
@@00:Push EBX
Or ESI,ESI
JE @@01
Mov ECX,[ESI]
Mov ESI,[ESI+4]
Mov EBX,EDX
Or EDX,EDX
JE @@02
Mov EDX,[EBX] {Clipp.XY}
Mov EBX,[EBX+4] {Clipp.Dim_XY}
@@02:Call PutImage_FullClipp
JB @@01
(* _DirX | _Sprite | ShadowTable | _Mask | _BackG | FUNCTION
------+---------+-------------+-------+--------+---------
0 | 0 | 0 | 0 | 0 | Sub_MoveImage_FX0
0 | 0 | 0 | 0 | 1 | Sub_MoveImage_FX0
0 | 0 | 0 | 1 | 0 | Sub_MoveImageMask_FX0
0 | 0 | 0 | 1 | 1 | Sub_MoveImageMask_FX0
0 | 0 | 1 | 0 | 0 | Sub_MoveImageShadow_FX0
0 | 0 | 1 | 0 | 1 | Sub_MoveImageShadow_FX0
0 | 0 | 1 | 1 | 0 | Sub_MoveImageShadow_FX0
0 | 0 | 1 | 1 | 1 | Sub_MoveImageShadow_FX0
0 | 1 | 0 | 0 | 0 | Sub_MoveSprite_FX0
0 | 1 | 0 | 0 | 1 | Sub_MoveSpriteBk_FX0
0 | 1 | 0 | 1 | 0 | Sub_MoveSpriteMask_FX0
0 | 1 | 0 | 1 | 1 | Sub_MoveSpriteBkMsk_FX0
0 | 1 | 1 | 0 | 0 | Sub_MoveSpriteShad_FX0
0 | 1 | 1 | 0 | 1 | Sub_MoveSprBkShad_FX0
0 | 1 | 1 | 1 | 0 | Sub_MoveSpriteShad_FX0
0 | 1 | 1 | 1 | 1 | Sub_MoveSprBkShad_FX0
1 | 0 | 0 | 0 | 0 | Sub_MoveImage
1 | 0 | 0 | 0 | 1 | Sub_MoveImage
1 | 0 | 0 | 1 | 0 | Sub_MoveImageMask
1 | 0 | 0 | 1 | 1 | Sub_MoveImageMask
1 | 0 | 1 | 0 | 0 | Sub_MoveImageShadow
1 | 0 | 1 | 0 | 1 | Sub_MoveImageShadow
1 | 0 | 1 | 1 | 0 | Sub_MoveImageShadow
1 | 0 | 1 | 1 | 1 | Sub_MoveImageShadow
1 | 1 | 0 | 0 | 0 | Sub_MoveSprite
1 | 1 | 0 | 0 | 1 | Sub_MoveSpriteBk
1 | 1 | 0 | 1 | 0 | Sub_MoveSpriteMask
1 | 1 | 0 | 1 | 1 | Sub_MoveSpriteBkMask
1 | 1 | 1 | 0 | 0 | Sub_MoveSpriteShadow
1 | 1 | 1 | 0 | 1 | Sub_MoveSpriteBkShadow
1 | 1 | 1 | 1 | 0 | Sub_MoveSpriteShadow
1 | 1 | 1 | 1 | 1 | Sub_MoveSpriteBkShadow *)
Test EAX,_Def_DirX
JE @@03
Test EAX,_Def_Attr_Sprite
JNE @@04
Cmp DWord Ptr [ESP],0
JNE @@05
Test EAX,_Def_Attr_Mask
JNE @@06
Call Sub_MoveImage
Jmp @@01
@@06:Call Sub_MoveImageMask
Jmp @@01
@@05:Call Sub_MoveImageShadow
Jmp @@01
@@04:Cmp DWord Ptr [ESP],0
JNE @@07
Test EAX,_Def_Attr_Mask
JNE @@08
Test EAX,_Def_Attr_BackG
JNE @@09
Call Sub_MoveSprite
Jmp @@01
@@09:Call Sub_MoveSpriteBk
Jmp @@01
@@08:Test EAX,_Def_Attr_BackG
JNE @@10
Call Sub_MoveSpriteMask
Jmp @@01
@@10:Call Sub_MoveSpriteBkMask
Jmp @@01
@@07:Test EAX,_Def_Attr_BackG
JNE @@11
Call Sub_MoveSpriteShadow
Jmp @@01
@@11:Call Sub_MoveSpriteBkShadow
Jmp @@01
@@03:Test EAX,_Def_Attr_Sprite
JNE @@12
Cmp DWord Ptr [ESP],0
JNE @@13
Test EAX,_Def_Attr_Mask
JNE @@14
Call Sub_MoveImage_FX0
Jmp @@01
@@14:Call Sub_MoveImageMask_FX0
Jmp @@01
@@13:Call Sub_MoveImageShadow_FX0
Jmp @@01
@@12:Cmp DWord Ptr [ESP],0
JNE @@15
Test EAX,_Def_Attr_Mask
JNE @@16
Test EAX,_Def_Attr_BackG
JNE @@17
Call Sub_MoveSprite_FX0
Jmp @@01
@@17:Call Sub_MoveSpriteBk_FX0
Jmp @@01
@@16:Test EAX,_Def_Attr_BackG
JNE @@18
Call Sub_MoveSpriteMask_FX0
Jmp @@01
@@18:Call Sub_MoveSpriteBkMsk_FX0
Jmp @@01
@@15:Test EAX,_Def_Attr_BackG
JNE @@19
Call Sub_MoveSpriteShad_FX0
Jmp @@01
@@19:Call Sub_MoveSprBkShad_FX0
@@01:Add ESP,4
Pop EBP
Pop ESI
Pop EDI
Pop EBX
End;
Never use the slow loop
instruction when optimizing for speed, except on AMD CPUs where it's not actually slow.
Avoid partial-register slowdowns by using movzx for byte loads. (lodsb is slower than movzx
+ inc esi
, so don't use it either). See http://agner.org/optimize/ for more x86 performance optimization stuff. (And also the links in the x86 tag wiki.)
Your 2nd function is just a blend based on the bytes not being a special transparent value. Use SSE2 to optimize it with pcmpeqb
and then blend with pand
/ pandn
+ por
. Or SSE4.1 pblendvb
.
SSSE3 pshufb
lets you more efficiently broadcast a byte to all positions.
Especially if you make a version with a fixed width, like 16, 24, or 32 pixels wide, you'd avoid needing much in the way of scalar cleanup code to handle odd widths. But anything wider than 16 should be doable with potentially-overlapping first/last unaligned vector stores.
And yes, making different versions of the function instead of passing integer flip / no-flip parameters is probably good, especially if you do the flipping with SSSE3 pshufb
(or multiple SSE2 shuffles, or even scalar bswap
). With pshufb
you could have an identity shuffle (that leaves a vector unchanged instead of reversing), but it would be more efficient to have a separate loop for the no-flip case that just don't use pshufb
at all.