Question

Well, I'm making a Space Invaders game on Assembly x86 ( 8086 ), and it runs pretty good so far. I'm using assembly in graphics mode 13h, that means 320x200 pixels and 256 colors.

For drawing I'm using the sub-function 0ch, that means that I'm drawing pixel by pixel. The problem is that the screen is cleared pretty fast and causes some visual glitches.

I've programmed some games before and the solution may be double buffered drawing. How to achieve this in Assembly x86?

Edit

I'm using Windows 8 X64, for testing and running my code DOSBox Portable, tasm and tlink.

Was it helpful?

Solution

You'd need a buffer in RAM (320*200 = 64000 bytes). This buffer almost fills a segment, so it's probably best to make sure that the address for the start of the buffer is "segment:0x0000". You'd draw things by setting pixels/bytes in this buffer in RAM. For example, to set the pixel at (x,y) to colour c you might do:

mov ax,[y]
mov dx,320
mul dx               ;dx:ax = y * 320
mov di,[x]           ;di = x
add di,ax            ;di = y * 320 + x
mov bx,[bufferSeg]   ;bx = segment of video buffer
mov es,bx            ;es:di = address of pixel
mov al,[c]           ;al = colour
mov [es:di],al       ;Store colour in buffer at (x,y)

As you can see this calculation is messy/slow; and you wouldn't want to do it for every single pixel. Fortunately you almost never need to draw individual pixels (normally you're drawing lines or characters, or "sprites") and normally you can calculate the address of the first pixel and then add something to it to find the address of the next pixel instead of calculating the address of the next pixel from scratch. For example, for drawing a vertical line the address of the next pixel is the address of the previous pixel + 320.

For graphics mode 0x13; display memory is at physical address 0x000A0000 (or 0xA000:0x0000). After drawing everything, you'd copy everything from the buffer to display memory. For example:

mov ds,ax              ;ds = segment for buffer
xor si,si              ;si:si = address for buffer
mov ax,0xA000          ;ax = segment for display memory
mov di,ax              ;di = segment for display memory
mov es,ax              ;es:di = address for display memory
mov cx,320*200/2       ;cx = number of words to copy
cld                    ;Make sure direction flag is clear
rep movsw              ;Copy 320*200/2 words from buffer to display memory

OTHER TIPS

mov es,[bufferSeg] works. you don't need to use an extra register when doing segment/memory and memory/segment mov.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top