Pix's Graphics in Assembler Page

This page chronicles verbatim my journey teaching myself the arcane art of demo coding... This goes all the way back to the yrs post 1996 when I just graduated from junior college and just got my hands on my very first PC. Those were the days of the 14.4k / 28.8k modems, BBSs, and when the internet is just in it's infancy. It was a time when access to information was not as easy as it is with Google being around like today. There was no graphics API such as OpenGL and everything has to be done by your own, down to the last plot of every single pixel.... and you have all sorts of other fun things like Real Mode (segmented memory with segment:offset pairs addressing a max of 64K at time), Protected Mode (where you can address a full 2^32 memory address space). You can read all about it here.
 
The codes and routines hereon will be that of a 17 yr old replicated verbatim :)
 

Switching into VGA mode

The standard video modes used back in those days were Mode 19, or Mode 0x13, which is 320x200 with 256 colors (8 bits per pixel). The very first graphics library routine in my gfx library code is to switch from text mode to mode 0x13. This can be simply accomplished by the C with inline asm routines below. In the below we have a version using Turbo C++ and the other using DJGPP. Initially the code base was done using Turbo C++ and subsequently moved to DJGPP... and the below showcases the difference between the 2 compiler and their assembly syntax.
 

 Turbo C++

DJGPP

void initmode(void)
{
  asm{
        mov ax, 0x13
        int 0x10
  }
}
Note the above Intel syntax for assembler statements 
void initmode(void)
{
  __dpmi_regs r;

  r.x.ax=0x13;
  __dpmi_int(0x10, &r);
}

The above simply sets the ax register with the value 0x13 and invokes interrupt 10h. To return to text mode, we simply need to load ax register with 0x03 and call interrupt 10h.

Setting the Color Palette

In VGA mode 0x13 we have a paletted color mode with the coder being free to choose up to 256 colors out of a max of 16.7M colors. The paletted color mode maps a color index number from 0 to 255 to a preset RGB tuple from (0, 0, 0) to (255, 255, 255). For example, the coder can set color 0 to be (255, 255, 255) which will be white, and color 1 to (255, 0, 0), which is red. Subsequently, everywhere in the frame buffer that has a 0 written to it will be rendered white, and everywhere that has 1 will be rendered red. The following routine sets a particular color index to the given RGB tuple, 
 
void setcol(byte ColNo, byte r, byte g, byte b)
{
  __asm__ __volatile__
  ("
    movw $0x03C8,%%edx //----------------------------
    movb %0,%%eax      //selects col no
    outb %%al,%%dx     //----------------------------
    incw  %%edx
    movb %1,%%eax
    outb %%eax,%%dx     //output r value to port
    movb %2,%%eax
    outb %%eax,%%dx     //output g value to port
    movb %3,%%eax
    outb %%eax,%%dx     //output b value to port
   "
   :
   :"g" (ColNo),"g" (r),"g" (g),"g" (b) //pre load regs.....
   :"eax","edx"
  );
}
In the above, byte is a typedef for unsigned char. The routine outputs the color index to port 0x03C8 followed by the R, G, B values to port 0x03C9. We can see in the above the AT&T syntax used by the DJGPP source routine, the most obvious is the flipping of source and destination operands in the assembly statements.
 

Syncing to Vertical and Horizontal Retrace

For a good explanation of what vertical/horizontal retrace is refer to here. Basically, in graphics programming one of the basic techniques is Double Buffering, in which we draw to an off-screen buffer before they are "blit"-ed to video memory. The purpose of syncing to the vertical retrace is so that we do not copy the off-screen buffer to video memory in the middle of a vertical retrace, as this will result in "tearing". The following code fragment performs waiting till a vertical retrace ends and returns,
 
void vtrace(void)
{
  __asm__ __volatile__
  ("
    movw $0x3DA,%%dx
i1:
    inb  %%dx,%%al   /*gets port val and perform AND, when we are in the*/
    test $0x08,%%al  /*middle of a retrace, port val is always 0x80 and the*/
    jnz  i1          /*AND returns true so we jump back and test again until*/
                     /*retrace is over...*/
i2:
    inb  %%dx,%%al   /*gets port val and perform AND, when we are in the*/
    test $0x08,%%al  /*midst of drawing a screen, port val is not 0x80,*/
    jz   i2         /*AND returns false so we jump back and test again until*/
    "                 /*the drawing is over so we'll be at the start of a vtrc*/
                     /*once we get out*/
    :
    :
    :"eax","edx"
  );
}
Using vtrace(), we invoke it followed by swapping the off-screen buffer to video memory. To sync to the vertical retrace, we just need to do the 'test' instruction against 0x01 instead of 0x08 above. Syncing to the horizontal retrace enables interesting text mode "copper" effects