• Please review our updated Terms and Rules here

CGA graphic lib

JoJo_ReloadeD

Experienced Member
Joined
May 12, 2007
Messages
120
Hello everyone,

I am trying to create a C CGA graphic library, and so far I have:

- plotting in 320 mode (asm)
- plotting in 160 mode (asm)
- line drawing in 320 mode (c)
- palette change (asm)


I need to optimize them (lookup tables), and to create blitting functions for every mode. Does anybody know of docs or one library itself ?

Also, if anybody knows of the same, but for EGA it would be nice.

Thanks!
 
I started the same thing but never finished it, but you're welcome to pilfer anything you can use: ftp://ftp.oldskool.org/pub/misc/code/CGA.rar

About the only things in there that are worth anything is the MC6845.PAS which has the 6845 very well mapped out and documented, and WILT*.INC which contains near optimal line-drawing for 320/640x200 (and I think my modifications for 160x200x16 as well). There are some tweak modes (160x100x16, 40x50, 40x100, 80x50, 80x100) but that code is generic, I never got around to optimizing it. Also, some of the example programs (TEST*.PAS) do not work with the latest version of the library, but TESTPIX and TESTLINE do and that should be enough for you to compile and run everything.

In ftp://ftp.oldskool.org/pub/misc/code/ is some other code you might be interested in, including TINTERRUP.PAS which includes code to simulate a vertical retrace interrupt for CGA cards (only).
 
I started the same thing but never finished it, but you're welcome to pilfer anything you can use: ftp://ftp.oldskool.org/pub/misc/code/CGA.rar

About the only things in there that are worth anything is the MC6845.PAS which has the 6845 very well mapped out and documented, and WILT*.INC which contains near optimal line-drawing for 320/640x200 (and I think my modifications for 160x200x16 as well). There are some tweak modes (160x100x16, 40x50, 40x100, 80x50, 80x100) but that code is generic, I never got around to optimizing it. Also, some of the example programs (TEST*.PAS) do not work with the latest version of the library, but TESTPIX and TESTLINE do and that should be enough for you to compile and run everything.

In ftp://ftp.oldskool.org/pub/misc/code/ is some other code you might be interested in, including TINTERRUP.PAS which includes code to simulate a vertical retrace interrupt for CGA cards (only).

Thank you so much! :D
 
One trick I've used that might help you speed things up a bit -- instead of wasting time trying to pass the color as 0..3 in color modes, pass it as a populated pixel-packed. For example:
color 0 = 0x00
color 1 = 0x55
color 2 = 0xAA
color 3 = 0xFF

Instead of doing shifts to come up with your mask, you can make a simple 4 byte array to XLAT into:
maskArray : array[0..3] of byte = ( $03, $0C, $30, $C0 );

then for a putpixel you'd

Code:
{ assumes es:di is video byte }
mov  bx, OFFSET maskArray
mov  ax, xCoord
and  al, 3
xlat
mov  ah, al
not  al
and  al, es:[di]
and  ah, color
or   al, ah
stosb

It's easier to take your mask then AND it to the pixel-packed color byte then use a NOT copy of the mask to AND the video location against, than it is to sit there playing with shl al, cl. I'm basically doing the same thing with my font output routines for 160x100 in my current WIP faster 160x100 engine.

Also, if you want more code to look at, you're welcome to look at my 160x100 code from paku paku. It's mostly inline assembler so should'nae be too hard to move over to C.
http://www.deathshadow.com/pakuPaku

The full source for the game is in the archive. The video card detection code might be useful to you -- the sprite functions probably not so much since they are very 'engine specific'.
 
I was digging through some old code, and remembered about my trick for CGA address calculation.

Code:
mov   cl, 2
mov   ax, yCoord
ror   ax, 1
xor   bx, bx
xchg  bh, ah
shr   bx, cl
mov   di, bx
shr   ax, cl
add   di, ax
shr   ax, cl
add   di, ax
mov   ax, xCoord
mov   bx, ax
xchg  ah, al
shr   bx, cl
add   di, bx
mov   bx, OFFSET maskTable
and   al, $03
xlat

Sneaky trick, the rotate moves that bottom yCoord bit into the upper byte, move that into BX and shift it twice, and you have either 0x2000 or 0x0000 as the result, so set DI to that. clearing BX and using XCHG to isolate that means another shift 2 on AX and we have trunc(yCoord/2)*64, so add that to DI, then shift two more times for *16 and we have our *80. xCoord is simpler since it's just a load it into AX and BX, shift BX to get our X offset and add that to DI, and AL by $03 to get our xlat index value.

The use of CL for those 2x shifts might seem odd since it's a slower operation (8+4n, so 16!), but it's two less memory bytes fetched and the execution time lets the BUI fill up, meaning on a 8088 it's actually faster than unrolling them overall -- the extra execution time means the next 4 bytes of opcodes will have no load penalty, and it's two less bytes for the opcodes themselves. Sounds strange, but it works. The conventional wisdom of unrolling shifts doesn't always jive with real world, especially when they're all the same shift amount.
 
Back
Top