maya
maya

Reputation: 11

print 800*600 bmp picture assembly

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

Answers (1)

Sep Roland
Sep Roland

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.

But the 320x200 example can use LFB method too.

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

And the 800x600 code is very similar.

You get your BytesPerScanLine value and LinearFrameBuffer address from inspecting the results of VESA 4F01h ReturnVBEModeInformation function.

  • offset +40 of the ModeInfoBlock PhysBasePtr (dword)
  • offset +50 of the ModeInfoBlock LinBytesPerScanLine (word)

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

Related Questions