如何解决我有一些汇编代码可以使我的 MS-DOS 游戏的屏幕淡出它有效,但它不断循环
我正在用 C 和汇编为 MS-DOS 制作游戏(我打算用 DOSBox 或我自己的修改分发游戏)。我大部分图形代码都在汇编中,这是一种我较弱的语言,但我认为它使用起来很方便,因为它能够将事物更改为如此精细的级别(包括诸如图形调色板等)。
但是,我的代码基于从一些旧的 16 位汇编源代码中找到的淡出函数,我正在尝试将其转换为 32 位汇编。
我让代码工作了,但是,它不断重复循环而不是继续代码。
AFObeg equ [bp+4]
AFOcnt equ [bp+4+2]
proc FadeOut_ near
push ebx
push ecx
push edx
mov ebp,esp
push ds
push esi
push edi
push ds ; get data segment into es
pop es
mov edx,offset _WorkPalette
push edx ; save offset of opal
xor ebx,ebx
mov ecx,100h
mov eax,1017h ; bios read dac registers function
int 10h ; read the palette registers into opal
pop edi ; offset of opal,was in dx!
mov eax,AFObeg ; get offset of first palette byte to
mov ebx,3 ; be processed
mul ebx
add edi,eax ; adjust offset into opal
mov eax,AFOcnt ; find the number of bytes to be processed
mov ebx,3
mul ebx ; leave it in ax
mov ecx,64 ; 64 passes through fade loop
o_fade_loop:
push ecx ; save the fade loop counter
push edi ; save offset of first byte processed in
mov bl,cl ; we'll use the pass number as a threshold
mov ecx,eax ; load number of bytes to process into cx
o_pal_cmp_loop:
cmp bl,es:[edi] ; start decrementing when palette value
jnz o_no_dec ; is equal loop count (it will stay equal
dec BYTE PTR es:[edi] ; to loop count for the rest of this pass)
o_no_dec:
inc edi
loop o_pal_cmp_loop ; do the next byte
mov ebx,esp ; need the stack pointer for a moment
mov di,ss:[ebx] ; restore offset into pal without popping
mov ecx,AFOcnt ; number of triplets to process
push eax ; need to use ax for port i/o
mov edx,03DAh ; CRT controller input status 1 register
o_vbi_1:
in al,dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz o_vbi_1 ; we're not in a blanking interval
o_vbi_2:
in al,dx ; now wait for the start of the
test al,08h ; next blanking interval
jz o_vbi_2
mov ah,AFObeg ; get first register to process into ah
mov dx,03c8h ; DAC palette index register
o_pal_load_loop:
mov al,ah ; get next palette number to write
out dx,al ; write the register number to the dac
inc dx ; address dac data register
mov al,BYTE PTR es:[di] ; get first byte of triplet
out dx,al ; write it to the dac data register
inc edi ; point to second byte
mov al,BYTE PTR es:[di] ; get second byte of triplet
out dx,al ; write it to the dac data register
inc edi ; point to third byte
mov al,BYTE PTR es:[di] ; get third byte of triplet
out dx,al ; write it to the dac data register
inc edi ; point to first byte of next triplet
dec edx ; address the da21c index register
inc ah ; point to next palette register
loop o_pal_load_loop ; process next triplet
pop eax ; restore ax
pop edi ; restore the offset into pal
pop ecx ; restore the fade loop counter
loop o_fade_loop ; do the next pass through the fade loop
pop edi
pop esi
pop ds
pop ebp
ret
endp ;end of the fade out function
如果大家还有什么问题,我会很乐意回答的。
编辑:对于那些想知道原始代码是什么样子的人,这里是:
AFObeg equ [bp+ABASE]
AFOcnt equ [bp+ABASE+2]
PBEGIN _FadeOut
push bp
mov bp,sp
push ds
push si
push di
push ds ; get data segment into es
pop es
mov dx,offset DGROUP:_WorkPalette
push dx ; save offset of opal
xor bx,bx
mov cx,100h
mov ax,1017h ; bios read dac registers function
int 10h ; read the palette registers into opal
pop di ; offset of opal,was in dx!
mov ax,AFObeg ; get offset of first palette byte to
mov bx,3 ; be processed
mul bx
add di,ax ; adjust offset into opal
mov ax,AFOcnt ; find the number of bytes to be processed
mov bx,3
mul bx ; leave it in ax
mov cx,64 ; 64 passes through fade loop
o_fade_loop:
push cx ; save the fade loop counter
push di ; save offset of first byte processed in
mov bl,cl ; we'll use the pass number as a threshold
mov cx,ax ; load number of bytes to process into cx
o_pal_cmp_loop:
cmp bl,es:[di] ; start decrementing when palette value
jnz o_no_dec ; is equal loop count (it will stay equal
dec BYTE PTR es:[di] ; to loop count for the rest of this pass)
o_no_dec:
inc di
loop o_pal_cmp_loop ; do the next byte
mov bx,sp ; need the stack pointer for a moment
mov di,ss:[bx] ; restore offset into pal without popping
mov cx,AFOcnt ; number of triplets to process
push ax ; need to use ax for port i/o
mov dx,03DAh ; CRT controller input status 1 register
o_vbi_1:
in al,dx ; watch vertical blanking bit
test al,08h ; wait for it to clear to make sure
jnz o_vbi_1 ; we're not in a blanking interval
o_vbi_2:
in al,dx ; now wait for the start of the
test al,08h ; next blanking interval
jz o_vbi_2
mov ah,BYTE PTR AFObeg ; get first register to process into ah
mov dx,03c8h ; DAC palette index register
o_pal_load_loop:
mov al,ah ; get next palette number to write
out dx,al ; write the register number to the dac
inc dx ; address dac data register
mov al,BYTE PTR es:[di] ; get first byte of triplet
out dx,al ; write it to the dac data register
inc di ; point to second byte
mov al,BYTE PTR es:[di] ; get second byte of triplet
out dx,al ; write it to the dac data register
inc di ; point to third byte
mov al,BYTE PTR es:[di] ; get third byte of triplet
out dx,al ; write it to the dac data register
inc di ; point to first byte of next triplet
dec dx ; address the dac index register
inc ah ; point to next palette register
loop o_pal_load_loop ; process next triplet
pop ax ; restore ax
pop di ; restore the offset into pal
pop cx ; restore the fade loop counter
loop o_fade_loop ; do the next pass through the fade loop
pop di
pop si
pop ds
pop bp
ret
_FadeOut endp
这里是宏 ET.MAC 文件,其中定义了 ABASE 之类的内容
; MACRO FILE FOR EGA320 LIBRARY
IFDEF _ML
%OUT LARGE MODEL
PBEGIN MACRO L
PUBLIC L
L PROC FAR
ENDM
PEXTRN MACRO L
EXTRN L:FAR
ENDM
ABASE EQU 6 ;BASE STACK PTR UPON PROCEDURE ENTRY
ENDIF
IFDEF _MC
PBEGIN MACRO L
PUBLIC L
L PROC NEAR
ENDM
PEXTRN MACRO L
EXTRN L:NEAR
ENDM
ABASE EQU 4 ;BASE STACK PTR UPON PROCEDURE ENTRY
%OUT COMPACT MODEL
ENDIF
XMOV MACRO A,B
PUSH B ;XFER SOURCE
POP A ; TO DEST.
ENDM
GEN MACRO OP,ARG
IRP X,<ARG>
OP X
ENDM
ENDM
XSTM MACRO S,O,D
MOV WORD PTR D,O
MOV WORD PTR D+2,S
ENDM
但是为了避免使用该文件,我已经切换到只是将 ABASE 的值更改为 4 或 6,但它们仍然给出了相对相似的结果。
解决方法
对于淡入淡出循环,您使用 mov ecx,eax
加载计数。回顾 eax
从哪里获得它的值,我们找到了 mov eax,AFOcnt
指令。不过貌似AFOcnt
只有16位,所以eax
的上半部分会有垃圾值,会导致你的循环运行时间长。
使用 movzx eax,word ptr AFOcnt
将 eax
的上半部分清零(或者您可以使用 and
指令将其屏蔽)。
其他一些注意事项(不全面):
- 您保存了
ds
,但修改了es
- 这个简单的淡入淡出代码会在淡入淡出时破坏颜色。只需稍加努力,即可重做淡入淡出,以保留每个红-绿-蓝分量的相对值,从而使颜色真正淡化为黑色。
- 您混合使用 16 位(
[di]
,函数参数)和 32 位 ([edi]
) 寻址。这应该专门使用 32 位寻址。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。