Ok, lets start out with mode 13h. What's mode 13h? It's the graphic mode most demos and games are (or were, nowadays windows has taken more control of that part) written in. Mode 13h has a size of 320*200 pixels where every pixel can have any of 256 colors.
As you might know from mode 3
(= textmode - the one that you usually use), the segment address of the screen memory is 08b00h. This is not true for mode 13h! Here the screen memory begins at the segment address 0a000h.
Ok - let's say that you want to draw a pixel to the screen, what do you need?
1 - Segment address of the screen memory (you already got this - 0a000h remember?)
2 - Offset (ie where on the screen you want to write)
3 - Color of the pixel
We know the first part, so let's jump to the offset...how do we calculate it? You should be able to figure out that yourself knowing the screen limits, but ok - I'll help you with it.
Offset = 320*y + x.
where ofcourse X and Y are coordinates. If we want to write to the first position of the screen (0,0 - in the upper left corner) we put these values in our formula. 320*0+0 = 0. So, the offset for this position is 0. So far so good, let's try to calculate the offset for (5,10). Offset = 320*10 + 5 = 3205. You see - it isnt very complicated...now you should understand how the offset calculations work so we can jump to...
...Color of the pixel...not much to say about it - just specify a value between 0-255 and sent it to the screen...let's go to the interesting part instead - lets see some asm code!
;Setup VGA and write to it mov ax,013h ;This is how we change the graphic mode int 10h mov ax,0a000h ;Lets use es (extra segment register) as our screen segment mov es,ax ;We cant type "mov es,0a000h" mov di,offs ;We'll use di (destination index) as our offset. mov al,5 ;Put color in al, this can be from 0-255 mov es:[di],al ;Write to seg:ofsNot to hard to understand is it? Here comes the code to calculate the offset:
mov ax,320 ;You must have declared offs,x and y as word variables (dw) mul y add ax,x mov offs,ax
Nice isnt it? But wouldnt it be even nicer if we could optimize the code? Try to figure out yourself what we can change, remove etc in our code in order to get the most out of it, and then continue the reading.
First of all, we can change "mov es:[di],al" into the more fitting "stosb"...the result is exactly the same. The other thing we can do is to try to remove the "mul" instruction. Why? Because it's slow! A mul instruction can take as much as 42 (the answer to everything - I hope you know your Douglas Adams) clock cykles. Now I'm going to teach you something really usefull! How to optimize your code using SHL and SHR!
Have you ever thought about how nice the instruction SHL (shift left) can be? We can use it in our multiplications instead of using MUL, but it's rather limited. It can only handle an even 2-potency (ie 2^0, 2^1, 2^2, 2^3 etc...). So let's say we want to calculate 5*256. This can be done like this:
mov ax,5 Shl ax,8 ;2^8 = 256.
Now is'nt that cool? And the best part is that SHL only takes one clock cykle! You can use SHR in the same way, if you want to divide something with an even 2-potency.
"But SHL cant solve our problem! 320 isnt an even 2-potency! you'll shout now. Well, you're half right. 320 isnt an even 2-potency, but we can still use SHL to help us out. Ever thought of what 256+64 is? That's right - 320! So, here is the optimized code for our offset calculation:
mov di,y mov bx,di shl bx,8 ;We can change this line into "xchg bh,bl". This is a good shl di,6 ;way to multiply something with 256. add di,bx add di,x mov offs,di
Grrrrreat! Not a single MUL! I'll present now the whole code to display a pixel on screen. Just Cut&Paste the text and compile it with
c:\..\>tasm pixel.asm
c:\..\>tlink /t pixel.obj.
;--------------------------------------------------------------------------------------- ; PIXEL.ASM - Prints a pixel to the screen, TASM version. Written by Cruehead / MiB '98 ;--------------------------------------------------------------------------------------- .MODEL SMALL .CODE .386 org 100h START: jmp StartMeUp x dw 50 ;Play with these values and see how the location of the pixel changes y dw 40 StartMeUp: mov ax,0013h ;Change mode to 320*200*256 int 10h mov ax,0a000h ;Start of video VGA memory mov es,ax mov di,y ;Calculate offset mov bx,di xchg bh,bl shl di,6 add di,bx add di,x mov al,10 ;Use color number 10 from the standard VGA palette stosb waitagain: in al,60h ;This will wait until the user has pressed the ESC button cmp al,1 jnz waitagain mov ax,0003h ;We have to switch back to textmode when we're finnished int 10h mov ax,4c00h ;Leave control back to DOS int 21h END START
As usuall, if you want to ask me something, my email is cruehead_@hotmail.com.
Cruehead / MiB'98
Copyright © MiB 1998. All rights reversed.