📄 final.asm
字号:
extrn Openfile:far,CloseFile:far,ReadFile:far
extrn readdata:far
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
delay macro times;;;;;画面滞留,减慢移动速度;times为外循环次数,用于控制移动速度
local d11,d12
mov dx,times
d11: mov cx,0ffffh
d12: loop d12
dec dx
jnz d11
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RestoreGraphics macro
mov ah, 00h
int 16h
mov ah, 00h
mov al, 00h
int 10h
endm
;////////////////////////////////////////
display macro ImageSrc
lea dx,ImageSrc;用于选择图片,写成宏
push si ;后面用到的[bp+8]
push di ;后面的[bp+6]
push dx ;后面的[bp+4]
call bitmap
cmp Eflag,0
jnz exitDoszz
endm
;///////////////////////////////////////
Stack Segment
Stk db 65535 dup(?)
Stack Ends
Data Segment common
ImageBuffer db 65078 dup(?)
ImageSrc1 db 'test.bmp',0
ImageSrc2 db 'test2.bmp',0
ImageSrc3 db 'test3.bmp',0
ImageSrc4 db 'test4.bmp',0
ImageSrc5 db 'test5.bmp',0
Eflag dw 0
OpenErrorMsg db '***open error***',0dh,0ah
readmsg db '***read error***',0dh,0ah
Not256Color db 'Not a 256 color bitmap',24h
handle dw ?
Data Ends
;;;;;;;;;;;;;;;;\;\\\\\\\\\\\\\\\\\\\\\
Code Segment ;50th row
Assume cs:Code,ds:Data,ss:Stack
main proc far
Start:
mov ax,Data
mov ds,ax
xor ax,ax
mov ax,-600
loop1:
add ax,8
cmp ax,310
jg next1
mov di,ax
mov si,40
display ImageSrc1 ;宏调用
;delay 20
jmp loop1
next1:
mov ax,-64
mov bx,-64
loop2:
add ax,4
cmp ax,315
jg next2
add bx,2
cmp bx,195
jg next2
mov di,ax
mov si,bx
display ImageSrc2
;delay 40
jmp loop2
next2:
mov ax,-64
mov bx,200
loop3:
add ax,4
cmp ax,315
jg next3
sub bx,2
cmp bx,0
jng next3
mov di,ax
mov si,bx
display ImageSrc3
;delay 40
jmp loop3
exitDoszz:
jmp exitDos
next3:
mov ax,320
mov bx,-64
loop4:
sub ax,4
cmp ax,-60
jng next4
add bx,2
cmp bx,195
jg next4
mov di,ax
mov si,bx
display ImageSrc4
;delay 40
jmp loop4
next4:
mov ax,320
mov bx,200
loop5:
sub ax,4
cmp ax,-60
jng exitDos
sub bx,2
cmp bx,-60
jng exitDos
mov di,ax
mov si,bx
display ImageSrc5
;delay 40
jmp loop5
exitDos:
RestoreGraphics;;;;恢复原来的显示模式
call far ptr readdata
RestoreGraphics
mov ax,4c00h
int 21h
main endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bitmap proc near
push bp ;bp用于作为寻找将会保存在堆栈中的BMP头信息的基址
mov bp,sp
sub sp,20
push ax
push bx
push cx
push dx
push si
push di
push es
;sub sp,20 ;在堆栈中预留20 Bytes的空间用于保存将用到的BMP头信息
mov dx,[bp+4] ;ImageSrc 地址
call far ptr OpenFile
cmp Eflag,0
jnz exitz ;打开出错,退出 ;;81th row
openOk:
;;;Read first 4 byte of the file in order to get the file size!!!
mov dx,offset ImageBuffer ;图片缓冲区
mov cx,4 ;设置将要读取的字节长度
call far ptr ReadFile
cmp Eflag,0
jz next ;读取出错,退出
;;//////89th row
exitz:
mov ax,01 ;设置退出标志
mov Eflag,ax
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
add sp,20
pop bp
ret 6
;ret ;退出
;;//////
next:
call far ptr CloseFile
;;;Read The entire bitmap file to memory/////////////////////////////
mov si,2 ;
mov cx,[si] ;Save the bitmap file entire size to CX Register ;;;100th row
mov dx,[bp+4] ;取得 ImageSrc 地址
call far ptr OpenFile ;再次打开文件
cmp Eflag,0
jnz exitzz ;打开出错,退出
call far ptr ReadFile ;读取的文件长度已经保存在CX中了,长度为整个文件长
cmp Eflag,0
jnz exitzz ;读取出错,退出
call far ptr CloseFile ;关闭文件
;Save Information to local variable
;把相关BMP头文件信息保存到变量中(堆栈中)之前已经预留20个字节的空间;
mov si,012h
mov ax,[si]
mov [bp-2],ax ;Save BmpWidth
mov [bp-4],ax ;Save BmpOnScreenWidth 在屏幕显示的宽度
mov [bp-6],ax ;Save BytePerRow 每行显示的宽度
mov cl,4
div cl ;图像长度除以4
cmp ah,0 ;余数保存在ah
jz NoDwAA ;No Dword align adjust 余数为零,说明是双字对齐的
mov cl,4
sub cl,ah ;4-余数,即为还差的使它能够双字对齐的长度
add [bp-6],cl ;保存到堆栈的bp-6位置(校正长度)
NoDwAA:
mov cx,0
mov [bp-8],cx ;Save LeftCutWidth,Default = 0
;图片隐藏在显示器屏幕左边的长度
mov si,016h
mov ax,[si]
mov [bp-10],ax ;Save BmpHeight 图片高度
mov [bp-12],ax ;Save BmpOnScreenHeight 图片在屏幕中的显示高度
mov si,01ch
mov ax,[si]
mov [bp-14],ax ;Save BitPerPixel 图片每像素的比特数
mov si,0eh
mov ax,[si] ;Save bmpfileheader length BMP文件头长度
add ax,14
mov [bp-16],ax ;Save PaletteOffset 调色板偏移位置
mov si,0ah
mov ax,[si]
mov [bp-18],ax ;Save ImgDataOffset 图像数据偏移位置
mov [bp-20],word ptr 0 ;Save RowOffset 行偏移量
;;;; Save the value to Local variable局部变量
jmp CoorDinateX
exitzz:
mov ax,01 ;设置退出标志
mov Eflag,ax
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
add sp,20
pop bp
ret 6
CoordinateX:
mov ax,[bp+6] ;X coordinate 显示起点的X坐标
push ax
and ah,80 ;如果ah为FFFF则说明X为负数,相与的结果就不为0
pop ax
jz PositiveX ;If X coordinate>=0,jump,正数则跳
mov ax,[bp+6] ;取得初始设置的X坐标
push ax
not ax
inc ax ;取反加一,求得|X|的值
mov [bp-8],ax ;Save LeftCutWidth 这个值即为隐藏在屏幕左边的长度
pop ax
add ax,[bp-2] ;X 坐标加上BmpWidth图像宽度,即图像最右边缘的显示位置
jnc exitzz ;Exit if X coordinate add BmpWidth < 0
;负数与图像宽度相加而不产生进位,说明图像最右边缘的显示位置
;也不能显示出来,此时整个图像隐藏在屏幕左边
;
jz exitzz ;Exit if X coordinate add BmpWidth = 0
;道理同上类似
push ax
mov cx,320
sub cx,ax ;屏幕宽度减去图像最右边缘的显示位置,即为实际显示出来的
;相对于屏幕左边缘的位置RowOffset
mov [bp-20],cx ;Save RowOffset 保存
add ax,[bp-8] ; 图像最右边缘的显示位置+左边裁剪的宽度
mov [bp-4],ax ;Save BmpOnScreenWidth + LeftCutWidth
pop ax
mov cx,320
cmp cx,ax
jnc NoWOverf ;No Width Overflow图像最右边缘的显示位置超出了屏幕右边缘?
mov ax,[bp-8]
add ax,320 ;LeftCutWidth+屏幕宽 :如果超出屏幕右边缘,
;就用320代替图像显示的图像右边缘
mov [bp-4],ax ;Save BmpOnScreenWidth = 320 + LeftCutWidth
mov ax,0
mov [bp-20],ax ;Save RowOffset 行偏移量
NoWOverf: ;;如果未超出屏幕右边缘
mov ax,0
mov [bp+6],ax ;实际显示时的X坐标位置为屏幕左边缘
jmp CoordinateY
PositiveX:
cmp ax,320 ;显示的起点的X坐标-320
jnc exitzz ;后如果结果非负,说明图像将会完全隐藏在屏幕右边
mov cx,320
sub cx,[bp-2] ;320-BmpWidth图像宽度,图像显示实际长度
mov [bp-20],cx ;保存
add ax,[bp-2] ;BmpWidth+显示的起点的X坐标,即为图像最右边缘的显示位置
mov cx,320 ;
cmp cx,ax ;是否超过320?
jnc CoordinateY;没有超出则跳
mov ax,320 ;超出了,就用320代替图像最右边缘的显示位置
sub ax,[bp+6] ;减去x坐标位置,即为图像左边缘的显示位置
mov [bp-4],ax ;Save OnScreenWidth保存
mov cx,320
sub cx,ax ;320-x坐标位置,即为图像左边缘与屏幕左边的距离RowOffset
mov [bp-20],cx ;SaveRowOffset
CoordinateY:
mov ax,[bp+8] ;Y 坐标
push ax
and ah,80 ;如果ah为FFFF则说明Y为负数,相与的结果就不为0
pop ax
jz PositiveY
;Y 坐标为负
add ax,[bp-10] ;BmpHeight图像高度+Y 坐标
jnc exitzz1 ;
jz exitzz1 ;结果<=0则图像完全在屏幕以上
mov [bp-10],ax ;Save BmpHeight
mov [bp-12],ax ;Save OnScreenHeight
mov cx,0
mov [bp+8],cx ;Y的实际显示起始位置为0
mov cx,200
cmp cx,ax ;OnScreenHeight>200?如果大于说明溢出到屏幕下方
jnc SetInt10 ;No Height Overflow
mov cx,200 ;溢出,OnScreenHeight设置为200,实际能显示的高度
mov [bp-12],cx
NoHOverf:
jmp SetInt10
exitzz1:
mov ax,01 ;设置退出标志
mov Eflag,ax
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
add sp,20
pop bp
ret 6
PositiveY: ;Y坐标为正
cmp ax,200 ;Y坐标>=200,说明图像完全在屏幕下方
jnc exitzz1
add ax,[bp-10] ;取得BmpHeight
mov cx,200
cmp cx,ax ;BmpHeight是否大于200
jnc SetInt10 ;不大于则跳
mov ax,200 ;大于则让
sub ax,[bp+8] ;200-Y坐标 作为OnScreenHeight实际能显示的高度
mov [bp-12],ax
;;;;;;;;;Set the Palette register and copy image data to video buffer which
;address start at A000:0000.
SetInt10:
mov ax,013h
int 10h ;Set Video Mode to 13h设置到【320*200 256色】的显示模式
mov dx,03c6h ;写图形控制寄存器接口,水平位移寄存器
mov ax,0ffh ;写入的数据是0ffh,D0 ~ D3为水平左移点数,D4~D7不使用
out dx,ax
mov si,[bp-16] ;调色板偏移地址
mov di,0 ;
mov cx,256 ;循环次数
call SetPalette ;设置调色板 ;280th row
call Showbmp ;显示
exit:
delay 200h
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
add sp,20
pop bp
ret 6
bitmap endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SetPalette proc near
SetP:
mov dx,03c8h ;颜色查找表写寄存器,用于存放颜色查找表单元地址
;
mov ax,di ;di=0 颜色查找表单元地址
out dx,al ;写入
mov dx,03c9h ;颜色查找表数据寄存器,用于存放写入或读出
;颜色查找表某单元的数据
;;;;;;;;;;三个写3C9H端口命令即可修改颜色查找表的一组彩色值,
;;;;;;;;;;每写3个字节后,写序号寄存器中的内容自动+1
mov al,byte ptr[si+2] ;调色板偏移地址+2
push bx
mov bl,63
mul bl ;;[si+2]*63
mov bl,0ffh
div bl ;;([si+2]*63)/0ffh
pop bx
out dx,al
mov al,byte ptr[si+1] ;调色板偏移地址+1
push bx
mov bl,63
mul bl
mov bl,0ffh
div bl
pop bx
out dx,al
mov al,byte ptr[si] ;调色板偏移地址
push bx
mov bl,63
mul bl
mov bl,0ffh
div bl
pop bx
out dx,al
add si,4
inc di
loop SetP
ret
SetPalette endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Showbmp proc near
mov ax,0a000h ;Video memory start address
mov es,ax ;
mov ax,[bp+8] ;Y坐标显示起点
mov cx,320
mul cx ;Y坐标显示起点*320,即为起点开始以下的屏幕像素
add ax,[bp+6] ;低位结果AX加上X坐标显示起点
mov di,ax ;传给di
vertical: ;垂直移动
cmp word ptr[bp-12],0 ;if bitmapHeightOnScreen==0,display finished ,exit
;jz exit
jz return
dec word ptr[bp-10] ;bitmapHeight--
dec word ptr[bp-12] ;bitmapHeightOnScreen--
mov ax,[bp-10] ;BmpHeight
mul word ptr[bp-6] ;bitPerRow*BmpHeight,即为已经显示的像素块
mov bx,ax
add bx,[bp-18] ;bx+imagDataOffset图像数据偏移
mov si,0
add si,[bp-8] ;leftCutWidth
horizon: ;水平移动
cmp si,word ptr[bp-4] ;bitmapWidthOnSreen=leftCutWidth?if so, the end of a row
jz horizonend
mov al,[bx][si] ;已经显示的像素块+图像数据偏移+leftCutWidth
mov es:[di],al
inc si
inc di
jmp horizon
horizonEnd: ;一行的显示已经结束,跳到下一行的开头
add di,[bp-20] ;di+rowOffset
jmp Vertical
return:
ret
Showbmp endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code ends
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end Start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -