phoenix图形界面支持1600*800以下的所有分辨率,以及各种色数,包括8位色,16位色,24位色等。
首先要介绍一个概念:Linear Frame Buffer ,这个是什么呢?这个是vesa2.0以后新增的一个概念(现在显卡一般都支持vesa2.0及以上了),用于标志显存的物理地址,而我们只要往这个地址里面写数据就可以在显示器上显示出来,其余的我们都不需要关心,神奇吧!这个数据根据颜色的位数不同可以是8位数,16位数,24位数,32位数等等。。这个数据标志了一个RGB颜色,关于RGB颜色我就不多说了。
我们首先要做的是设置显示模式,也就是分辨率和颜色,在nasm下这只需要3行代码,通过BIOS 0x10中断来实现。注意这个必须在实模式设置,进入保护模式后就无法使用0x10中断了。
代码如下:
  mov ax , 0x4f02
  mov bx , 0x4117       ;设置显示模式1024 * 768 ( 5:6:5 )
  int 0x10
 
代码很简单,下面来解释一下:
首先第一行,mov ax , 0x4f02,这行代码的作用是将我们所要用的功能号存入ax,这个功能号表示我们要设置显示模式。
第二行mov bx , 0x4117   是设置显示模式,其中117表示显示模式为1024 * 768 ( 5:6:5 ),前面的4表示我们需要使用Linear Frame Buffer 。如果需要设置其他的显示模式那么可以参考最下面的显示模式列表。
第三行 int 0x10 调用10号中断,完成!现在我们的操作系统就进入了1024 * 768 ( 5:6:5 )显示模式:),但是我们现在只是进入了这个模式,还不能显示东西,因为我们还没有得到显存的地址Linear Frame Buffer 呢~~下面我们就来看怎样得到这个地址
首先我们通过0x10中断读取一个数据结构,这个数据结构十分庞大,有256个字节,我们需要用这样一个结构体来标志它
typedef struct _mode_info         /* VESA information for a specific mode */
{
   uint16 ModeAttributes  ;
   uint8  WinAAttributes  ;
   uint8  WinBAttributes  ;
   uint16 WinGranularity  ;
   uint16 WinSize            ;
   uint16 WinASegment         ;
   uint16 WinBSegment      ;
   uint32  WinFuncPtr           ;
   uint16 BytesPerScanLine     ;
   uint16 XResolution         ;
   uint16 YResolution          ;
   uint8  XCharSize            ;
   uint8  YCharSize            ;
   uint8  NumberOfPlanes       ;
   uint8  BitsPerPixel         ;
   uint8  NumberOfBanks        ;
   uint8  MemoryModel         ;
   uint8  BankSize    ;      
   uint8  NumberOfImagePages ;
   uint8  Reserved_page    ;   
   uint8  RedMaskSize   ; 
   uint8  RedMaskPos   ;      
   uint8  GreenMaskSize;      
   uint8  GreenMaskPos ;      
   uint8  BlueMaskSize;      
   uint8  BlueMaskPos ;        
   uint8  ReservedMaskSize ;  
   uint8  ReservedMaskPos ;    
   uint8  DirectColorModeInfo; 
   /* VBE 2.0 extensions */
   uint16  *PhysBasePtr ;      
   uint32  Reserved2 ;
   uint16  Reserved1 ; 
   /* VBE 3.0 extensions */
   uint16 LinBytesPerScanLine  ;
   uint8  BnkNumberOfPages ;   
   uint8  LinGreenMaskSize ;  
   uint8  LinGreenFieldPos ;   
   uint8  LinBlueMaskSize ;   
   uint8  LinBlueFieldPos ;    
   uint8  LinRsvdMaskSize ;   
   uint8  LinRsvdFieldPos ;   
   uint32  MaxPixelClock  ;    
   uint8  Reserved[190] ;    
}mode_info;
 
一看很眼晕是不?我当时看到也这样,但是不用担心,我们需要的只有一个,uint16  *PhysBasePtr,这个是什么?这个就是我们要取得的显存地址,呵呵,简单吧。接下来我们来看如何取得这个数据结构,代码也很简单,就几行
 mov bx , 0x9000
  mov es , bx
  mov di , 0x0
  mov ax , 0x4f01
  mov cx , 0x117
  int 0x10
 
首先是ax中的功能号0x4f02变成0x4f01了,这表示我们想取得显示模式信息。当int 0x10调用这个功能号的时候我们要取得的模式信息数据结构会被保存到es:di的地址中,这里我们把es赋值为0x9000,di赋值为0x0,这样这个数据结构就会被存放到物理地址es:di=0x90000中。
然后cx中保存的是所要取得的显示模式的标志号。这里是117,表示要取得1024 * 768 ( 5:6:5 )模式的信息。
 
简单把,现在上面那个big数据结构就被保存在物理地址0x90000中了
现在我们想往显存里写数据只需:
unsigned short  *video_base;      //声明一个指向显存的指针,指针指向的类型根据颜色
                                                   //位 数来决定
mode_info *p=(mode_info*)0x90000;     //然后声明一个指向模式信息数据结构的指针p,并且
                                                                  //让p指向我们模式信息所在的地址0x90000
 video_base=p->PhysBasePtr;                 //把模式信息中Linear Frame Buffer 地址取出来赋给
                                                                  //v ideo_bases
 
现在我们可以对显存为所欲为了,呵呵
比如说画一个点就用下面这个语句:
*video_base=0xaaa   ;
其中0xaaaa是颜色值,好像是橘红色的:)
 
我就写这么多把,其余的就靠个人发挥了,想画什么就直接写显存就可以了。
谢谢大家的支持!
附:
显示模式表:
100h - 640x400 256 108h - 80 60
101h - 640x480 256 109h - 132 25
102h 6Ah 800x600 16 10Ah - 132 43
103h - 800x600 256 10Bh - 132 50
104h - 1024x768 16 10Ch - 132 60
105h - 1024x768 256
106h - 1280x1024 16
107h - 1280x1024 256
10Dh - 320x200 32K (1:5:5:5)
10Eh - 320x200 64K (5:6:5)
10Fh - 320x200 16.8M (8:8:8)
110h - 640x480 32K (1:5:5:5)
111h - 640x480 64K (5:6:5)
112h - 640x480 16.8M (8:8:8)
113h - 800x600 32K (1:5:5:5)
114h - 800x600 64K (5:6:5)
115h - 800x600 16.8M (8:8:8)
116h - 1024x768 32K (1:5:5:5)
117h - 1024x768 64K (5:6:5)
118h - 1024x768 16.8M (8:8:8)
119h - 1280x1024 32K (1:5:5:5)
11Ah - 1280x1024 64K (5:6:5)
11Bh - 1280x1024 16.8M (8:8:8)
81FFh Special Mode (see below for details)