In this lesson we'll see the basics of
working in a graphics mode: How to put the 320x200x256 mode, how to exit
of it, how to draw pixels, how to use the palette,...Well, all the basics,
like i said.
Of course, most of the code is programmed in Asm, for optimization (we need speed in graphics mode).
Basics of 320x200x256 Mode
Put some colors into your life
Behind Scenario: Virtual Screens
Segment and offset
Memory in Intel 80x86 in real mode (MS-DOS)
use segment:offset to access to one byte. This
means that if i want to put/get a byte in memory, i must give these two
values, instead of a linear address.
Segment and offset are usually in hexadecimal.
Segment:Offset is equivalent to (Segment*16)+Offset.
Example:A000h:0001h it's 655361 (in linear address).
MS-DOS can't take a byte above F000:FFFF->FFFFF-> nearly 1Mb. This's THE barrier. If we want to use the addresses above 1Mb, we need to use EMS or XMS. Or protected mode. Or Win95 + DirectX.
Communications between programs and Hw
(video cards, HDD controllers,...) are done by ports. If i want to send/receive
data to/from Hw we need to use ports.
In Pascal, ports are a predefined arrays: PORT y PORTW. One manages 8 bits ports, and the another manages 16 bits ports.
BASICS OF 320x200x256 MODE
How to start (and end) the 13h mode
For start the 320x200x256 mode (13h),
interrupts are a must. We make a call to interrupt 10h (screen services).
Inside this interrupt we use service 0h (active a graphics mode) with parameter
13h (mode 13h). And voilà!!!, we're in 320x200x256.
(If you don't know anythng of assembler, no problem. The only important thing is to use the code, not know how are made).
Code: [ mov ah,0; mov al,13h; int 10h ]
For exit, we use the same interrupt and service, but with parameter 03h (text mode)
Pixels. Where are, and how to change them
In every graphics mode, screen is "mapped"
on memory. This mean that one pixel in the screen is one byte in memory.
How? in this way:
MEMORY (64000 contiguous bytes starting in DESPLZ)
SCREEN (320 columns and 200 rows)
There's an equivalence between memory
and screen: DESPLZ:(320*row)+column<=>(row,column)
Example: one pixel in row 1, column 2, it's in DESPLZ:(320*1)+2=DESPLZ:322.
And what is DESPLZ ? Segment A000h. So, the first position of the screen in memory is the byte A000h:0000h.
Then, If i want to draw one pixel of color P (one pixel is a byte=[0..255] -> you know now why we have 256 colors ^_^) in row R, column C, i must make one operation:
Now we have color P in row R, column C of the screen.
PUT SOME COLORS INTO YOUR LIFE
As you know, one color is made by mixing
For example: black is the mix of no colors, white is the mix of all the colors, and violet is red+blue.
In PC, the mechanism is the same (mix colors). Every color is the combination of some basic colors.
In 320x200x256 mode, colors are red, el green and blue. So RGB=R(ed)G(reen)B(lue).
These three colors have 64 degrees of intensity (0..63) (this is cuz we use 6 bits for intensity: 26). When we join these intensities, we obtain one color (R,G,B):
Example: red (63,0,0) joins blue (0,0,63) and violet is the result (63,0,63) ^_^
Palette is a set of colors (in this mode 256), and everyone is made with the method described above (combination Red.Green-Blue). We can say that we have an array of 256 elements, and one element is the result is three intensities: (R[0..63],V[0..63],A[0..63]).
Where's the palette?. Here.
DAC is a Digital to Analogic Converter. It converts RGB intensities to colors in the screen (said fast and not very well ^_^).
It has 256 registers of 18 bits (<-palette), and every one of these registers has the RGB intensities. When in screen we draw the pixel x (23, f. ex.), x is the index to one of the DAC registers.
DAC has some ports, and through them we can read/write the RGB intensities of every color:
|3C7h (Pel Read Address)||Index to a color to access(0..255)|
|3C8h (Pel Write Address)||Index to a color to change(0..255)|
|3C9h (Pel Data DAC)||Access to a DAC register|
How to use DAC ports and BIOS to change the intensity of colors.
Read a DAC register (read the RGB
components of a color):
Set in port 3C7h the color to be accessed. Next we read three times the port 3C9h, and we obtain the RGB components (1º red, 2º green y 3º blue).
Change a DAC register (write the RGB
components of a color):
Set in port 3C8h the color to be changed. Next we write in 3C9h the RGB components (1º red, 2º green y 3º blue, three writes).
Change an entire palette (using BIOS
(I suppose we have a var. called Palette => Array 0..255 of r,g,b:byte).
Use interrupt 10h, service 10h, subfunction (al) 12h (change DAC components).Bx=0 (start in the first color, 0), Cx=256 (change 256 colors), Es:Dx=Seg(Palette):Ofs(Palette) (Segment and Offset of variable palette).
NOTE: the record r,g,b:byte is in this order 'cause system takes the first component of the record as R, second as G and third as B.
(Thanks to PCActual magazine and to Antonio Ropero)
The image in screen bring up-to-date
its contents from video memory, $A000:0000 (this can't be saw by human
eyes, but videocameras can: try to film your monitor).
And how happens? An electron beam starts in the first line of the upper left corner, and goes to the right. When it arrives into the edge of the right, goes to the next line. It ends in the lower right corner. (see that the beam starts in the start of video memory and ends in the end of video memory. Look at tables in Pixels. Where are, and how to change them).
This process is iterative.
What is Vertical retrace?
When the beam arrives to the lower right corner, it goes to the upper left corner. This moment is called vertical retrace.
What problems have?
The vertical retrace have no problems
^_^. But the beam has: If we draw an sprite in the screen when the beam
is working, the sprite may flick (cuz not the entire image'll be draw,
only the part after the beam).
Example: if we draw an sprite $A000:3FF0 a $A000:4005 and the beam is in $A000:4000, only the range of pixels $A000:4000=>$A000:4005 will be displayed (the other pixels of the sprite must wait the next beam).
How can I avoid flickering?
Waiting the vertical retrace. In this
moment the beam will be in $A000:0000 and every pixel we draw will be put
And V.R. has another good thing: makes an universal delay for every computer (cuz V.R. not depends on microprocessor Mhz).
BEHIND SCENARIO: VIRTUAL SCREENS
What are virtual screens?
Remember that screen is mapped in memory
(1 pixel=>one byte in video memory). Well then, a virtual screen is a variable
that imitates the structure of video memory (Array[0..63999] of byte).
If we imitate the structure of video memory, we can "draw" pixels (write bytes) onto this "screen", using the segment of the virtual screen: SegVirtual:[(320*R)+C]. Of course every "pixel" in this "screen" won't be wrote in the real screen.
How can i use them
If we draw the scenario and the sprites in the real screen, the gift will be a brutal flickering.
So we draw the pixel onto the virtual
screen, wait the vertical retrace and flip the contents of the virtual
screen onto memory. (We copy the 64000 bytes of v.s.to [$A000:0000,$A000:FFFF]).
Then, there'll be no flick with this method.
Virtual screens have more uses: scrolls, backups,...etc. See the next lessons of this tutorial.
In the .zip with the game there's two
files: G320x200.pas and virtuals.pas. They have the routines
of all the things explained in this file, with more things
Well, its 3:35 am, i want to sleep,... Why i don't use a translator like everybody in this world ?. I suppose i'm a @·$%¿?!, but translators are @#!#?¡# ....^_^.