中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
作者:
标题: DJGPP教程2 -- VGA编程 上一主题 | 下一主题
Wengier
系统支持

“新DOS时代”站长


积分 27734
发帖 10521
注册 2002-10-9
状态 离线
『楼 主』:  DJGPP教程2 -- VGA编程

In this page I'll explain how to programming the VGA at a resolution of 320x200x256. I will also include a demo program (see it later).

Structure of the video memory at 320x200x256
The memory structure at this resolution is very simple to use: is only a sequence of bytes mapped in the central memory. First, remember this: a pixel on the screen is a byte in the memory. So at a resolution of 320x200 the screen use 64000 bytes of memory. This memory start at the address A000:0000 (A0000 in protected mode) of the main memory. Under a real mode system is simple to access at this memory by using a far pointer, like this:

        char far *vgamemory = (char *)0xA0000000L;

or (on old compilators)

        char far *vgamemory = (char *)MK_FP(0xA000, 0);

But under DJGPP isn't so simple because the memory is protected, so you can't access directly to all the memory of the system. The best solution is to disable the protection of the DOS memory by calling the procedure __djgpp_nearptr_enable(). There are a simple code that shows how to access at the DOS memory:

        #include

        __djgpp_nearptr_enable();
        vgamemory=(char *)(0xa0000 + __djgpp_conventional_base);

         __djgpp_nearptr_disable();

The header nearptr.h is necessary for the prototipes of the functions. We should use __djgpp_conventional_base to get the right address of the DOS memory (the protected mode is very intricate). At the end of the program, use __djgpp_nearptr_disable() to get the program back to regular protected mode. But you must remember that with this code you disable the protection of the memory, so you can damage the DOS area and block the system. Use the program info (you must download the file txi390b.zip) for more informations.
For clearing the screen with a specified color simply call the function memset() with a pointer to the video memory.

Setting the VGA mode 320x200x256
The BIOS supplies a procedure that provide to set the VGA mode 320x200x256 via interrupt 10h. We must only set a register (ax) and call this interrupt. To return to the text mode (usually mode 03h) we can use the same procedure. There are the simple code to swap to the wanted mode:

#define TEXT_MODE 0x03
#define VGA_MODE  0x13

void setmode(short mode)
{
        union REGS regs;

        regs.h.ah = 0x00;          // Procedure 0x00: Set Video Mode
        regs.h.al = mode;          // The requested video mode
        int86(0x10,&regs,&regs)          // Call the BIOS
}

If you set the most significant bit of the register al (use 0x93 instead of 0x13) the video memory is not cleared. If you don't like to use the BIOS you can download the file modes.zip that explain how to set the video mode without the BIOS.

Put the first pixel
In the paragraph Structure of the video memory I've introduced how to access to the video memory. Now is very simple to draw a pixel: is enough to write at the right offset in the video memory. So I've draw a simple image to explain how the video memory is used at this resolution:
If you write a color byte at the start of the video memory (A000:0000) you'll show a pixel at the upper-left corner of the screen (0, 0). When you write at the offset 319 (A000:013F) you'll show a pixel at the upper right corner. Writing at the next byte (A000:0140) and the pixel will appear at the position (0, 1). So we can understand that if we want to show a pixel at the position (x, y) we must write at the address A000:(y*320+x) of the video memory. This is a fast method for write a pixel. But we can optimize a bit the speed by using shifting instead of multiplications. So we divide the number 320 into the powers of two 256 and 64 and we have  320y = 256y + 64y  and next  offset = (y<<8) + (y<<6) + x .

The  basical  algorithms
Lines
For drawing a line we must calculate where an immaginary line intersect an immaginary rect. For each square of the rect correspond a pixel on the screen. So for each square intersected by a immaginary line we have a pixel of the real line to draw. We must calculate what squares is intersected by the line. A simple method is by using the equation x-x1=m(y-y1) , but is a bit slow.
Instead we can use the Bresenham's line-drawing algorithm that use only additions and subtractions. It is based on the relation:

        sizex/sizey=countx/county

        sizex and sizey are the sizes of the rectangle that contain the line
        countx and county are the counters impiegated by the algorithm

so we have:

                    county * sizex       
        calculatex= --------------
                        sizey               

                    countx * sizey       
        calculatey= --------------
                        sizex

But the Bresenham's algorithm transform the equations for drawing the lines without the multiplications and the divisions. See the demo program for the code of the algorithm.

Rectangles
Drawing rectangles is very simple: simply drawing 2 horizontals and 2 verticals lines. But we can make an optimized code that not use the drawline() function and draw a rectangle more faster. We know the structure of the video memory, so is simple to design an algorithm for a rectangle.


draw sizex pixels from (x1, y1)
onerow:
   jump 320-sizex pixels
   draw a pixel
   jump sizex-2 (intsizex) pixels
   draw a pixel
while row drawed < sizey-2
jump 320-sizex pixel
draw sizex pixels

See the demo program for the code of the algorithm.

Circles
Now I've no time for this.

