You need to write/use image loader or use your own image file format. BMP may look simple but has too much in it like compression pixel formats etc but you still can focus on a specific type of BMP and ignore all the others...
Back in the days of MS-DOS I was using 256 color PCX images with palette as I used 256 color video modes. Here NASM LINEZ game example:
see the pcx:
subroutine. It decodes loaded PCX file from memory ds:0
to raw VGA image at es:di
. Beware it does support just 64 KByte
size limit !!!
Now to visualize the image you would have to copy es:di
content into VideoRAM (assuming A000:0000
) for example with rep movsd
or you can set es:di
to it in the first place (but that could flicker).
This PCX loader however does not use palette from the image so you need to encode it ... (the routines to change VGA palette are included in the source you just need to extract the RGB values from PCX I think it was at the end of file) Look here:
if converts PCX to 32bit raw image.
For more info about MS-DOS game programing see PCGPE 1.0
Here another game example (TASM) which uses own image file-format:
It has text menues, binary file access, 320x200 sprite graphics, 3 human players
[Edit1] New code
I removed the old code example and instead I created compilable and working 8bit PCX with color palette viewer in TASM. It uses VESA 800x600x256
colors mode (103h
).
The image must fit into screen and its file size must be less than 64 KByte !!!
I did not add any checks or error messages ... It simply loads file image.pcx
and displays it on VESA then wait on key hit end exit. Here the TASM source:
PCX.ASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.386
IDEAL
MODEL TINY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DATASEG
file: db 'image.pcx',0 ;filename to load
buff:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CODESEG
STARTUPCODE
scrxs equ 800
scrys equ 600
mov ax,103h ; VESA 800x600x256
call vesamod
mov al,0
call vesapag
; scrxs equ 320
; scrys equ 200
; mov ax,19 ; VGA 320x200x256
; int 10h
lea dx,[file] ; load PCX into DS:buff, CX bytes
call fopen
lea dx,[buff]
mov cx,64000 ; some max value to fit into DS segment
call fread ; CX is PCX real size
call fclose
lea si,[buff] ; decode directly to VRAM
mov ax,0A000h
mov es,ax
mov di,0
call pcx
mainl0:
mov ax,256 ; test keyboard
int 16h
jz mainl0
sub ax,ax ; clear key buffer
int 16h
mov ax,3 ;|VGA 80x25 text
int 16
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesamod:pusha ;set VESA videomode ax
mov bx,ax
mov ax,4f02h
int 16
popa
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
vesapag:pusha ;al=page switch vesa video page window A
mov [cs:scrpag],al
mov dl,al
sub dh,dh
sub bx,bx
mov ax,4f05h ; window A
int 16
popa
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .386P
scrpag db 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .386P
hand dw 0 ;### handler...
ferr db 0 ;### DOS error code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fopen: pusha ;DS:DX = file name, [hand] <= file handle
mov ax,3D02h
int 21h
mov bl,0
jnc fopen0
mov bl,al
sub ax,ax
fopen0: mov [cs:hand],ax
mov [cs:ferr],bl
popa
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fclose: pusha ;[hand] = file handle
mov bx,[cs:hand]
mov ah,3eh
int 21h
mov bl,0
jnc fclose0
mov bl,al
sub ax,ax
fclose0:mov [cs:ferr],bl
mov [cs:hand],ax
popa
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
fread: pusha ;DS:DX = adr, CX = lenght, [hand] = hand, CX => read
mov bx,[cs:hand]
mov ah,3Fh
int 21h
mov bl,0
jnc fread0
mov bl,al
sub ax,ax
fread0: mov [cs:ferr],bl
mov [cs:freadsz],ax
popa
mov cx,[cs:freadsz]
ret
freadsz dw 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
pcx: pusha ;decode pcx at ds:si to es:di cx = PCX size
push ds
push es
push ecx
push edx
push si ;set palette
add si,cx
sub si,768
sub ax,ax
pall0: mov dx,3C8h
mov al,ah
out dx,al
inc dx
lodsb
shr al,2
out dx,al
lodsb
shr al,2
out dx,al
lodsb
shr al,2
out dx,al
inc ah
jnz pall0
pop si
mov ax,[ds:si+8] ;get xs
sub ax,[ds:si+4]
inc ax
mov [cs:pcxxs],ax
mov [cs:pcxx],ax
mov ax,[ds:si+10] ;get ys
sub ax,[ds:si+6]
inc ax
mov [cs:pcxys],ax
mul [cs:pcxxs]
push dx
push ax
pop edx
add si,128 ;src start after pcx header
sub ecx,ecx ;RLE decoder of PCX
pcxl0: lodsb
mov cx,1
cmp al,192
jb pcxr0
mov cl,al
and cl,63
lodsb
pcxr0: mov bx,cx
pcxl1: call point
dec [cs:pcxx] ;correct next screen line position if end of PCX line
jnz pcxr1
mov ax,[cs:pcxxs]
mov [cs:pcxx],ax
neg ax
add ax,scrxs
add di,ax
jnc pcxr1
; page swith
mov al,[cs:scrpag]
inc al
call vesapag
pcxr1: loop pcxl1
mov cx,bx
sub edx,ecx
jz pcxesc
jnc pcxl0
pcxesc: pop edx
pop ecx
pop es
pop ds
popa
ret
pcxxs dw 0 ;PCX resolution
pcxys dw 0
pcxx dw 0 ;actual X coordinate
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
point: mov [es:di],al ;point ;estosb
inc di
jnz pntesc
; page swith
mov al,[cs:scrpag]
inc al
call vesapag
pntesc: ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
END
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
So take any image up to 800x600
convert it to 256 color PCX with palette and rename it to image.pcx
. Then place it to your *.com
file and run. I compiled it with Volcov commander extension script vc.ext
like this:
asm:@c:languagecompilasmasm !.! /ic:languagesourceasminc
@c:languagecompilasmlink !.obj /t /x
@del !.obj
so each time I hit the enter on any asm file it will compile. Just change the paths and if you are not targeting *.com
files then change the /t
switch accordingly. Here preview from my DOSBox: