Page 1 of 1

Drawing Lines

Posted: Fri Jun 13, 2008 10:39 pm
by Omega
Hi. How do you draw lines in Pmode? I have a menu and would like to draw a box around it in C. Thanks.

Posted: Fri Jun 13, 2008 11:11 pm
by Pyrofan1

Posted: Sat Jun 14, 2008 2:14 am
by Ready4Dis
Well, you are a bit cryptic on your description. So, you have a menu, I am assuming this is in text mode? if that's the case, you can draw lines using special ascii codes, look up the ascii character map. Here are the ones of interest:

196 is a horizontal section
179 is vertical section
218 = top left corner
217 = bottom right corner
191 = top right
192 = bottom left

So, you simply draw your horizontal and vertical lines around the menu, then and fill in the 4 corners with the above ascii values. I have a nice text based window drawing routine, using this, there is also a double thick line, useful in some other cases, take a peek at the standard ascii map though, should give you an idea.

Posted: Sat Jun 14, 2008 2:58 am
by Omega
Thanks, that was going to be my next question.
void plot_pixel(int x,int y,unsigned char color)
{
char *vga = (char *) 0xb8000;
unsigned int i = 160*y + 2*x;
i = 160*y + 2*x;
vga[i++] = color;
}
Example Usage wrote: plot_pixel(1, 1, 0xDA);
Now the fun is writing my own drawing routine. =)

Posted: Sat Jun 14, 2008 3:28 am
by Pyrofan1
void plot_pixel(int x,int y,unsigned char color)
{
char *vga = (char *) 0xb8000;
unsigned int i = 160*y + 2*x;
i = 160*y + 2*x;
vga[i++] = color;
}
That code will not work at all, 0xb8000 is color text memory, graphic memory is located at 0xa0000 if i'm not mistaken.

Posted: Sat Jun 14, 2008 3:33 am
by JamesM
Pyrofan1 wrote:
void plot_pixel(int x,int y,unsigned char color)
{
char *vga = (char *) 0xb8000;
unsigned int i = 160*y + 2*x;
i = 160*y + 2*x;
vga[i++] = color;
}
That code will not work at all, 0xb8000 is color text memory, graphic memory is located at 0xa0000 if i'm not mistaken.
You're not mistaken - I was just about to write that same reply.

Posted: Sat Jun 14, 2008 4:02 am
by Omega
It works for me. I just wrote a routine that draws the box around my menu using that function.

Code: Select all

void draw_box(void)
{
	int y=0;
	plot_pixel((13/2)-1,7,0xDA); //left corner
	for(y=0;y<37;y++) { plot_pixel((13/2)+y,7,0xC4); } //top line
	plot_pixel((13/2)+37,7,0xBF); //right corner
	//*******************
	int u=0;
	for(u=8;u<14;u++) { plot_pixel((13/2)-1,u,0xB3); } //left side
	//*******************
	int s=0;
	for(s=8;s<14;s++) { plot_pixel((13/2)+37,s,0xB3); } //right side
	//*******************
	int r=0;
	plot_pixel((13/2)-1,14,0xC0); //left corner
	for(r=0;r<37;r++) { plot_pixel((13/2)+r,14,0xC4); } //bottom line
	plot_pixel((13/2)+37,14,0xD9); //right corner
}

Posted: Sat Jun 14, 2008 4:22 am
by JamesM
vst_0201 wrote:It works for me. I just wrote a routine that draws the box around my menu using that function.

Code: Select all

void draw_box(void)
{
	int y=0;
	plot_pixel((13/2)-1,7,0xDA); //left corner
	for(y=0;y<37;y++) { plot_pixel((13/2)+y,7,0xC4); } //top line
	plot_pixel((13/2)+37,7,0xBF); //right corner
	//*******************
	int u=0;
	for(u=8;u<14;u++) { plot_pixel((13/2)-1,u,0xB3); } //left side
	//*******************
	int s=0;
	for(s=8;s<14;s++) { plot_pixel((13/2)+37,s,0xB3); } //right side
	//*******************
	int r=0;
	plot_pixel((13/2)-1,14,0xC0); //left corner
	for(r=0;r<37;r++) { plot_pixel((13/2)+r,14,0xC4); } //bottom line
	plot_pixel((13/2)+37,14,0xD9); //right corner
}
Not trying to be fancy... =)
Not trying to be fancy, but you could at least have used function and parameter names that actually describe what the function is intended to do.

(1) plot_pixel doesn't really plot a pixel, does it? it puts a character at a certain place on the screen.
(2) the "color" parameter isn't a colour, is it? it's an ASCII character code.

Can you see why we were confused?

Posted: Sat Jun 14, 2008 4:24 am
by Omega
Right, my mistake. No problem, I can fix it. thanks =)

