Page 1 of 1

Graphics Modes

Posted: Mon Aug 24, 2009 8:10 pm
by pathos
Well, it's pretty quiet around here, so I'll get some discussion going.

I've been trying to figure out how to work in different VGA modes other than 80x24 text mode, specifically VGA 640x480x16. I use the BIOS interrupt 10h in real mode to get there and that's really all I know, and I can't find much information out there. I know the new video memory location is 0xA0000, but whenever I try to set a pixel, the best I can do is one white one.

Does anyone know of any resources out that can help me out? Much appreciated.

Re: Graphics Modes

Posted: Tue Aug 25, 2009 4:53 am
by Mike
Hello,

Are you referring to 640x480x16 colors ("aka Mode 12h") ?

...If so, I can post some of my video driver for some examples.

Re: Graphics Modes

Posted: Tue Aug 25, 2009 1:14 pm
by pathos
Mike wrote:Hello,

Are you referring to 640x480x16 colors ("aka Mode 12h") ?

...If so, I can post some of my video driver for some examples.


Yes, I am; sorry for dropping the word "colors."

If you don't mind, I'd like to see your code. But I understand if you're protective of it!

Re: Graphics Modes

Posted: Tue Aug 25, 2009 5:43 pm
by Mike
Hello,

Mode 12h has 4 planes. Because its 4 bits per pixel, each bit is in a different plane, so it fits in 1 bit per plane. To write a pixel, you have to mask out the bits that you want to set across all four planes. This means that you will need to update the VGA mask register when writing pixels. Afterwords setting write mode 2 to allow writing to display memory to replicate across all four bit planes so the pixels written to display appear correctly on screen.

You can do this via VGA BIOS interrupts or port i/o.

Doing this to clear the screen isnt too hard. What it does is select to write to all 4 bit planes per pixel at once, 8 pixels at a time. After selecting what to write to it, basically, it writes it to display.

Code: Select all

void
VidClear (CHAR Color) {

   PBYTE VideoMemory = (PBYTE) 0xa0000;

   //! select graphics bit mask register
   outportb (0x3ce, 8);

   //! mask entire color byte so we write to 8 pixels at once
   outportb (0x3cf, 0xff);

   //! select graphics mode register
   outportb (0x3ce, 5);

   //! select write mode 2 (replicate bits 0-3 of data across all 4 planes)
   outportb (0x3cf, 2);

   //! write pixels...
   memset (VideoMemory, Color, (640/8)*480);
}

For plotting a single pixel is a little more complex and a little hard to explain without visually seeing it. Basically it masks out what pixel to set and selects the write mode to write the data to that pixel's all 4 planes. This allows us to write the pixel to display memory correctly.

Code: Select all

void
VidPlotPixel (IN WORD x,
           IN WORD y,
           IN BYTE c) {

   PBYTE VideoMemory = (PBYTE) 0xa0000;
   UINT Offset = y * (640/8) + (x/8);
   BYTE BitMask = x;
   BYTE Shift = 1;
   static BYTE Latch = 0; //static to insure its not optomized out

   BitMask &= 7;
   BitMask ^= 7;
   Shift <<= BitMask;

   //! select graphics bit mask register
   outportb (0x3ce, 8);

   //! mask off pixel bit to set
   outportb (0x3cf, Shift);

   //! select graphics mode register
   outportb (0x3ce, 5);

   //! select write mode 2 (replicate bits 0-3 of data across all 4 planes)
   outportb (0x3cf, 2);

   //! load the data into the internal latch register (needed for bit mask register)
   Latch = VideoMemory [Offset];

   //! write the pixel
   VideoMemory [Offset] = c;
}

Its easier to see how everything works with a VGA reference at hand.

Re: Graphics Modes

Posted: Tue Aug 25, 2009 7:19 pm
by pathos
Wow, thanks. I didn't know about the four planes thing, which would probably explain my odd results.

[edit]
Thanks again, it works great!

Re: Graphics Modes

Posted: Tue Aug 25, 2009 9:19 pm
by pathos
One more question =)

Now I want to draw a character to the screen. I've figured out how, using an 8x8 bitmap, but my question is what's the fastest way to draw it.

For example, let's say I have letter_A, letter_B, and letter_C. I want to write "ABC." I don't want to have "If character = A, then buffer=letter_A" all the way down the alphabet, numbers, symbols, etc, before I run it through the loop to draw the pixels in the right spot. What's a fast way to recognize the letters and get them into the loop?

Example (I think this is too slow):

Code: Select all

void vga_putc(UCHAR c)
{
   UCHAR letter[8];

   if (c == 'A')
   {
      for(int i = 0; i < 8; i++)
      {
         letter[i] = small_A[i];
      }
   }

   for(USHORT i = 0; i < 8; i++)
   {
      for(USHORT j = 0; j < 8; j++)
      {
         if(CHECK_BIT(letter[i], j))
         {
            vga_plot_pixel(cursor_x+j, cursor_y+i, 0xA);
         }
      }
   }
}

Also, while I've got the above code up there, for some reason it's printing characters out twice. Any idea why?

Re: Graphics Modes

Posted: Wed Aug 26, 2009 8:00 pm
by Mike
Hello,

Perhaps this: Have a two dimensional array representing an array of all of the characters arrays. So char[a] would be the array of your 'a' bitmap, char[ b ] would be your 'b' bitmap and so on.

So, assuming that char[0] is your bitmap of the NUL character, a simple UCHAR* letter = &_Characaters ['c'];, where c is the character to display should work.

*Please keep in mind that I never used this method as I handle things very differently here. However it should work and be effective to use.

Re: Graphics Modes

Posted: Wed Aug 26, 2009 8:11 pm
by pathos
That's kinda what I was thinking of doing, I just haven't had the chance to work on it.