LOADER CLASS 101
Greetings and welcome to the 1st issue of LOADER CLASS 101. Your teacher for the class is the "VGA KING" Sauron. I am assuming that you have a general knowledge of assembly for this. If not, pick up an assembly book to help you learn the basics and then this will make more sense. I am using turbo assembler V2.0 for all these examples but Microsoft's Assembler should work just as well.
In this 1st issue, I am covering:
- Displaying a VGA 320x200x256c picture
- Pallete Scrolling
- Fading Techniques
Included with this .ZIP is a few utilities to help you.
They are:
- INTRO.EXE - Re-orders the BMP so it is easier to use
- CUT.EXE - This cuts the end off any file.
- GIF2BMP.EXE - Used by INTRO.EXE to convert a 320x200x256c gif to BMP.
The other files in this .ZIP are:
- SAURON.NFO - This file.
- HUMBLE.ASM - The source code for the example.
- PICTURE.DAT - The example picture converted with INTRO.EXE
- PICTURE.GIF - The example GIF
- B.BAT - The file you run to compile the example (note, you must have TASM and TLINK in your path)
- 256.DAT - 256 0's used in the stack.
Lets first concentrate on displaying a 320x200x256c picture. The 1st thing you must do is create/find a GIF. Then use the program INTRO.EXE to convert the GIF to a BMP in useable format. If you are having problems running this program, make sure your COMSPEC is set pointing to your command.com.
For Example, something like this should be in your autoexec.bat file:
COMSPEC=C:\command.com
I have knowticed that this program doesn't work on GIFLITED GIF's. Now, you should have a .DAT file that is 64768 bytes long. The 1st 768 bytes are the pallete. The next 64000 is the picture starting from the top left to the bottom right.
Here's a Skeleton for displaying a picture along with comments:
;----------------------------------------------------------------------
DOSSEG ; so we can use the CUT procedure
picture segment byte public 'DATA'
pal db 768 dup (0) ; the pallete of this picture (256*3)
pic db 64000 dup (0) ; The actual picture. (320*200)
picture ends
stacks segment byte stack 'STACK'
thestak db 256 dup (0) ; the STACK used by the microprocessor
stacks ends
code segment byte public 'code'
assume cs:code, ss:stacks
MAIN: mov ax,0013h ; sets screen to 320x200x256c
int 10h ; sets screen to 320x200x256c when ax =13h
mov ax,picture ;BEGIN setup pallete
mov es,ax
mov dx,offset pal
mov ax,1012h
mov bx,0
mov cx,256
int 10h ;END setup pallete
mov ax,picture ;BEGIN copy picture to vga card.
mov ds,ax
mov ax,0a000h
mov es,ax
mov di,0
mov si,offset pic
mov cx,64000/2
rep movsw ;END copy picture to vga card.
HERE: mov ah,1 ;poll keyboard for a key
int 16h ;poll keyboard for a key when ah = 1
jz HERE ;if no key then Jump to HERE
mov ah,0 ;clear keyboard buffer
int 16h ;clear keyboard buffer when ah=0
mov ax,0003 ; sets screen to TEXT 80x25
int 10h ; sets screen to TEXT 80x25 when ax = 3
mov ax,4c00h ; program EXIT
int 21h ; program EXIT when ax = 4c00h
code ends
end MAIN
;----------------------------------------------------------------------------
You may cut this out and make a .ASM file out of it.
This program uses 3 segments (CODE,PICTURE,STACKS (in that order)). Most of this program should make sense to you but I will explain 2 sections a little more.
- The Pallete Section. This is a BIOS call which sets up the pallete. To call this BIOS call, you must setup AX with 1012h and call INT 10h. There are 256 colors and for each color there is 3 HUE's. (R)ed, (G)reen, and (B)lue. That means 256*3=768 bytes of data must be set for 256 colors.
- Before calling this BIOS call, you must set up BX,CX,DX and ES.
- ES - To be loaded with the SEGMENT which your pallete data is in. Just move PICTURE into AX and then AX into ES. You cannot do this: MOV ES,picture. So you must go about it this way.
- BX - The 1st color to set (0-255). Since we are setting all 256 colors, set this # to 0.
- CX - The # of colors to set.
- DX - The starting area for the pallete.
- The moving the picture to the vga card (0a000h). There is 64k setup at 0a000h for a 320x200 picture. For speed, the command REP MOVSW is being used. This will move 2 bytes at a time from DS:SI to ES:DI.
Now to compile all this. I have created a batch file called B.BAT which will help speed things up ALOT. Here is the batch file and an explanation of what it does.
tasm sauron ; runs tasm on sauron.asm
tlink sauron ; runs tlink on sauron.obj
cut sauron.exe 65024 ; cuts 65024 off the end of the
; sauron.exe 64768 (picture)
; + 256 (stack)
; =65024
copy /b sauron.exe+PICTURE.DAT+256.dat sauron.exe ; puts it all together.
; /b is to make a BINARY copy.
sauron ; runs SAURON.EXE
----------------------------------------------------------------------------
Pretty easy huh? Now lets try some pallete cycling and fading techniques without using BIOS calls. If you want to know what color to start the pallete cycling, use your favorite paint program (I use autodesk animator pro) to find the starting pallete color # and the ending pallete #.
There are a few changes to the previous example to achieve this. Here is the finished program along with comments on the new code.
dosseg
data segment byte public 'data'
credits db "LOADER CLASS 101",13,10
db "Taught By - Sauron THG F/X Prez$"
palbegin db 221 ;
palbegincx dw 221*3
palcx dw 20*3
paltmp3 db 3 dup (0)
paltmp db 256*3 dup (0)
paltmp2 db 256*3 dup (0)
fadepoint db 64
fadepoint2 db 64
data ends
picture segment byte public 'data'
pal db 768 dup (0)
pic db 64000 dup (0)
picture ends
stacks segment byte stack 'stack'
thestak db 256 dup (0h)
stacks ends
code segment byte public 'code'
assume cs:code, ds:data, ss:stacks
start: jmp main
PalleteRotate proc near
mov ax,data
mov es,ax
mov ds,ax
PDN: mov cx,[palcx]
mov di,offset paltmp3 ;to here
mov si,offset paltmp ;from here
rep movsb
mov cx,3
mov si,offset paltmp3
rep movsb
mov dx,03dah
vr1: in al,dx
and al,08
jz vr1
mov al,[palbegin]
mov dx,03c8h
out dx,al
inc dx
mov cx,[palcx]
mov si,offset paltmp
pl13: lodsb
out dx,al
loop pl13
ret
PalleteRotate endp
FADEOUT proc
mov ax,data
mov ds,ax
mov es,ax
mov ax,picture
mov ds,ax
mov cx,768/2
mov si,offset pal
mov di,offset paltmp
rep movsw
mov ax,data
mov ds,ax
mov es,ax
flp1: mov bx,768
flp2: cmp paltmp[bx],0
je fl3
dec paltmp[bx]
fl3: dec bx
jnz flp2
mov dx,offset paltmp
mov ax,1012h
mov bx,0
mov cx,256
int 10h
dec [fadepoint]
jnz flp1
endfadeout: ret
FADEOUT endp
;====================================================
MAIN: mov ax,0013h
int 10h
mov ax,picture ;BEGIN setup pallete
mov es,ax
mov ds,ax
mov dx,offset pal
mov ax,1012h
mov bx,0
mov cx,256
int 10h ;END setup pallete
mov ax,picture ;BEGIN copy picture to vga card.
mov ds,ax
mov ax,0a000h
mov es,ax
mov di,0
mov si,offset pic
mov cx,64000/2
rep movsw ;END copy picture to vga card.
mov ax,data ;copy pallete to temp for rotating pal
mov ds,ax
mov cx,[palcx]
mov dx,[palbegincx]
mov ax,picture
mov ds,ax
mov ax,data
mov es,ax
mov si,offset pal
add si,dx
mov di,offset paltmp
rep movsb ;end copy pallete
HERE: call PalleteRotate
mov ah,1
int 16h
jz HERE
mov ah,0
int 16h
call fadeout
mov ax,0003
int 10h
mov ax,data
mov ds,ax
mov ah,9
mov dx,offset credits
int 21h
mov ax,4c00h
int 21h
code ends
end start
The 2 major new procedures are PALLETE CYCLING and FADEOUT. Here they are in detail.
1) PALLETE CYCLING. 1st I have it copy just the section of the pallete that we are going to rotate to a buffer. Now to the actual palleterotate procedure. Basically, the 1st section shifts the section of the pallete DOWN by 1. Then it takes the 3 bottom bytes and puts them at the top. This is to make sure you keep the pallete rotating and not just shift them all off the bottom.
mov ax,data
mov ds,ax
mov es,ax
mov cx,[palcx]
mov di,offset paltmp3 ;to here
mov si,offset paltmp ;from here
rep movsb
mov cx,3
mov si,offset paltmp3
rep movsb
The next section writes directly to the vga card. Here is what this procedure does:
mov dx,03dah ; check for vertical retrace
vr1: in al,dx ;
and al,08 ;
jz vr1 ; end checking section
mov al,[palbegin]
mov dx,03c8h
out dx,al
inc dx
mov cx,[palcx]
mov si,offset paltmp
pl13: lodsb
out dx,al
loop pl13
1st, we check for vertical retrace to be sure we don't get "SNOW" on the screen. For direct pallete cycling, you must have these registers setup first:
This will select the starting color to start copying over bytes.
mov al,[palbegin] ; # to start cycling colors
mov dx,03c8h ; port address
out dx,al
This will repeat CX # of times to copy all colors into the new pallete.
inc dx ; dx is really now 03c9h
mov cx,[palcx] ; # of colors * 3 to set
mov si,offset paltmp ; starting offset for colors
pl13: lodsb ; move into al, what is in DS:SI and
; increment SI
out dx,al ; output to port 03c9h byte in AL
loop pl13 ; repeat till cx = 0 and DEC CX
I hope this will help you in programming the VGA card in assembly. It is now 5:47am in the morning and I am TIRED so the end of this article might not make too much sense. From these examples, you can display multiple pictures, fading in/out, and pallete cycling. I will try to clear up any question in the next issue of the Humble Review. If you have a question, you can contact me at The Warriors Guild BBS - (708)653-1839.
Next issue, I am going to cover scrollers.
*******************
If you use any of this code or this helps you understand VGA programming please greet me somewhere in your loader. You don't have to give me credit for using my code as this is the basics of VGA programming. HAPPY HACKING!
*******************
B.BAT
tasm sauron
tlink sauron
cut sauron.exe 65024
copy /b sauron.exe+PICTURE.DAT+256.dat sauron.exe
sauron
SAURON.ASM
dosseg
data segment byte public 'data'
credits db "LOADER CLASS 101",13,10
db "Taught By - Sauron THG F/X Prez$"
palbegin db 221 ; color to start at for cycling
palbegincx dw 221*3 ; palbegin * 3
palcx dw 20*3 ; # of colors to cycle *3
paltmp3 db 3 dup (0) ;
paltmp db 256*3 dup (0)
paltmp2 db 256*3 dup (0) ; tempory pallete
fadepoint db 64 ; # of times to darken pallete
data ends
picture segment byte public 'data'
pal db 768 dup (0)
pic db 64000 dup (0)
picture ends
stacks segment byte stack 'stack'
thestak db 256 dup (0h)
stacks ends
code segment byte public 'code'
assume cs:code, ds:data, ss:stacks
start: jmp main
PalleteRotate proc near
mov ax,data
mov es,ax
mov ds,ax
PDN: mov cx,[palcx]
mov di,offset paltmp3 ;to here
mov si,offset paltmp ;from here
rep movsb
mov cx,3
mov si,offset paltmp3
rep movsb
mov dx,03dah
vr1: in al,dx
and al,08
jz vr1
mov al,[palbegin]
mov dx,03c8h
out dx,al
inc dx
mov cx,[palcx]
mov si,offset paltmp
pl13: lodsb
out dx,al
loop pl13
ret
PalleteRotate endp
FADEOUT proc
mov ax,data
mov ds,ax
mov es,ax
mov ax,picture
mov ds,ax
mov cx,768/2
mov si,offset pal
mov di,offset paltmp
rep movsw
mov ax,data
mov ds,ax
mov es,ax
flp1: mov bx,768
flp2: cmp paltmp[bx],0
je fl3
dec paltmp[bx]
fl3: dec bx
jnz flp2
mov dx,offset paltmp
mov ax,1012h
mov bx,0
mov cx,256
int 10h
dec [fadepoint]
jnz flp1
endfadeout: ret
FADEOUT endp
;========================================================================
MAIN: mov ax,0013h
int 10h
mov ax,picture ;BEGIN setup pallete
mov es,ax
mov ds,ax
mov dx,offset pal
mov ax,1012h
mov bx,0
mov cx,256
int 10h ;END setup pallete
mov ax,picture ;BEGIN copy picture to vga card.
mov ds,ax
mov ax,0a000h
mov es,ax
mov di,0
mov si,offset pic
mov cx,64000/2
rep movsw ;END copy picture to vga card.
mov ax,data ;copy pallete to temp for rotating pal
mov ds,ax
mov cx,[palcx]
mov dx,[palbegincx]
mov ax,picture
mov ds,ax
mov ax,data
mov es,ax
mov si,offset pal
add si,dx
mov di,offset paltmp
rep movsb ;end copy pallete
HERE: call PalleteRotate ;after polling they keyboard, it calls
;the pallete rotating procedure
mov ah,1
int 16h
jz HERE
mov ah,0
int 16h
call fadeout
mov ax,0003
int 10h
mov ax,data
mov ds,ax
mov ah,9 ; used to display a string of text.
; uses a $ to end text.
mov dx,offset credits ; starting byte of text.
int 21h ; if ah = 9 then display text
mov ax,4c00h
int 21h
code ends
end start
The 2 major new procedures are PALLETE CYCLING and FADEOUT. Here they are
in detail.
1) PALLETE CYCLING. 1st I have it copy just the section of the pallete
that we are going to rotate to a buffer. Now to the actual
palleterotate procedure. Basically, the 1st section shifts the section
of the pallete DOWN by 1. Then it takes the 3 bottom bytes and puts
them at the top. This is to make sure you keep the pallete rotating
and not just shift them all off the bottom.
mov ax,data
mov ds,ax
mov es,ax
mov cx,[palcx]
mov di,offset paltmp3 ;to here
mov si,offset paltmp ;from here
rep movsb
mov cx,3
mov si,offset paltmp3
rep movsb
The next section writes directly to the vga card.
Here is what this procedure does:
mov dx,03dah ; check for vertical retrace
vr1: in al,dx ;
and al,08 ;
jz vr1 ; end checking section
mov al,[palbegin]
mov dx,03c8h
out dx,al
inc dx
mov cx,[palcx]
mov si,offset paltmp
pl13: lodsb
out dx,al
loop pl13
1st, we check for vertical retrace to be sure we don't get "SNOW" on
the screen. For direct pallete cycling, you must have these registers
setup first:
AL - # to start cycling colors