Posted: Sat Jun 14, 2008 5:18 am
by Ready4Dis
Glad it's working, not to difficult. I agree though, I would fix up your function naming, will confuse yourself later when you look back at it.

Posted: Sat Jun 14, 2008 2:12 pm
by Omega
I changed it, so here is the updated function and routine.

Code: Select all

void plot_ascii(int x,int y,unsigned char ascii)
{
	char *vga = (char *) 0xb8000;
	unsigned int i = 160*y + 2*x;
	i = 160*y + 2*x;
	vga[i++] = ascii;
}
And, for those in need of this code, you would use it like so:

Code: Select all

void draw_box(void)
{
   int y=0;
   plot_ascii((13/2)-1,7,0xDA); //left corner
   for(y=0;y<37;y++) { plot_ascii((13/2)+y,7,0xC4); } //top line
   plot_ascii((13/2)+37,7,0xBF); //right corner
   //*******************
   int u=0;
   for(u=8;u<14;u++) { plot_ascii((13/2)-1,u,0xB3); } //left side
   //*******************
   int s=0;
   for(s=8;s<14;s++) { plot_ascii((13/2)+37,s,0xB3); } //right side
   //*******************
   int r=0;
   plot_ascii((13/2)-1,14,0xC0); //left corner
   for(r=0;r<37;r++) { plot_ascii((13/2)+r,14,0xC4); } //bottom line
   plot_ascii((13/2)+37,14,0xD9); //right corner
}
Of course you would need to change the x and y values to suit your own needs/design. Thanks

Posted: Sun Jun 15, 2008 2:26 am
by Ready4Dis
I wrote mine a bit differently to be more efficient, plus to have variable sized boxes. I can use this for text based windows, or messages, etc. Here is my function for comparison:

Code: Select all


typedef unsiged long u32;
typedef unsigned short u16;

u16 *ScreenPtr16 = (u16*)0xB8000;

struct Rect_S
{
	u32	x1,y1,x2,y2;
};

//Used to display windows/menus
u16	Pieces[11] =
{
	218,		//Top Left
	192,		//Bottom Left
	191,		//Top Right
	217,		//Bottom Right
	196,		//Straight Horizontal
	179,		//Straight Vertical
	194,		//Split Vertical Down
	193,		//Split Vertical Up
	195,		//Split Horizontal Right
	180,		//Split Horizontal Left
	197		//Cross
};

void DrawBox(struct Rect_S *rect, u32 Color)	//Draws a box :)
{
	u32 Ctr, Off1, Off2;
	Off1 = rect->y1*80+rect->x1;
	Off2 = rect->y2*80+rect->x1;

	ScreenPtr16[Off1] = Pieces[0]+Color;
	ScreenPtr16[Off2] = Pieces[1]+Color;

	++Off1;
	++Off2;
	for (Ctr=0;Ctr!=rect->x2-rect->x1-1;++Ctr)
	{
		ScreenPtr16[Off1] = Pieces[4]+Color;
		ScreenPtr16[Off2] = Pieces[4]+Color;
		++Off1;
		++Off2;
	}
	ScreenPtr16[Off1] = Pieces[2]+Color;
	ScreenPtr16[Off2] = Pieces[3]+Color;

	Off1 = rect->y1*80+rect->x1;
	Off2 = rect->y1*80+rect->x2;
	for (Ctr=0;Ctr!=rect->y2-rect->y1-1;++Ctr)
	{
		Off1+=80;
		Off2+=80;
		ScreenPtr16[Off1] = Pieces[5]+Color;
		ScreenPtr16[Off2] = Pieces[5]+Color;
	}
}
This will draw a box using a color, however for the color it goes like this:

Color = (Background << 12 ) + (Foreground << 8 );

Each one can be 4-bits wide, so 16 colors each. This is so I can draw windows, menu's, etc in any color comination as well as any location and size. I also have a window structure that holds the position, size and name, and draws a window with title. Pretty useless since I have VESA support, and have never used this code beyond testing, but hopefully it gets some use to help others. It's pretty well optimized, so it should be plenty fast for text mode ;).

Posted: Sun Jun 15, 2008 3:30 am
by Omega
Yours is much better and more useful as mine has hard-coded x and y values and is much too custom to present itself as a useful snippet to the masses. I am storing this one in my dev folder just in case I decide to start fencing in my content. Nice work, thanks a lot

Posted: Sun Jun 15, 2008 9:09 am
by Ready4Dis
Well, hopefully it's useful for someone. I also have the scan-code in my list of pieces for splitting the box (like breaks between menu's, or seperating a window into multiple sections), so it can be pretty useful for a text-based GUI, menu system, IDE or Shell of sorts. Hope it goes to some use, wrote it and never used it beyond testing to make sure it worked, haha.