Using the palette
In mode 13h we can use 256 colors for display graphics. Each color is selected from a palette of 262144 colors, so if we must use a special color we can modify the default selection of a color for setting the one that we want. For make this is necessary to tell to the VGA card the number of the color that we want to change and next the RGB value. This value is a triple of byte in the range 0..63, that specify the intensity of Red, Green and Blue. Whit the mixing of these colors we can make the wanted color. The VGA card have 3 register for change the palette: RGB_READ for telling the index of the color to read, RGB_WRITE for telling the index of the color to write and RGB_DATA for read/write the RGB value. RGB_RESET is used for prepare the VGA card (isn't necessary). The following code shows how to setting the RGB value of the color 15 (WHITE):

#define RGB_RESET 0x03C6
#define RGB_READ  0x03C7
#define RGB_WRITE 0x03C8
#define RGB_DATA  0x03C9

void setwhite(void)
{
   outp(RGB_RESET, 0xFF);     // Prepare the VGA card
   outp(RGB_WRITE, WHITE);    // Tell that we want to write the color 15 (WHITE)
   outp(RGB_DATA, 64);        // Red value
   outp(RGB_DATA, 64);        // Green value
   outp(RGB_DATA, 64);        // Blue value
}

For setting all the 256 colors simply tell to the VGA card that we want to write the color 0, and next write the RGB of all the colors:

void setpalette(char *palette)
{
   register int i;

   outp(RGB_RESET, 0xFF);                // Prepare the VGA card
   outp(RGB_WRITE, 0);                  // Tell that we want to write the entire palette
   for(i=0;i<256;i++) {
      outp(RGB_DATA, palette[i*3]);     // Red value
      outp(RGB_DATA, palette[i*3+1]);   // Green value
      outp(RGB_DATA, palette[i*3+2]);   // Blue value
   }
}

For reading the RGB value of a color or of all the colors simply write the index to RGB_READ and read the values from RGB_DATA.See the demo program for the code.

How about snow or noise?
Is possible that a noise will appear on the screen when the palette is changed continuously. This effect is done because we change the palette in the same time that the VGA card update the screen. For prevent this effect is necessary to wait the retrace signal of the card via the bit 3 of the register 0x03DA. There are the code:

void waitretrace(void)
{
   // Wait vertical retrace
   while(inportb(0x03DA)&0x08);
   // Wait refresh
   while(!(inportb(0x03DA)&0x08));
}



Wengier - 新DOS时代

欢迎大家来到我的“新DOS时代”网站,里面有各类DOS软件和资料,地址:
http://wendos.mycool.net/

E-Mail & MSN: wengierwu AT hotmail.com (最近比较忙,有事请联系DOSroot和雨露,谢谢!)

2003-5-14 00:00
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (29206679)  编辑帖子  回复  引用回复
如是大师
元老会员

步行的人


积分 9654
发帖 3351
注册 2003-3-11
来自 湖北
状态 离线
『第 2 楼』:  

翻一下嘛,。。这可难为我们这些E盲了。。。



弄花香满衣,掬水月在手。
                 明月鹭鸟飞, 芦花白马走。
       我自一过后,野渡现横舟。
              青云碧空在,净瓶水不流。
http://dos.e-stone.cn/guestbook/index.asp
   ======中國DOS聯盟=====
我的新网页http://rsds.7i24.com欢迎光顾
2003-5-17 00:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
Wengier
系统支持

“新DOS时代”站长


积分 27734
发帖 10521
注册 2002-10-9
状态 离线
『第 3 楼』:  

请anyhow、Sandy和Roy来翻译一下吧,谢了。



Wengier - 新DOS时代

欢迎大家来到我的“新DOS时代”网站,里面有各类DOS软件和资料,地址:
http://wendos.mycool.net/

E-Mail & MSN: wengierwu AT hotmail.com (最近比较忙,有事请联系DOSroot和雨露,谢谢!)

2003-5-17 00:00
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (29206679)  编辑帖子  回复  引用回复
LanE
银牌会员




积分 1833
发帖 648
注册 2002-11-8
状态 离线
『第 4 楼』:  

#define TEXT_MODE 0x03
#define VGA_MODE  0x13

void setmode(short mode)
{
union REGS regs;

regs.h.ah = 0x00;   // Procedure 0x00: Set Video Mode
regs.h.al = mode;   // The requested video mode
int86(0x10,&reg;s,&reg;s)   // Call the BIOS
}

看这个和TURBO的用法和相似啊

2003-5-23 00:00
查看资料  发送邮件  发短消息 网志  OICQ (9367907)  编辑帖子  回复  引用回复
Wengier
系统支持

“新DOS时代”站长


积分 27734
发帖 10521
注册 2002-10-9
状态 离线
『第 5 楼』:  

DJGPP本来就是一种新的高级的C/C++语言嘛。。



Wengier - 新DOS时代

欢迎大家来到我的“新DOS时代”网站,里面有各类DOS软件和资料,地址:
http://wendos.mycool.net/

E-Mail & MSN: wengierwu AT hotmail.com (最近比较忙,有事请联系DOSroot和雨露,谢谢!)

2003-5-23 00:00
查看资料  发送邮件  访问主页  发短消息 网志  OICQ (29206679)  编辑帖子  回复  引用回复
cir2633
初级用户





积分 52
发帖 23
注册 2009-12-25
状态 离线
『第 6 楼』:  

问下, 保护模式下还用指定指针的模式吗 ? 比如far,near
我觉得没必要i

2010-1-13 10:14
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复

请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: