Im currently learning graphical programming in tasm using dosbox. Ive been using a bunch of loops to draw square blocks of pixels and its really hard. I want to know if theres a way to read an image and display it. I know how to read a txt file maybe this is a start. Pls help
-
No, that's not possible... that's the reason, why all the DOS games did draw just squares, and never had any graphic files with images... /sarcasm ... yes, you "just" load the content of file into memory, if it is compressed file, then you decompress it (writing own gif decoder may be much more difficult then doing bunch of loops), then you copy it to VRAM. Memory management (as you are in real mode? So each memory page only 64ki long and juggling around with segment regs all the time), and palette problems included. (probably easiest way is to prepare "raw" data in file in target format) – Ped7g Aug 20 '17 at 03:09
-
btw, I'm flagging this as "too broad" ... you should at least pick graphics mode (16 colors have completely different format than 256 13h mode), specify real/protected mode (and if you are in real mode, and planning to do anything memory intensive, then rather consider using some "extender" like dos4gw and start using protected mode), and specify gfx file format (choose wisely, as writing decompression routines can be project in itself, if you don't plan to mix with C and some library ... bmp is doable, just upside-down data, and some old formats were even more friendly, just can't recall any) – Ped7g Aug 20 '17 at 03:26
-
I'm using svga mode - 101H - 640x480 - 256 packed pixel. I've seen some using bitmaps and am trying to learn to read bitmap files and display it – Jhon Paul Jaspe Aug 20 '17 at 04:59
-
Ok, `bmp` is reasonably simple to read and decode, although in real mode with 64ki segments it will be total PITA to operate in such high resolution. Actually I can't even recall how that SVGA mode memory layout is designed and what is banked, if every 4th pixel (nah, doesn't fit), or every bit over 8 planes, or just the whole screen is divided into 5+ parts. (I used Watcom C compiler to init everything into protected mode, load files, decode them, etc (all in C/C++), and VBE2.0 extension to have linear protected mode VRAM mapping, then I did the fun stuff in 32b asm, so everything was simple) – Ped7g Aug 20 '17 at 07:22
1 Answers
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:\language\compil\tasm\tasm !.! /ic:\language\source\tasm\inc
@c:\language\compil\tasm\tlink !.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:

- 49,595
- 11
- 110
- 380
-
By the way, how do i print string with larger fonts in graphics mode. I'm using now 800x600 256 colors. – Jhon Paul Jaspe Aug 20 '17 at 13:07
-
writing an image loader maybe too much for me for the time being, i'll stick with drawing block by block of pixels. Thank you for teaching me some ideas – Jhon Paul Jaspe Aug 20 '17 at 13:18
-
@JhonPaulJaspe use larger font or double the pixels The fonts can be obtained from EGA/VGA ROM or use image like this [ASCII 8x8 pixel 32x8 characters font texture](https://stackoverflow.com/a/44797902/2521214). For the loader it is enough to copy the pcx routine of mine and use it on file loaded into memory. for more then 64KB you need to add page switchings ... either by VESA BIOS or use LFB .... but that is more suited for Protected mode which I do not have experience with ... – Spektre Aug 20 '17 at 21:36
-
How? i don't understand, isn't there just a function in the video services that would make the font size increase? I've tried ah = 1122h, 1123h, 1124h, in int 10h and the font size were larger indeed but were distorted and not readable. i don't know – Jhon Paul Jaspe Aug 21 '17 at 14:27
-
im sorry but i can't comprehend some of the stuff that you mentioned like the loader or the pcx routine – Jhon Paul Jaspe Aug 21 '17 at 14:29
-
@JhonPaulJaspe 1. in gfx mode you should use your own string print functions. 2. search the code block in my answer for `pcx:` it is pcx decoder to raw 256 color image without palette. So you need just copy its source to your project and call it with the registers set ... it needs just the file loaded in memory which you can do as you mention you can open text files and as destination chose some memory or use VRAM directly. It is written for 320x200x256 video mode so start with that and when working you can recode to 800x600 or whatever – Spektre Aug 21 '17 at 17:24
-
are the video pages, in int 10h similar to layers in programs like photoshop? wherein the graphics on 1 page is independent of the other? I'm drawing some static graphics in page 0, then I'm drawing graphics in page 1 which will be movable, how do i clear page 1, without affecting other pages? I've tried, selecting the active page 1, then draw black in the whole screen, then select active page 0 again. but the graphics drawn on page 0 are not returning. – Jhon Paul Jaspe Aug 22 '17 at 09:15
-
@JhonPaulJaspe Pages on VESA are just 64KByte parts of screen they are not move-able (if I remember correctly) They are there because you can address only 64 KBytes from VRAM but the videomode requires more ... `800x600x256-> 7x64KByte`. If you are in protected mode then you can access the whole VRAM if map as LFB into CPU memory space but that is way above my knowledge (I used only real mode) – Spektre Aug 22 '17 at 11:30
-
my method for moving graphics will be, delete previous graphic, increment position, then draw again. i'm thinking of clearing the whole screen in video page 1, to delete the previous graphic. While the contents in video page 0 will still remain and be visible, then draw again – Jhon Paul Jaspe Aug 22 '17 at 12:11
-
@JhonPaulJaspe you are mixing pages with back/double buffering those are not the same thing ... – Spektre Aug 22 '17 at 12:21
-
sorry i have a lot of misconceptions, one more question. In C++ you can create header files, and use them in another cpp file. Is there a way to implement this in assembly? like i have "mainProgram.asm", then i want to create "subProgram.asm" and subProgram contains many many procedures and macros. and i want to include them in mainProgram like #include
or something. Is it possible to do this? Because my code is getting very long and it's hard to manage – Jhon Paul Jaspe Aug 22 '17 at 12:47 -
I've seen some using include "filename.inc" what is this .inc file? is this what i need to implement what i said in previously^? how to do this? – Jhon Paul Jaspe Aug 22 '17 at 13:04
-
@JhonPaulJaspe you can use `include 'filename'` directive ... the `*.asm, *.inc; *.lib` extensions are used all are in `asm`. – Spektre Aug 22 '17 at 13:08
-
in my mainProgram.asm, i have .model .data, .stack, .code. in my subProgram.asm, i also have them, i tried using "include subProgram.asm" it assembled, but when i call a procedure from the subProgram.asm in mainProgram.asm, it doesn't work. – Jhon Paul Jaspe Aug 22 '17 at 13:42
-
HOLY SH**T, I SUCCESSFULLY INCLUDED AN ASM FILE, I REMOVED THE THE DIRECTIVES IN MY SUBPROGRAM AND JUST LEFT THE .CODE THERE AND IT WORK HOLY SH**T. THANK YOU MAN – Jhon Paul Jaspe Aug 22 '17 at 13:48
-
@JhonPaulJaspe yes directives in subfiles mess things up as you got them in the main file too which conflicts them in between ... the `include` just copies the file to that place where the `include` is (just like in C++) so you need to be careful with using DATA and CODE segments in included files ... Btw I tried to compile the pcx decoder under TASM but it does not work due to compiler incompatibilities (it was written in NASM) I must have forgot to change something that TASM does not like ... aaargh I hate TASM now I remember why I moved to NASM .... – Spektre Aug 22 '17 at 14:00
-
@JhonPaulJaspe added edit1 finaly found the problem with TASM (datasegment labels does not start at offset 0 and also got the direct memory addressing going) – Spektre Aug 22 '17 at 16:44