Reputation: 11
I've been working on an assembly project and I need to print a bmp picture on the screen. I changed the screen's resolution to 800*600 and I have a code (which I didn't write) that prints 320*200 bmp picture. I don't know how to change it to print 800*600 picture.
Can somebody please help? thanks.
That is the part of the code that needs to be changed:
proc CopyBitmap
; BMP graphics are saved upside-down.
; Read the graphic line by line (200 lines in VGA format),
; displaying the lines from bottom to top.
mov ax, 0A000h
mov es, ax
mov cx,200
PrintBMPLoop:
push cx
; di = cx*320, point to the correct screen line
mov di,cx
shl cx,6
shl di,8
add di,cx
; Read one line
mov ah,3fh
mov cx,320
mov dx,offset ScrLine
int 21h
; Copy one line into video memory
cld ; Clear direction flag, for movsb
mov cx,320
mov si,offset ScrLine
rep movsb ; Copy line to the screen
;rep movsb is same as the following code:
;mov es:di, ds:si
;inc si
;inc di
;dec cx
;... loop until cx=0
pop cx
loop PrintBMPLoop
ret
endp CopyBitmap
Upvotes: 0
Views: 607
Reputation: 39191
The code that you say you didn't write yourself is wrong! To fill the entire 320x200 256-color screen with a bitmap of the same size, the Y-coordinate will have to vary from 199 downto 0. This code currently loops from 200 downto 1 and thus the bottom line of the bitmap is never displayed. This is easy to fix.
When you told us that you've changed the screen's resolution to 800x600, you should also have told us the color resolution. In below code I will assume it's 256-colors, just like in the example code. Moreover I will present a solution that uses the LinearFrameBuffer method. A windowed approach exists but is more difficult (certainly if you don't want to cut too many corners). For a video mode that does no longer fit the 64KB graphic window (800 * 600 = 480000 bytes), it will involve bank switching with VESA.
The video window is at the segmented address 0A000h:0000h. This is in fact the linear address 000A0000h.
; On entry BX is handle for the file with filepointer at bitmap data!!!
proc CopyBitmap
; BMP graphics are saved upside-down.
; Read the graphic line by line (200 lines in VGA format),
; displaying the lines from bottom to top.
push es
xor ax, ax
mov es, ax
mov cx, 200
PrintBMPLoop:
push cx
; Point to the correct screen line
dec cx ; Y ranging from 199 to 0
movzx edi, cx
imul edi, 320
add edi, 000A0000h
; Read one line
mov dx, offset ScrLine
mov cx, 320
mov ah, 3Fh ; DOS.ReadFile
int 21h
jc WhatIfError?
cmp ax, cx
jne WhatIfError?
; Copy one line into video memory
mov si, dx
add dx, cx ; DX now points to the end of the buffer
CopyLoop:
lodsd ; Load 4 pixels together
stosd [edi] ; This generates an AddressSizePrefix
cmp si, dx
jb CopyLoop
pop cx
loop PrintBMPLoop
pop es
ret
endp CopyBitmap
You get your BytesPerScanLine value and LinearFrameBuffer address from inspecting the results of VESA 4F01h ReturnVBEModeInformation function.
The BytesPerScanLine value need not be 800. The graphics environment might easily have chosen 1024 as a more sensible value. You need to check and not just assume.
; On entry BX is handle for the file with filepointer at bitmap data!!!
proc CopyBitmap
; BMP graphics are saved upside-down.
; Read the graphic line by line (600 lines in SVGA format),
; displaying the lines from bottom to top.
push es
xor ax, ax
mov es, ax
mov cx, 600
PrintBMPLoop:
push cx
; Point to the correct screen line
dec cx ; Y ranging from 599 to 0
movzx edi, cx
imul edi, BytesPerScanLine
add edi, LinearFrameBuffer
; Read one line
mov dx, offset ScrLine
mov cx, 800
mov ah, 3Fh ; DOS.ReadFile
int 21h
jc WhatIfError?
cmp ax, cx
jne WhatIfError?
; Copy one line into video memory
mov si, dx
add dx, cx ; DX now points to the end of the buffer
CopyLoop:
lodsd ; Load 4 pixels together
stosd [edi] ; This generates an AddressSizePrefix
cmp si, dx
jb CopyLoop
pop cx
loop PrintBMPLoop
pop es
ret
endp CopyBitmap
Upvotes: 3